SFPSDWriter 是一个 Objective-C 库,用于写入 PSD 文件。在我们 Shiny Frog,我们需要一种方法来写入具有 多图层、组 的 PSD 文件,这个库是我们经过几天头痛后得到的结果。
它具有以下特点:
SFPSDWriter 不具备以下功能:
// The images we want to insert in the PSD
NSImage *firstImage = [NSImage imageNamed:@"firstImage"];
NSImage *secondImage = [NSImage imageNamed:@"secondImage"];
// SFPSDWriter instance
SFPSDWriter *psdWriter = [[SFPSDWriter alloc] initWithDocumentSize:NSSizeToCGSize(firstImage.size) andResolution:300.0 andResolutionUnit:SFPSDResolutionUnitPPI];
// We want all our layers to be included in a group...
SFPSDGroupOpeningLayer *firstGroup = [psdWriter openGroupLayerWithName:@"We ♥ groups!"];
// ... and the group should be open at file opening
[firstGroup setIsOpened:YES];
// Adding the first image layer
[psdWriter addLayerWithCGImage:[[[firstImage representations] objectAtIndex:0] CGImage]
andName:@"First Layer"
andOpacity:1
andOffset:NSMakePoint(0, 0)];
// I mean, we really love groups
// This time we don't need to change group's attributes so we don't store the reference
[psdWriter openGroupLayerWithName:@"You'll have to open me!"];
// The second image will be in the second group, offsetted by (116px, 66px), semi-transparent...
SFPSDLayer *secondLayer = [psdWriter addLayerWithCGImage:[[[secondImage representations] objectAtIndex:0] CGImage]
andName:@"Second Layer"
andOpacity:0.5
andOffset:NSMakePoint(116, 66)];
// ... and with "Darken" blend mode
[secondLayer setBlendMode:SFPSDLayerBlendModeDarken];
// We'll prepare the Drop Shadow Effect Layer information
SFPSDDropShadowEffectLayerInformation *dropShadowInformation = [[SFPSDDropShadowEffectLayerInformation alloc] init];
dropShadowInformation.enabled = YES;
dropShadowInformation.size = 100;
dropShadowInformation.angle = 90;
dropShadowInformation.distance = 30;
dropShadowInformation.color = [[NSColor redColor] CGColor];
dropShadowInformation.blendMode = SFPSDLayerBlendModeNormal;
dropShadowInformation.useGlobalLight = NO;
dropShadowInformation.opacity = 100;
// We'll set the Drop Sahdow on the second layer (we can add it to the SFPSDGroupOpeningLayer too)
[secondLayer setDropShadowEffectLayerInformation:dropShadowInformation];
// Other available Effect Layers are:
// - Inner Shadow (SFPSDInnerShadowEffectLayerInformation)
// - Outer Glow (SFPSDOuterGlowEffectLayerInformation)
// - Inner Glow (SFPSDInnerGlowEffectLayerInformation)
// - Bevel (SFPSDBevelEffectLayerInformation)
// - Solid Fill (SFPSDSolidFillEffectLayerInformation)
// We have to close every group we've opened
[psdWriter closeCurrentGroupLayer]; // second group
[psdWriter closeCurrentGroupLayer]; // first group
// We can change the embedded color profile of the document (for example with an "sRGB IEC61966-2.1")
[psdWriter setColorProfile:SFPSDSRGBColorProfile];
// We'll write our test file to the Desktop
NSString *basePath = [NSHomeDirectory() stringByAppendingPathComponent:@"Desktop"];
NSString *fullFilePath = [basePath stringByAppendingPathComponent:@"SFPSDWriter Test File.psd"];
// Retrieving the PSD data
NSError *error = nil;
NSData * psd = [psdWriter createPSDDataWithError:&error];
// Checking for errors
if (nil != error) {
NSLog(@"There was an error writing the PSD: %@", [error description]);
return;
}
// Writing the data on disk
[psd writeToFile:fullFilePath atomically:NO];
// Opening the newly created file! :)
[[NSWorkspace sharedWorkspace] openFile:fullFilePath];
// The images we want to insert in the PSD
UIImage *firstImage = [UIImage imageNamed:@"firstImage"];
UIImage *secondImage = [UIImage imageNamed:@"secondImage"];
// SFPSDWriter instance
SFPSDWriter *psdWriter = [[SFPSDWriter alloc] initWithDocumentSize:firstImage.size andResolution:300.0 andResolutionUnit:SFPSDResolutionUnitPPI];
// We want all our layers to be included in a group...
SFPSDGroupOpeningLayer *firstGroup = [psdWriter openGroupLayerWithName:@"We ♥ groups!"];
// ... and the group should be open at file opening
[firstGroup setIsOpened:YES];
// Adding the first image layer
[psdWriter addLayerWithCGImage:[firstImage CGImage]
andName:@"First Layer"
andOpacity:1
andOffset:CGPointMake(0, 0)];
// I mean, we really love groups
// This time we don't need to change group's attributes so we don't store the reference
[psdWriter openGroupLayerWithName:@"You'll have to open me!"];
// The second image will be in the second group, offsetted by (116px, 66px), semi-transparent...
SFPSDLayer *secondLayer = [psdWriter addLayerWithCGImage:[secondImage CGImage]
andName:@"Second Layer"
andOpacity:0.5
andOffset:CGPointMake(116, 66)];
// ... and with "Darken" blend mode
[secondLayer setBlendMode:SFPSDLayerBlendModeDarken];
// We'll prepare the Drop Shadow Effect Layer information
SFPSDDropShadowEffectLayerInformation *dropShadowInformation = [[SFPSDDropShadowEffectLayerInformation alloc] init];
dropShadowInformation.enabled = YES;
dropShadowInformation.size = 100;
dropShadowInformation.angle = 90;
dropShadowInformation.distance = 30;
dropShadowInformation.color = [[UIColor redColor] CGColor];
dropShadowInformation.blendMode = SFPSDLayerBlendModeNormal;
dropShadowInformation.useGlobalLight = NO;
dropShadowInformation.opacity = 100;
// We'll set the Drop Sahdow on the second layer (we can add it to the SFPSDGroupOpeningLayer too)
[secondLayer setDropShadowEffectLayerInformation:dropShadowInformation];
// Other available Effect Layers are:
// - Inner Shadow (SFPSDInnerShadowEffectLayerInformation)
// - Outer Glow (SFPSDOuterGlowEffectLayerInformation)
// - Inner Glow (SFPSDInnerGlowEffectLayerInformation)
// - Bevel (SFPSDBevelEffectLayerInformation)
// - Solid Fill (SFPSDSolidFillEffectLayerInformation)
// We have to close every group we've opened
[psdWriter closeCurrentGroupLayer]; // second group
[psdWriter closeCurrentGroupLayer]; // first group
// We can change the embedded color profile of the document (for example with an "sRGB IEC61966-2.1")
[psdWriter setColorProfile:SFPSDSRGBColorProfile];
// We'll write our test file into the documents folder of the application
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fullFilePath = [documentsDirectory stringByAppendingPathComponent:@"SFPSDWriter Test File.psd"];
// Retrieving the PSD data
NSError *error = nil;
NSData * psd = [psdWriter createPSDDataWithError:&error];
// Checking for errors
if (nil != error) {
NSLog(@"There was an error writing the PSD: %@", [error description]);
return;
}
// Writing the data on disk
// When using the simulator we can find the file in
// /Users/<Username>/Library/Application\ Support/iPhone\ Simulator/<Simulator Version>/Applications/<Application>/Documents
[psd writeToFile:fullFilePath atomically:NO];
示例项目是 使用方法 部分中的代码的复制和粘贴
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification // Mac OS X
和
- (void)applicationDidBecomeActive:(UIApplication *)application // iOS
还有一个用于压力测试库的调试项目。您可以在 Example Projects/SFPSDWriter Stress Tester 中找到它。
库已满足我们的需求,因此没有计划对其做进一步的改进。显然,如果我们找到一些问题,我们会解决问题或加快速度。
目前没有计划让这个库能够读取 PSD 文件。或者更确切地说:有一个具体的计划不让这个库读取 PSD 文件。
在此,我想邀请您阅读这个 著名的评论,让您了解与 PSD 文件工作意味着什么。必须承认,我觉得这个评论很有激励性,但我是个变态。如果可以的话,不要玩 PSD 文件。 :)
我们很乐意评估接受拉取请求的可能性,如果您有任何建议欢迎告诉我们。
此库受到了来自Ben Gotow的PSDWriter的启发。它在结构上进行了一些重组,将信息的编写和通道委托给层,并在这里和那里增加了一些内容。
如果没有Gus Mueller(@ccgus)提供的一些专业技巧,此库将无法实现!这些技巧讲述了PSD组的神秘行为。