diff --git a/Dependencies/PSDWriter/Documentation/Categories/NSData+PSDAdditions.html b/Dependencies/PSDWriter/Documentation/Categories/NSData+PSDAdditions.html new file mode 100644 index 0000000..9032fc5 --- /dev/null +++ b/Dependencies/PSDWriter/Documentation/Categories/NSData+PSDAdditions.html @@ -0,0 +1,367 @@ + + + + + NSData(PSDAdditions) Category Reference + + + + + + + +
+
+

PSDWriter Documentation

+ Foundry376 +
+ + + +
+ +
+
+ + + +
+ +
+ + + + +
Declared inNSDataPSDAdditions.h
NSDataPSDAdditions.m
+ + + + + + +
+ +

Tasks

+ + + + + +
    +
  • + + – packedBitsDescription +

    Takes packedBits data and prints out a description of the packed contents by +running the decode operation and explaining via NSLog how the data is being +decoded. Useful for checking that packedBits data is correct.

    +
    + + +
  • + + – packedBitsForRange:skip: +

    A special version of packedBits which will take the data and pack every nth +value.

    +
    + + +
  • +
+ +
+ + + + + + + + + +
+ +

Instance Methods

+ +
+ +

packedBitsDescription

+ + + +
+

Takes packedBits data and prints out a description of the packed contents by +running the decode operation and explaining via NSLog how the data is being +decoded. Useful for checking that packedBits data is correct.

+
+ + +
- (NSString *)packedBitsDescription
+ + + + + + + + +
+

Discussion

+

Takes packedBits data and prints out a description of the packed contents by +running the decode operation and explaining via NSLog how the data is being +decoded. Useful for checking that packedBits data is correct.

+
+ + + + + + + +
+

Declared In

+ NSDataPSDAdditions.h
+
+ + +
+ +
+ +

packedBitsForRange:skip:

+ + + +
+

A special version of packedBits which will take the data and pack every nth +value.

+
+ + +
- (NSData *)packedBitsForRange:(NSRange)range skip:(int)skip
+ + +
+

Parameters

+ +
+
skip:
+

The number of bytes to advance as the data is encoded. Skip = 1 will +encode every byte, skip = 4 will encode every fourth byte, and so on.

+
+ +
+
range:
+

The range within the data object that should be encoded. Useful +for specifying a non-zero starting offset to get a certain channel encoded.

+
+ +
+ + + + + + + +
+

Discussion

+

A special version of packedBits which will take the data and pack every nth +value.

+ +

This is important for PSDWriter because it’s necessary to encode R, then G, +then B, then A data – so we essentially start at offset 0, skip 4, then do offset 1, +skip 4, etc… to compress the data with very minimal memory footprint.

+ +

For normal packbits just to skip = 1

+
+ + + + + + + +
+

Declared In

+ NSDataPSDAdditions.h
+
+ + +
+ +
+ + +
+ + +
+
+ + + \ No newline at end of file diff --git a/Dependencies/PSDWriter/Documentation/Categories/NSMutableData+PSDAdditions.html b/Dependencies/PSDWriter/Documentation/Categories/NSMutableData+PSDAdditions.html new file mode 100644 index 0000000..8d008a5 --- /dev/null +++ b/Dependencies/PSDWriter/Documentation/Categories/NSMutableData+PSDAdditions.html @@ -0,0 +1,305 @@ + + + + + NSMutableData(PSDAdditions) Category Reference + + + + + + + +
+
+

PSDWriter Documentation

+ Foundry376 +
+ + + +
+ +
+
+ + + +
+ +
+ + + + +
Declared inNSDataPSDAdditions.h
NSDataPSDAdditions.m
+ + + + + + +
+ +

Tasks

+ + + + + + + +
+ + + + + + + + + +
+ +

Instance Methods

+ +
+ +

appendValue:withLength:

+ + + +
+

Allows you to append a numeric value to an NSMutableData object and pad it to any length.

+
+ + +
- (void)appendValue:(long)value withLength:(int)length
+ + +
+

Parameters

+ +
+
length:
+

The number of bytes that should be used to store the value. The value will be padded +to length bytes regardless of the number of bytes required to store it.

+
+ +
+
value:
+

The value to append

+
+ +
+ + + + + + + +
+

Discussion

+

Allows you to append a numeric value to an NSMutableData object and pad it to any length.

+ +

For example, we could say [data appendValue: 2 withLength: 5], and 00002 would be written +into the data object. Very useful for writing to file formats that have header structures +that require a certain number of bytes be used for a certain value. i.e. PSD and TIFF

+
+ + + + + + + +
+

Declared In

+ NSDataPSDAdditions.h
+
+ + +
+ +
+ + +
+ + +
+
+ + + \ No newline at end of file diff --git a/Dependencies/PSDWriter/Documentation/Classes/PSDLayer.html b/Dependencies/PSDWriter/Documentation/Classes/PSDLayer.html new file mode 100644 index 0000000..bbdbbab --- /dev/null +++ b/Dependencies/PSDWriter/Documentation/Classes/PSDLayer.html @@ -0,0 +1,447 @@ + + + + + PSDLayer Class Reference + + + + + + + +
+
+

PSDWriter Documentation

+ Foundry376 +
+ + + +
+ +
+
+ + + +
+ +
+ + + + + + + +
Inherits fromNSObject
Declared inPSDLayer.h
PSDLayer.m
+ + + + + + +
+ +

Tasks

+ + + + + +
    +
  • + +   name +

    The name of the layer. I believe this must be 16 characters or less.

    +
    + property + +
  • + +   imageData +

    The image data in RGBA or RGB format, depending on whether the PSDWriter.layerChannelCount +is set to 4 or 3, respectively.

    +
    + property + +
  • + +   opacity +

    The opacity of the layer between 0 and 1.

    +
    + property + +
  • + +   rect +

    The rectangle the layer should be placed within in the PSD. Note that scaling is not currently +supported, so you should really only adjust the origin of this rect to move the imageData around +within the PSD.

    +
    + property + +
  • +
+ +
+ + + + + +
+ +

Properties

+ +
+ +

imageData

+ + + +
+

The image data in RGBA or RGB format, depending on whether the PSDWriter.layerChannelCount +is set to 4 or 3, respectively.

+
+ + +
@property (nonatomic, retain) NSData *imageData
+ + + + + + + + +
+

Discussion

+

The image data in RGBA or RGB format, depending on whether the PSDWriter.layerChannelCount +is set to 4 or 3, respectively.

+
+ + + + + + + +
+

Declared In

+ PSDLayer.h
+
+ + +
+ +
+ +

name

+ + + +
+

The name of the layer. I believe this must be 16 characters or less.

+
+ + +
@property (nonatomic, retain) NSString *name
+ + + + + + + + +
+

Discussion

+

The name of the layer. I believe this must be 16 characters or less.

+
+ + + + + + + +
+

Declared In

+ PSDLayer.h
+
+ + +
+ +
+ +

opacity

+ + + +
+

The opacity of the layer between 0 and 1.

+
+ + +
@property (nonatomic, assign) float opacity
+ + + + + + + + +
+

Discussion

+

The opacity of the layer between 0 and 1.

+
+ + + + + + + +
+

Declared In

+ PSDLayer.h
+
+ + +
+ +
+ +

rect

+ + + +
+

The rectangle the layer should be placed within in the PSD. Note that scaling is not currently +supported, so you should really only adjust the origin of this rect to move the imageData around +within the PSD.

+
+ + +
@property (nonatomic, assign) CGRect rect
+ + + + + + + + +
+

Discussion

+

The rectangle the layer should be placed within in the PSD. Note that scaling is not currently +supported, so you should really only adjust the origin of this rect to move the imageData around +within the PSD.

+
+ + + + + + + +
+

Declared In

+ PSDLayer.h
+
+ + +
+ +
+ + + + + + +
+ + +
+
+ + + \ No newline at end of file diff --git a/Dependencies/PSDWriter/Documentation/Classes/PSDWriter.html b/Dependencies/PSDWriter/Documentation/Classes/PSDWriter.html new file mode 100644 index 0000000..1d665cd --- /dev/null +++ b/Dependencies/PSDWriter/Documentation/Classes/PSDWriter.html @@ -0,0 +1,724 @@ + + + + + PSDWriter Class Reference + + + + + + + +
+
+

PSDWriter Documentation

+ Foundry376 +
+ + + +
+ +
+
+ + + +
+ +
+ + + + + + + +
Inherits fromNSObject
Declared inPSDWriter.h
PSDWriter.m
+ + + + + + +
+ +

Tasks

+ + + + + +
    +
  • + +   layers +

    The PSDLayer objects with layer data, names, etc… Note that when you call +createPSDData, this array is slowly emptied – the PSDWriter removes the individual layers +from memory as it builds the PSD file.

    +
    + property + +
  • + +   documentSize +

    The size of the PSD you’re exporting.

    +
    + property + +
  • + +   layerChannelCount +

    The number of channels in each layer. Defaults to 4, unless layers +are not transparent. At the moment, this setting applies to all layers.

    +
    + property + +
  • + +   flattenedData +

    Optional. The RGBA data for a flattened “preview” of the PSD.

    +
    + property + +
  • + +   shouldFlipLayerData +

    Allows you to automatically vertically flip the image data when it’s being +written to PSD. This is important if the source images are coming from OpenGL or +another drawing system with an inverted coordinate system.

    +
    + property + +
  • + +   shouldUnpremultiplyLayerData +

    Allows you to automatically unpremultiply the image data. Premultiplication is +a process by which the R,G, and B values are multiplied by the alpha. Setting this +to YES will cause RGB to be divided by A. You’ll know you need to do this if the +image comes out darker than you expect.

    +
    + property + +
  • + + – initWithDocumentSize: +

    Initializes a new PSDWriter for creating a PSD document with the specified size.

    +
    + + +
  • + + – addLayerWithCGImage:andName:andOpacity:andOffset: +

    Adds a new layer to the PSD image with the provided properties.

    +
    + + +
  • +
+ +
+ + + + + +
+ +

Properties

+ +
+ +

documentSize

+ + + +
+

The size of the PSD you’re exporting.

+
+ + +
@property (nonatomic, assign) CGSize documentSize
+ + + + + + + + +
+

Discussion

+

The size of the PSD you’re exporting.

+
+ + + + + + + +
+

Declared In

+ PSDWriter.h
+
+ + +
+ +
+ +

flattenedData

+ + + +
+

Optional. The RGBA data for a flattened “preview” of the PSD.

+
+ + +
@property (nonatomic, retain) NSData *flattenedData
+ + + + + + + + +
+

Discussion

+

Optional. The RGBA data for a flattened “preview” of the PSD.

+
+ + + + + + + +
+

Declared In

+ PSDWriter.h
+
+ + +
+ +
+ +

layerChannelCount

+ + + +
+

The number of channels in each layer. Defaults to 4, unless layers +are not transparent. At the moment, this setting applies to all layers.

+
+ + +
@property (nonatomic, assign) int layerChannelCount
+ + + + + + + + +
+

Discussion

+

The number of channels in each layer. Defaults to 4, unless layers +are not transparent. At the moment, this setting applies to all layers.

+
+ + + + + + + +
+

Declared In

+ PSDWriter.h
+
+ + +
+ +
+ +

layers

+ + + +
+

The PSDLayer objects with layer data, names, etc… Note that when you call +createPSDData, this array is slowly emptied – the PSDWriter removes the individual layers +from memory as it builds the PSD file.

+
+ + +
@property (nonatomic, retain) NSMutableArray *layers
+ + + + + + + + +
+

Discussion

+

The PSDLayer objects with layer data, names, etc… Note that when you call +createPSDData, this array is slowly emptied – the PSDWriter removes the individual layers +from memory as it builds the PSD file.

+
+ + + + + + + +
+

Declared In

+ PSDWriter.h
+
+ + +
+ +
+ +

shouldFlipLayerData

+ + + +
+

Allows you to automatically vertically flip the image data when it’s being +written to PSD. This is important if the source images are coming from OpenGL or +another drawing system with an inverted coordinate system.

+
+ + +
@property (nonatomic, assign) BOOL shouldFlipLayerData
+ + + + + + + + +
+

Discussion

+

Allows you to automatically vertically flip the image data when it’s being +written to PSD. This is important if the source images are coming from OpenGL or +another drawing system with an inverted coordinate system.

+
+ + + + + + + +
+

Declared In

+ PSDWriter.h
+
+ + +
+ +
+ +

shouldUnpremultiplyLayerData

+ + + +
+

Allows you to automatically unpremultiply the image data. Premultiplication is +a process by which the R,G, and B values are multiplied by the alpha. Setting this +to YES will cause RGB to be divided by A. You’ll know you need to do this if the +image comes out darker than you expect.

+
+ + +
@property (nonatomic, assign) BOOL shouldUnpremultiplyLayerData
+ + + + + + + + +
+

Discussion

+

Allows you to automatically unpremultiply the image data. Premultiplication is +a process by which the R,G, and B values are multiplied by the alpha. Setting this +to YES will cause RGB to be divided by A. You’ll know you need to do this if the +image comes out darker than you expect.

+
+ + + + + + + +
+

Declared In

+ PSDWriter.h
+
+ + +
+ +
+ + + + + +
+ +

Instance Methods

+ +
+ +

addLayerWithCGImage:andName:andOpacity:andOffset:

+ + + +
+

Adds a new layer to the PSD image with the provided properties.

+
+ + +
- (void)addLayerWithCGImage:(CGImageRef)image andName:(NSString *)name andOpacity:(float)opacity andOffset:(CGPoint)offset
+ + +
+

Parameters

+ +
+
image
+

The image to be added. Does not need to be the same size as the document, but it cannot be larger.

+
+ +
+
name
+

The name you’d like to give the layer.

+
+ +
+
opacity
+

The opacity of the layer, from [0-1]

+
+ +
+
offset
+

The offset of the layer within the document. Use this to position layers within the PSD.

+
+ +
+ + + + + + + +
+

Discussion

+

Adds a new layer to the PSD image with the provided properties.

+ +

If you are using NSImages and not CGImages, use the following code to convert to CGImageRefs:

+ +
NSImage* yourImage;
+CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)[yourImage TIFFRepresentation], NULL);
+CGImageRef imageRef = CGImageSourceCreateImageAtIndex(source, 0, NULL);
+
+ +

If you prefer, you can setup PSDLayers by yourself +and put them in the PSDWriter.layers array, but this method automatically creates the flattenedData, +an image that is a flattened preview of the layered PSD. If you populate the layer objects yourself, +you need to provide the flattened image data yourself.

+ +

Note: Having layers partially off the edge of the canvas is not currently supported.

+
+ + + + + + + +
+

Declared In

+ PSDWriter.h
+
+ + +
+ +
+ +

initWithDocumentSize:

+ + + +
+

Initializes a new PSDWriter for creating a PSD document with the specified size.

+
+ + +
- (id)initWithDocumentSize:(CGSize)s
+ + +
+

Parameters

+ +
+
s
+

The document size

+
+ +
+ + + + + + + +
+

Discussion

+

Initializes a new PSDWriter for creating a PSD document with the specified size.

+
+ + + + + + + +
+

Declared In

+ PSDWriter.h
+
+ + +
+ +
+ + +
+ + +
+
+ + + \ No newline at end of file diff --git a/Dependencies/PSDWriter/Documentation/css/styles.css b/Dependencies/PSDWriter/Documentation/css/styles.css new file mode 100755 index 0000000..92db21d --- /dev/null +++ b/Dependencies/PSDWriter/Documentation/css/styles.css @@ -0,0 +1,562 @@ +body { + font-family: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif; + font-size: 13px; +} + +code { + font-family: Courier, Consolas, monospace; + font-size: 13px; + color: #666; +} + +pre { + font-family: Courier, Consolas, monospace; + font-size: 13px; + line-height: 18px; + tab-interval: 0.5em; + border: 1px solid #C7CFD5; + background-color: #F1F5F9; + color: #666; + padding: 0.3em 1em; +} + +ul { + list-style-type: square; +} + +li { + margin-bottom: 10px; +} + +a { + text-decoration: none; + color: #36C; +} + +a:hover { + text-decoration: underline; + color: #36C; +} + +h2 { + border-bottom: 1px solid #8391A8; + color: #3C4C6C; + font-size: 187%; + font-weight: normal; + margin-top: 1.75em; + padding-bottom: 2px; +} + +table { + margin-bottom: 4em; + border-collapse:collapse; + vertical-align: middle; +} + +td { + border: 1px solid #9BB3CD; + padding: .667em; + font-size: 100%; +} + +th { + border: 1px solid #9BB3CD; + padding: .3em .667em .3em .667em; + background: #93A5BB; + font-size: 103%; + font-weight: bold; + color: white; + text-align: left; +} + +/* @group Common page elements */ + +#top_header { + height: 91px; + left: 0; + min-width: 598px; + position: absolute; + right: 0; + top: 0; + z-index: 900; +} + +#footer { + clear: both; + padding-top: 20px; + text-align: center; +} + +#contents, #overview_contents { + -webkit-overflow-scrolling: touch; + border-top: 1px solid #2B334F; + position: absolute; + top: 91px; + left: 0; + right: 0; + bottom: 0; + overflow-x: hidden; + overflow-y: auto; + padding-left: 2em; + padding-right: 2em; + padding-top: 1em; + min-width: 550px; +} + +#contents.isShowingTOC { + left: 230px; + min-width: 320px; +} + +.copyright { + font-size: 12px; +} + +.generator { + font-size: 11px; +} + +.main-navigation ul li { + display: inline; + margin-left: 15px; + list-style: none; +} + +.navigation-top { + clear: both; + float: right; +} + +.navigation-bottom { + clear: both; + float: right; + margin-top: 20px; + margin-bottom: -10px; +} + +.open > .disclosure { + background-image: url("../img/disclosure_open.png"); +} + +.disclosure { + background: url("../img/disclosure.png") no-repeat scroll 0 0; +} + +.disclosure, .nodisclosure { + display: inline-block; + height: 8px; + margin-right: 5px; + position: relative; + width: 9px; +} + +/* @end */ + +/* @group Header */ + +#top_header #library { + background: url("../img/library_background.png") repeat-x 0 0 #485E78; + background-color: #ccc; + height: 35px; + font-size: 115%; +} + +#top_header #library #libraryTitle { + color: #FFFFFF; + margin-left: 15px; + text-shadow: 0 -1px 0 #485E78; + top: 8px; + position: absolute; +} + +#top_header #library #developerHome { + color: #92979E; + right: 15px; + top: 8px; + position: absolute; +} + +#top_header #library a:hover { + text-decoration: none; +} + +#top_header #title { + background: url("../img/title_background.png") repeat-x 0 0 #8A98A9; + border-bottom: 1px solid #B6B6B6; + height: 25px; + overflow: hidden; +} + +#top_header h1 { + font-size: 115%; + font-weight: normal; + margin: 0; + padding: 3px 0 2px; + text-align: center; + text-shadow: 0 1px 0 #D5D5D5; + white-space: nowrap; +} + +#headerButtons { + background-color: #D8D8D8; + background-image: url("../img/button_bar_background.png"); + border-bottom: 1px solid #EDEDED; + border-top: 1px solid #2B334F; + font-size: 8pt; + height: 28px; + left: 0; + list-style: none outside none; + margin: 0; + overflow: hidden; + padding: 0; + position: absolute; + right: 0; + top: 61px; +} + +#headerButtons li { + background-repeat: no-repeat; + display: inline; + margin-top: 0; + margin-bottom: 0; + padding: 0; +} + +#toc_button button { + border-color: #ACACAC; + border-style: none solid none none; + border-width: 0 1px 0 0; + height: 28px; + margin: 0; + padding-left: 30px; + text-align: left; + width: 230px; +} + +li#jumpto_button { + left: 230px; + margin-left: 0; + position: absolute; +} + +li#jumpto_button select { + height: 22px; + margin: 5px 2px 0 10px; + max-width: 300px; +} + +/* @end */ + +/* @group Table of contents */ + +#tocContainer.isShowingTOC { + border-right: 1px solid #ACACAC; + display: block; + overflow-x: hidden; + overflow-y: auto; + padding: 0; +} + +#tocContainer { + background-color: #E4EBF7; + border-top: 1px solid #2B334F; + bottom: 0; + display: none; + left: 0; + overflow: hidden; + position: absolute; + top: 91px; + width: 229px; +} + +#tocContainer > ul#toc { + font-size: 11px; + margin: 0; + padding: 12px 0 18px; + width: 209px; + -moz-user-select: none; + -webkit-user-select: none; + user-select: none; +} + +#tocContainer > ul#toc > li { + margin: 0; + padding: 0 0 7px 30px; + text-indent: -15px; +} + +#tocContainer > ul#toc > li > .sectionName a { + color: #000000; + font-weight: bold; +} + +#tocContainer > ul#toc > li > .sectionName a:hover { + text-decoration: none; +} + +#tocContainer > ul#toc li.children > ul { + display: none; + height: 0; +} + +#tocContainer > ul#toc > li > ul { + margin: 0; + padding: 0; +} + +#tocContainer > ul#toc > li > ul, ul#toc > li > ul > li { + margin-left: 0; + margin-bottom: 0; + padding-left: 15px; +} + +#tocContainer > ul#toc > li ul { + list-style: none; + margin-right: 0; + padding-right: 0; +} + +#tocContainer > ul#toc li.children.open > ul { + display: block; + height: auto; + margin-left: -15px; + padding-left: 0; +} + +#tocContainer > ul#toc > li > ul, ul#toc > li > ul > li { + margin-left: 0; + padding-left: 15px; +} + +#tocContainer li ul li { + margin-top: 0.583em; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +#tocContainer li ul li span.sectionName { + white-space: normal; +} + +#tocContainer > ul#toc > li > ul > li > .sectionName a { + font-weight: bold; +} + +#tocContainer > ul#toc > li > ul a { + color: #4F4F4F; +} + +/* @end */ + +/* @group Index formatting */ + +.index-title { + font-size: 13px; + font-weight: normal; +} + +.index-column { + float: left; + width: 30%; + min-width: 200px; + font-size: 11px; +} + +.index-column ul { + margin: 8px 0 0 0; + padding: 0; + list-style: none; +} + +.index-column ul li { + margin: 0 0 3px 0; + padding: 0; +} + +.hierarchy-column { + min-width: 400px; +} + +.hierarchy-column ul { + margin: 3px 0 0 15px; +} + +.hierarchy-column ul li { + list-style-type: square; +} + +/* @end */ + +/* @group Common formatting elements */ + +.title { + font-weight: normal; + font-size: 215%; + margin-top:0; +} + +.subtitle { + font-weight: normal; + font-size: 180%; + color: #3C4C6C; + border-bottom: 1px solid #5088C5; +} + +.subsubtitle { + font-weight: normal; + font-size: 145%; + height: 0.7em; +} + +.warning { + border: 1px solid #5088C5; + background-color: #F0F3F7; + margin-bottom: 0.5em; + padding: 0.3em 0.8em; +} + +.bug { + border: 1px solid #000; + background-color: #ffffcc; + margin-bottom: 0.5em; + padding: 0.3em 0.8em; +} + +.deprecated { + color: #F60425; +} + +/* @end */ + +/* @group Common layout */ + +.section { + margin-top: 3em; +} + +/* @end */ + +/* @group Object specification section */ + +.section-specification { + margin-left: 2.5em; + margin-right: 2.5em; + font-size: 12px; +} + +.section-specification table { + margin-bottom: 0em; + border-top: 1px solid #d6e0e5; +} + +.section-specification td { + vertical-align: top; + border-bottom: 1px solid #d6e0e5; + border-left-width: 0px; + border-right-width: 0px; + border-top-width: 0px; + padding: .6em; +} + +.section-specification .specification-title { + font-weight: bold; +} + +/* @end */ + +/* @group Tasks section */ + +.task-list { + list-style-type: none; + padding-left: 0px; +} + +.task-list li { + margin-bottom: 3px; +} + +.task-item-suffix { + color: #996; + font-size: 12px; + font-style: italic; + margin-left: 0.5em; +} + +span.tooltip span.tooltip { + font-size: 1.0em; + display: none; + padding: 0.3em; + border: 1px solid #aaa; + background-color: #fdfec8; + color: #000; + text-align: left; +} + +span.tooltip:hover span.tooltip { + display: block; + position: absolute; + margin-left: 2em; +} + +/* @end */ + +/* @group Method section */ + +.section-method { + margin-top: 2.3em; +} + +.method-title { + margin-bottom: 1.5em; +} + +.method-subtitle { + margin-top: 0.7em; + margin-bottom: 0.2em; +} + +.method-subsection p { + margin-top: 0.4em; + margin-bottom: 0.8em; +} + +.method-declaration { + margin-top:1.182em; + margin-bottom:.909em; +} + +.method-declaration code { + font:14px Courier, Consolas, monospace; + color:#000; +} + +.declaration { + color: #000; +} + +.argument-def { + margin-top: 0.3em; + margin-bottom: 0.3em; +} + +.argument-def dd { + margin-left: 1.25em; +} + +.see-also-section ul { + list-style-type: none; + padding-left: 0px; + margin-top: 0; +} + +.see-also-section li { + margin-bottom: 3px; +} + +.declared-in-ref { + color: #666; +} + +/* @end */ + diff --git a/Dependencies/PSDWriter/Documentation/css/stylesPrint.css b/Dependencies/PSDWriter/Documentation/css/stylesPrint.css new file mode 100755 index 0000000..dc54cd2 --- /dev/null +++ b/Dependencies/PSDWriter/Documentation/css/stylesPrint.css @@ -0,0 +1,22 @@ + +header { + display: none; +} + +div.main-navigation, div.navigation-top { + display: none; +} + +div#overview_contents, div#contents.isShowingTOC, div#contents { + overflow: visible; + position: relative; + top: 0px; + border: none; + left: 0; +} +#tocContainer.isShowingTOC { + display: none; +} +nav { + display: none; +} \ No newline at end of file diff --git a/Dependencies/PSDWriter/Documentation/hierarchy.html b/Dependencies/PSDWriter/Documentation/hierarchy.html new file mode 100644 index 0000000..7a77fb6 --- /dev/null +++ b/Dependencies/PSDWriter/Documentation/hierarchy.html @@ -0,0 +1,86 @@ + + + + + PSDWriter Documentation Hierarchy + + + + + +
+
+

PSDWriter Documentation

+ Foundry376 +
+ + + +
+
+
+ + +
+ +
+

Class Hierarchy

+ + + +
+ + + +
+ + +

Category References

+ + +
+ +
+ + +
+
+ + \ No newline at end of file diff --git a/Dependencies/PSDWriter/Documentation/img/button_bar_background.png b/Dependencies/PSDWriter/Documentation/img/button_bar_background.png new file mode 100755 index 0000000..d2cd0d8 Binary files /dev/null and b/Dependencies/PSDWriter/Documentation/img/button_bar_background.png differ diff --git a/Dependencies/PSDWriter/Documentation/img/disclosure.png b/Dependencies/PSDWriter/Documentation/img/disclosure.png new file mode 100755 index 0000000..147198f Binary files /dev/null and b/Dependencies/PSDWriter/Documentation/img/disclosure.png differ diff --git a/Dependencies/PSDWriter/Documentation/img/disclosure_open.png b/Dependencies/PSDWriter/Documentation/img/disclosure_open.png new file mode 100755 index 0000000..ea3842b Binary files /dev/null and b/Dependencies/PSDWriter/Documentation/img/disclosure_open.png differ diff --git a/Dependencies/PSDWriter/Documentation/img/library_background.png b/Dependencies/PSDWriter/Documentation/img/library_background.png new file mode 100755 index 0000000..8fa6d45 Binary files /dev/null and b/Dependencies/PSDWriter/Documentation/img/library_background.png differ diff --git a/Dependencies/PSDWriter/Documentation/img/title_background.png b/Dependencies/PSDWriter/Documentation/img/title_background.png new file mode 100755 index 0000000..9001dac Binary files /dev/null and b/Dependencies/PSDWriter/Documentation/img/title_background.png differ diff --git a/Dependencies/PSDWriter/Documentation/index.html b/Dependencies/PSDWriter/Documentation/index.html new file mode 100644 index 0000000..0fd9db2 --- /dev/null +++ b/Dependencies/PSDWriter/Documentation/index.html @@ -0,0 +1,80 @@ + + + + + PSDWriter Documentation Reference + + + + + +
+
+

PSDWriter Documentation

+ Foundry376 +
+ + + +
+
+
+ + +
+ + + +
+

Class References

+ +
+ + + +
+ + +

Category References

+ + +
+ +
+ + +
+
+ + \ No newline at end of file diff --git a/Dependencies/PSDWriter/PSDWriter-Mac.xcodeproj/project.pbxproj b/Dependencies/PSDWriter/PSDWriter-Mac.xcodeproj/project.pbxproj new file mode 100644 index 0000000..7206852 --- /dev/null +++ b/Dependencies/PSDWriter/PSDWriter-Mac.xcodeproj/project.pbxproj @@ -0,0 +1,339 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 43066AFB15095A06003E5DD7 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43066AFA15095A06003E5DD7 /* Cocoa.framework */; }; + 43DDBFE416B63D9200255386 /* NSDataPSDAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 43DDBFDE16B63D9200255386 /* NSDataPSDAdditions.h */; }; + 43DDBFE516B63D9200255386 /* NSDataPSDAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 43DDBFDF16B63D9200255386 /* NSDataPSDAdditions.m */; }; + 43DDBFE616B63D9200255386 /* PSDLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 43DDBFE016B63D9200255386 /* PSDLayer.h */; }; + 43DDBFE716B63D9200255386 /* PSDLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 43DDBFE116B63D9200255386 /* PSDLayer.m */; }; + 43DDBFE816B63D9200255386 /* PSDWriter.h in Headers */ = {isa = PBXBuildFile; fileRef = 43DDBFE216B63D9200255386 /* PSDWriter.h */; }; + 43DDBFE916B63D9200255386 /* PSDWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 43DDBFE316B63D9200255386 /* PSDWriter.m */; }; + 43DDC00416B63E5600255386 /* PSDWriter-Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = 43DDC00316B63E5600255386 /* PSDWriter-Prefix.pch */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 43066AF715095A06003E5DD7 /* libPSDWriter-Mac.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPSDWriter-Mac.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 43066AFA15095A06003E5DD7 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 43066AFD15095A06003E5DD7 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; + 43066AFE15095A06003E5DD7 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; + 43066AFF15095A06003E5DD7 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 43DDBFDE16B63D9200255386 /* NSDataPSDAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSDataPSDAdditions.h; path = Shared/NSDataPSDAdditions.h; sourceTree = SOURCE_ROOT; }; + 43DDBFDF16B63D9200255386 /* NSDataPSDAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NSDataPSDAdditions.m; path = Shared/NSDataPSDAdditions.m; sourceTree = SOURCE_ROOT; }; + 43DDBFE016B63D9200255386 /* PSDLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PSDLayer.h; path = Shared/PSDLayer.h; sourceTree = SOURCE_ROOT; }; + 43DDBFE116B63D9200255386 /* PSDLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PSDLayer.m; path = Shared/PSDLayer.m; sourceTree = SOURCE_ROOT; }; + 43DDBFE216B63D9200255386 /* PSDWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PSDWriter.h; path = Shared/PSDWriter.h; sourceTree = SOURCE_ROOT; }; + 43DDBFE316B63D9200255386 /* PSDWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PSDWriter.m; path = Shared/PSDWriter.m; sourceTree = SOURCE_ROOT; }; + 43DDC00316B63E5600255386 /* PSDWriter-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "PSDWriter-Prefix.pch"; path = "Shared/PSDWriter-Prefix.pch"; sourceTree = SOURCE_ROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 43066AF415095A06003E5DD7 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 43066AFB15095A06003E5DD7 /* Cocoa.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 43066AEC15095A06003E5DD7 = { + isa = PBXGroup; + children = ( + 43066B0015095A06003E5DD7 /* PSDWriter-Mac */, + 43066AF915095A06003E5DD7 /* Frameworks */, + 43066AF815095A06003E5DD7 /* Products */, + ); + sourceTree = ""; + }; + 43066AF815095A06003E5DD7 /* Products */ = { + isa = PBXGroup; + children = ( + 43066AF715095A06003E5DD7 /* libPSDWriter-Mac.a */, + ); + name = Products; + sourceTree = ""; + }; + 43066AF915095A06003E5DD7 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 43066AFA15095A06003E5DD7 /* Cocoa.framework */, + 43066AFC15095A06003E5DD7 /* Other Frameworks */, + ); + name = Frameworks; + sourceTree = ""; + }; + 43066AFC15095A06003E5DD7 /* Other Frameworks */ = { + isa = PBXGroup; + children = ( + 43066AFD15095A06003E5DD7 /* AppKit.framework */, + 43066AFE15095A06003E5DD7 /* CoreData.framework */, + 43066AFF15095A06003E5DD7 /* Foundation.framework */, + ); + name = "Other Frameworks"; + sourceTree = ""; + }; + 43066B0015095A06003E5DD7 /* PSDWriter-Mac */ = { + isa = PBXGroup; + children = ( + 43066B1115095A38003E5DD7 /* Classes */, + 43066B0115095A06003E5DD7 /* Supporting Files */, + ); + path = "PSDWriter-Mac"; + sourceTree = ""; + }; + 43066B0115095A06003E5DD7 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 43DDC00316B63E5600255386 /* PSDWriter-Prefix.pch */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 43066B1115095A38003E5DD7 /* Classes */ = { + isa = PBXGroup; + children = ( + 43DDBFDE16B63D9200255386 /* NSDataPSDAdditions.h */, + 43DDBFDF16B63D9200255386 /* NSDataPSDAdditions.m */, + 43DDBFE016B63D9200255386 /* PSDLayer.h */, + 43DDBFE116B63D9200255386 /* PSDLayer.m */, + 43DDBFE216B63D9200255386 /* PSDWriter.h */, + 43DDBFE316B63D9200255386 /* PSDWriter.m */, + ); + path = Classes; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 43066AF515095A06003E5DD7 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 43DDBFE416B63D9200255386 /* NSDataPSDAdditions.h in Headers */, + 43DDBFE616B63D9200255386 /* PSDLayer.h in Headers */, + 43DDBFE816B63D9200255386 /* PSDWriter.h in Headers */, + 43DDC00416B63E5600255386 /* PSDWriter-Prefix.pch in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 43066AF615095A06003E5DD7 /* PSDWriter-Mac */ = { + isa = PBXNativeTarget; + buildConfigurationList = 43066B0815095A06003E5DD7 /* Build configuration list for PBXNativeTarget "PSDWriter-Mac" */; + buildPhases = ( + 43066AF315095A06003E5DD7 /* Sources */, + 43066AF415095A06003E5DD7 /* Frameworks */, + 43066AF515095A06003E5DD7 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "PSDWriter-Mac"; + productName = "PSDWriter-Mac"; + productReference = 43066AF715095A06003E5DD7 /* libPSDWriter-Mac.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 43066AEE15095A06003E5DD7 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1320; + }; + buildConfigurationList = 43066AF115095A06003E5DD7 /* Build configuration list for PBXProject "PSDWriter-Mac" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + English, + en, + ); + mainGroup = 43066AEC15095A06003E5DD7; + productRefGroup = 43066AF815095A06003E5DD7 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 43066AF615095A06003E5DD7 /* PSDWriter-Mac */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 43066AF315095A06003E5DD7 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 43DDBFE516B63D9200255386 /* NSDataPSDAdditions.m in Sources */, + 43DDBFE716B63D9200255386 /* PSDLayer.m in Sources */, + 43DDBFE916B63D9200255386 /* PSDWriter.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 43066B0615095A06003E5DD7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + 43066B0715095A06003E5DD7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + SDKROOT = macosx; + }; + name = Release; + }; + 43066B0915095A06003E5DD7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)\"", + ); + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "Shared/PSDWriter-Prefix.pch"; + ONLY_ACTIVE_ARCH = NO; + OTHER_LDFLAGS = ( + "-all_load", + "-ObjC", + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 43066B0A15095A06003E5DD7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)\"", + ); + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "Shared/PSDWriter-Prefix.pch"; + ONLY_ACTIVE_ARCH = NO; + OTHER_LDFLAGS = ( + "-all_load", + "-ObjC", + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 43066AF115095A06003E5DD7 /* Build configuration list for PBXProject "PSDWriter-Mac" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 43066B0615095A06003E5DD7 /* Debug */, + 43066B0715095A06003E5DD7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 43066B0815095A06003E5DD7 /* Build configuration list for PBXNativeTarget "PSDWriter-Mac" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 43066B0915095A06003E5DD7 /* Debug */, + 43066B0A15095A06003E5DD7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 43066AEE15095A06003E5DD7 /* Project object */; +} diff --git a/Dependencies/PSDWriter/PSDWriter-Mac.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Dependencies/PSDWriter/PSDWriter-Mac.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..6a51f77 --- /dev/null +++ b/Dependencies/PSDWriter/PSDWriter-Mac.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Dependencies/PSDWriter/PSDWriter-iOS.xcodeproj/project.pbxproj b/Dependencies/PSDWriter/PSDWriter-iOS.xcodeproj/project.pbxproj new file mode 100644 index 0000000..6a2858b --- /dev/null +++ b/Dependencies/PSDWriter/PSDWriter-iOS.xcodeproj/project.pbxproj @@ -0,0 +1,276 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 43066A6A150955FF003E5DD7 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43066A69150955FF003E5DD7 /* Foundation.framework */; }; + 43066A8515095618003E5DD7 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43066A8415095618003E5DD7 /* CoreGraphics.framework */; }; + 43DDBFF716B63DD500255386 /* NSDataPSDAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 43DDBFF116B63DD500255386 /* NSDataPSDAdditions.h */; }; + 43DDBFF816B63DD500255386 /* NSDataPSDAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 43DDBFF216B63DD500255386 /* NSDataPSDAdditions.m */; }; + 43DDBFF916B63DD500255386 /* PSDLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 43DDBFF316B63DD500255386 /* PSDLayer.h */; }; + 43DDBFFA16B63DD500255386 /* PSDLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 43DDBFF416B63DD500255386 /* PSDLayer.m */; }; + 43DDBFFB16B63DD500255386 /* PSDWriter.h in Headers */ = {isa = PBXBuildFile; fileRef = 43DDBFF516B63DD500255386 /* PSDWriter.h */; }; + 43DDBFFC16B63DD500255386 /* PSDWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 43DDBFF616B63DD500255386 /* PSDWriter.m */; }; + 43DDBFFE16B63DF900255386 /* PSDWriter-Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = 43DDBFFD16B63DF900255386 /* PSDWriter-Prefix.pch */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 43066A66150955FF003E5DD7 /* libPSDWriter-iOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPSDWriter-iOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 43066A69150955FF003E5DD7 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 43066A8415095618003E5DD7 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 43DDBFF116B63DD500255386 /* NSDataPSDAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSDataPSDAdditions.h; path = Shared/NSDataPSDAdditions.h; sourceTree = SOURCE_ROOT; }; + 43DDBFF216B63DD500255386 /* NSDataPSDAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NSDataPSDAdditions.m; path = Shared/NSDataPSDAdditions.m; sourceTree = SOURCE_ROOT; }; + 43DDBFF316B63DD500255386 /* PSDLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PSDLayer.h; path = Shared/PSDLayer.h; sourceTree = SOURCE_ROOT; }; + 43DDBFF416B63DD500255386 /* PSDLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PSDLayer.m; path = Shared/PSDLayer.m; sourceTree = SOURCE_ROOT; }; + 43DDBFF516B63DD500255386 /* PSDWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PSDWriter.h; path = Shared/PSDWriter.h; sourceTree = SOURCE_ROOT; }; + 43DDBFF616B63DD500255386 /* PSDWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PSDWriter.m; path = Shared/PSDWriter.m; sourceTree = SOURCE_ROOT; }; + 43DDBFFD16B63DF900255386 /* PSDWriter-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "PSDWriter-Prefix.pch"; path = "Shared/PSDWriter-Prefix.pch"; sourceTree = SOURCE_ROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 43066A63150955FF003E5DD7 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 43066A8515095618003E5DD7 /* CoreGraphics.framework in Frameworks */, + 43066A6A150955FF003E5DD7 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 43066A5B150955FF003E5DD7 = { + isa = PBXGroup; + children = ( + 43066A6B150955FF003E5DD7 /* PSDWriter-iOS */, + 43066A68150955FF003E5DD7 /* Frameworks */, + 43066A67150955FF003E5DD7 /* Products */, + ); + sourceTree = ""; + }; + 43066A67150955FF003E5DD7 /* Products */ = { + isa = PBXGroup; + children = ( + 43066A66150955FF003E5DD7 /* libPSDWriter-iOS.a */, + ); + name = Products; + sourceTree = ""; + }; + 43066A68150955FF003E5DD7 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 43066A8415095618003E5DD7 /* CoreGraphics.framework */, + 43066A69150955FF003E5DD7 /* Foundation.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 43066A6B150955FF003E5DD7 /* PSDWriter-iOS */ = { + isa = PBXGroup; + children = ( + 43066BA615096243003E5DD7 /* Classes */, + 43066A6C150955FF003E5DD7 /* Supporting Files */, + ); + path = "PSDWriter-iOS"; + sourceTree = ""; + }; + 43066A6C150955FF003E5DD7 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 43DDBFFD16B63DF900255386 /* PSDWriter-Prefix.pch */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 43066BA615096243003E5DD7 /* Classes */ = { + isa = PBXGroup; + children = ( + 43DDBFF116B63DD500255386 /* NSDataPSDAdditions.h */, + 43DDBFF216B63DD500255386 /* NSDataPSDAdditions.m */, + 43DDBFF316B63DD500255386 /* PSDLayer.h */, + 43DDBFF416B63DD500255386 /* PSDLayer.m */, + 43DDBFF516B63DD500255386 /* PSDWriter.h */, + 43DDBFF616B63DD500255386 /* PSDWriter.m */, + ); + path = Classes; + sourceTree = SOURCE_ROOT; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 43066A64150955FF003E5DD7 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 43DDBFF716B63DD500255386 /* NSDataPSDAdditions.h in Headers */, + 43DDBFF916B63DD500255386 /* PSDLayer.h in Headers */, + 43DDBFFB16B63DD500255386 /* PSDWriter.h in Headers */, + 43DDBFFE16B63DF900255386 /* PSDWriter-Prefix.pch in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 43066A65150955FF003E5DD7 /* PSDWriter-iOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 43066A73150955FF003E5DD7 /* Build configuration list for PBXNativeTarget "PSDWriter-iOS" */; + buildPhases = ( + 43066A62150955FF003E5DD7 /* Sources */, + 43066A63150955FF003E5DD7 /* Frameworks */, + 43066A64150955FF003E5DD7 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "PSDWriter-iOS"; + productName = "PSDWriter-iOS"; + productReference = 43066A66150955FF003E5DD7 /* libPSDWriter-iOS.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 43066A5D150955FF003E5DD7 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0430; + }; + buildConfigurationList = 43066A60150955FF003E5DD7 /* Build configuration list for PBXProject "PSDWriter-iOS" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 43066A5B150955FF003E5DD7; + productRefGroup = 43066A67150955FF003E5DD7 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 43066A65150955FF003E5DD7 /* PSDWriter-iOS */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 43066A62150955FF003E5DD7 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 43DDBFF816B63DD500255386 /* NSDataPSDAdditions.m in Sources */, + 43DDBFFA16B63DD500255386 /* PSDLayer.m in Sources */, + 43DDBFFC16B63DD500255386 /* PSDWriter.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 43066A71150955FF003E5DD7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 5.1; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 43066A72150955FF003E5DD7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + COPY_PHASE_STRIP = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 5.1; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 43066A74150955FF003E5DD7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + DEAD_CODE_STRIPPING = NO; + DSTROOT = /tmp/PSDWriter_iOS.dst; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "Shared/PSDWriter-Prefix.pch"; + LINK_WITH_STANDARD_LIBRARIES = YES; + MACH_O_TYPE = staticlib; + MACOSX_DEPLOYMENT_TARGET = 10.7; + PRODUCT_NAME = "$(TARGET_NAME)"; + SEPARATE_STRIP = NO; + SKIP_INSTALL = YES; + STRIP_STYLE = "non-global"; + }; + name = Debug; + }; + 43066A75150955FF003E5DD7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + DEAD_CODE_STRIPPING = NO; + DSTROOT = /tmp/PSDWriter_iOS.dst; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "Shared/PSDWriter-Prefix.pch"; + LINK_WITH_STANDARD_LIBRARIES = YES; + MACH_O_TYPE = staticlib; + MACOSX_DEPLOYMENT_TARGET = 10.7; + PRODUCT_NAME = "$(TARGET_NAME)"; + SEPARATE_STRIP = NO; + SKIP_INSTALL = YES; + STRIP_STYLE = "non-global"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 43066A60150955FF003E5DD7 /* Build configuration list for PBXProject "PSDWriter-iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 43066A71150955FF003E5DD7 /* Debug */, + 43066A72150955FF003E5DD7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 43066A73150955FF003E5DD7 /* Build configuration list for PBXNativeTarget "PSDWriter-iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 43066A74150955FF003E5DD7 /* Debug */, + 43066A75150955FF003E5DD7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 43066A5D150955FF003E5DD7 /* Project object */; +} diff --git a/Dependencies/PSDWriter/PSDWriter-iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Dependencies/PSDWriter/PSDWriter-iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..573dd1b --- /dev/null +++ b/Dependencies/PSDWriter/PSDWriter-iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Dependencies/PSDWriter/Shared/NSDataPSDAdditions.h b/Dependencies/PSDWriter/Shared/NSDataPSDAdditions.h new file mode 100644 index 0000000..849122f --- /dev/null +++ b/Dependencies/PSDWriter/Shared/NSDataPSDAdditions.h @@ -0,0 +1,52 @@ +// +// NSDataPSDAdditions.h +// PSDWriter +// +// Created by Ben Gotow on 5/24/09. +// Copyright 2009 __MyCompanyName__. All rights reserved. +// + +#import + + +@interface NSMutableData (PSDAdditions) + +/** Allows you to append a numeric value to an NSMutableData object and pad it to any length. + +For example, we could say [data appendValue: 2 withLength: 5], and 00002 would be written +into the data object. Very useful for writing to file formats that have header structures +that require a certain number of bytes be used for a certain value. i.e. PSD and TIFF + +@param value: The value to append +@param length: The number of bytes that should be used to store the value. The value will be padded +to length bytes regardless of the number of bytes required to store it. +*/ +- (void)appendValue:(long)value withLength:(int)length; + +@end + +@interface NSData (PSDAdditions) + +/** Takes packedBits data and prints out a description of the packed contents by +running the decode operation and explaining via NSLog how the data is being +decoded. Useful for checking that packedBits data is correct. */ +- (NSString *)packedBitsDescription; + +/** A special version of packedBits which will take the data and pack every nth +value. + +This is important for PSDWriter because it's necessary to encode R, then G, +then B, then A data - so we essentially start at offset 0, skip 4, then do offset 1, +skip 4, etc... to compress the data with very minimal memory footprint. + +For normal packbits just to skip = 1 + +@param range: The range within the data object that should be encoded. Useful +for specifying a non-zero starting offset to get a certain channel encoded. +@param skip: The number of bytes to advance as the data is encoded. Skip = 1 will +encode every byte, skip = 4 will encode every fourth byte, and so on. +*/ +- (NSData *)packedBitsForRange:(NSRange)range skip:(int)skip; + + +@end diff --git a/Dependencies/PSDWriter/Shared/NSDataPSDAdditions.m b/Dependencies/PSDWriter/Shared/NSDataPSDAdditions.m new file mode 100644 index 0000000..de146f6 --- /dev/null +++ b/Dependencies/PSDWriter/Shared/NSDataPSDAdditions.m @@ -0,0 +1,199 @@ +// +// NSDataPSDAdditions.m +// PSDWriter +// +// Created by Ben Gotow on 5/24/09. +// Copyright 2009 __MyCompanyName__. All rights reserved. +// + +#import "NSDataPSDAdditions.h" + +#define MIN_RUN 3 /* minimum run length to encode */ +#define MAX_RUN 127 /* maximum run length to encode */ +#define MAX_COPY 128 /* maximum characters to copy */ + +/* maximum that can be read before copy block is written */ +#define MAX_READ (MAX_COPY + MIN_RUN - 1) + + +@implementation NSMutableData (PSDAdditions) + +- (void)appendValue:(long)value withLength:(int)length +{ + Byte bytes[8]; + + double divider = 1; + for (int ii = 0; ii < length; ii++){ + bytes[length-ii-1] = (long)(value / divider) % 256; + divider *= 256; + } + + [self appendBytes:&bytes length:length]; +} + +@end + +@implementation NSData (PSDAdditions) + +- (NSString*)packedBitsDescription +{ + NSMutableString * description = [NSMutableString string]; + char * row = (char*)[self bytes]; + int pbOffset = 0; + int pbResultBytes = 0; + + while (pbOffset < [self length]){ + int headerByte = (int)row[pbOffset]; + if (headerByte < 0){ + int repeatTimes = 1-headerByte; + UInt8 repeatByte = (UInt8)row[pbOffset+1]; + [description appendFormat: @"Printing %u %d times. ", repeatByte, repeatTimes]; + + pbResultBytes += repeatTimes; + pbOffset += 2; + } else if (headerByte >= 0){ + [description appendFormat: @"Printing %d literal bytes. ", headerByte + 1]; + pbResultBytes += headerByte + 1; + pbOffset += 2 + headerByte; + } + } + + [description appendFormat: @"Total: %d bytes decoded.", pbResultBytes]; + return description; +} + +- (NSData*)packedBitsForRange:(NSRange)range skip:(int)skip +{ + const char * bytesIn = [self bytes]; + unsigned long bytesLength = range.location + range.length; + unsigned long bytesOffset = range.location; + NSMutableData * dataOut = [NSMutableData data]; + + BOOL currIsEOF = NO; + unsigned char currChar; /* current character */ + unsigned char charBuf[MAX_READ]; /* buffer of already read characters */ + int count; /* number of characters in a run */ + + /* prime the read loop */ + currChar = bytesIn[bytesOffset]; + bytesOffset = bytesOffset + skip; + count = 0; + + /* read input until there's nothing left */ + while (!currIsEOF) + { + charBuf[count] = (unsigned char)currChar; + count++; + + if (count >= MIN_RUN) { + int i; + /* check for run charBuf[count - 1] .. charBuf[count - MIN_RUN]*/ + for (i = 2; i <= MIN_RUN; i++){ + if (currChar != charBuf[count - i]){ + /* no run */ + i = 0; + break; + } + } + + if (i != 0) + { + /* we have a run write out buffer before run*/ + int nextChar; + + if (count > MIN_RUN){ + /* block size - 1 followed by contents */ + UInt8 a = count - MIN_RUN - 1; + [dataOut appendBytes:&a length:sizeof(UInt8)]; + [dataOut appendBytes:&charBuf length:sizeof(unsigned char) * (count - MIN_RUN)]; + } + + /* determine run length (MIN_RUN so far) */ + count = MIN_RUN; + while (true) { + if (bytesOffset < bytesLength){ + nextChar = bytesIn[bytesOffset]; + bytesOffset += skip; + } else { + currIsEOF = YES; + nextChar = EOF; + } + if (nextChar != currChar) break; + + count++; + if (count == MAX_RUN){ + /* run is at max length */ + break; + } + } + + /* write out encoded run length and run symbol */ + UInt8 a = ((int)(1 - (int)(count))); + [dataOut appendBytes:&a length:sizeof(UInt8)]; + [dataOut appendBytes:&currChar length:sizeof(UInt8)]; + + if ((!currIsEOF) && (count != MAX_RUN)){ + /* make run breaker start of next buffer */ + charBuf[0] = nextChar; + count = 1; + } else { + /* file or max run ends in a run */ + count = 0; + } + } + } + + if (count == MAX_READ) + { + int i; + + /* write out buffer */ + UInt8 a = MAX_COPY - 1; + [dataOut appendBytes:&a length:sizeof(UInt8)]; + [dataOut appendBytes:&charBuf[0] length:sizeof(unsigned char) * MAX_COPY]; + + /* start a new buffer */ + count = MAX_READ - MAX_COPY; + + /* copy excess to front of buffer */ + for (i = 0; i < count; i++) + charBuf[i] = charBuf[MAX_COPY + i]; + } + + if (bytesOffset < bytesLength) + currChar = bytesIn[bytesOffset]; + else + currIsEOF = YES; + bytesOffset += skip; + } + + /* write out last buffer */ + if (0 != count) + { + if (count <= MAX_COPY) { + /* write out entire copy buffer */ + UInt8 a = count - 1; + [dataOut appendBytes:&a length:sizeof(UInt8)]; + [dataOut appendBytes:&charBuf length:sizeof(unsigned char) * count]; + } + else + { + /* we read more than the maximum for a single copy buffer */ + UInt8 a = MAX_COPY - 1; + [dataOut appendBytes:&a length:sizeof(UInt8)]; + [dataOut appendBytes:&charBuf length:sizeof(unsigned char) * MAX_COPY]; + + /* write out remainder */ + count -= MAX_COPY; + a = count - 1; + [dataOut appendBytes:&a length:sizeof(UInt8)]; + [dataOut appendBytes:&charBuf[MAX_COPY] length:sizeof(unsigned char) * count]; + } + } + + return dataOut; +} + + + +@end diff --git a/Dependencies/PSDWriter/Shared/PSDLayer.h b/Dependencies/PSDWriter/Shared/PSDLayer.h new file mode 100755 index 0000000..5071b97 --- /dev/null +++ b/Dependencies/PSDWriter/Shared/PSDLayer.h @@ -0,0 +1,64 @@ +// +// PSDLayer.h +// PSDWriterLibrary +// +// Created by Ben Gotow on 3/8/12. +// Copyright (c) 2012 __MyCompanyName__. All rights reserved. +// + +#import + +#if TARGET_OS_IPHONE +#import +#endif + +@interface PSDLayer : NSObject +{ + NSString * name; + NSData * imageData; + float opacity; + CGRect rect; + NSInteger blendMode; + bool nonBaseLayer; +} + +/** The name of the layer. I believe this must be 16 characters or less. + Correction: must be padded to multiple of 4 include 1 byte length byte. Max size 256 bytes. + */ + +@property (nonatomic, retain) NSString * name; +/** The image data in RGBA or RGB format, + depending on whether the PSDWriter.layerChannelCount is set to 4 or 3, respectively.*/ +@property (nonatomic, retain) NSData * imageData; + +/** The opacity of the layer between 0 and 1. */ +@property (nonatomic, assign) float opacity; + +/** The blend modes */ + enum PSDBlendModes { + kPSDBlendModeNormal=0, + kPSDBlendModeDisolve, + kPSDBlendModeDarken, + kPSDBlendModeMultiply, + + kPSDBlendModeColorBurn, + kPSDBlendModeLinearBurn, + kPSDBlendModeDarkerColor, + kPSDBlendModeLighten, + + kPSDBlendModeScreen, + kPSDBlendModeColorDodge, + kPSDBlendModeLinearDodge, + kPSDBlendModeLighter + }; + +@property (nonatomic, assign) NSInteger blendMode; + +@property (nonatomic, assign) bool nonBaseLayer; + +/** The rectangle the layer should be placed within in the PSD. + Note that scaling is not currently supported, so you should really only adjust the origin of this rect to move the imageData around within the PSD. +*/ +@property (nonatomic, assign) CGRect rect; + +@end diff --git a/Dependencies/PSDWriter/Shared/PSDLayer.m b/Dependencies/PSDWriter/Shared/PSDLayer.m new file mode 100755 index 0000000..a3727a3 --- /dev/null +++ b/Dependencies/PSDWriter/Shared/PSDLayer.m @@ -0,0 +1,22 @@ +// +// PSDLayer.m +// PSDWriterLibrary +// +// Created by Ben Gotow on 3/8/12. +// Copyright (c) 2012 __MyCompanyName__. All rights reserved. +// + +#import "PSDLayer.h" + +@implementation PSDLayer + +@synthesize imageData, name, opacity, rect, blendMode; + +- (void)dealloc +{ + [imageData release]; + [name release]; + [super dealloc]; +} + +@end diff --git a/Dependencies/PSDWriter/Shared/PSDWriter-Prefix.pch b/Dependencies/PSDWriter/Shared/PSDWriter-Prefix.pch new file mode 100644 index 0000000..dfbb6a1 --- /dev/null +++ b/Dependencies/PSDWriter/Shared/PSDWriter-Prefix.pch @@ -0,0 +1,7 @@ +// +// Prefix header for all source files of the 'PSDWriter-iOS' target in the 'PSDWriter-iOS' project +// + +#ifdef __OBJC__ + #import +#endif diff --git a/Dependencies/PSDWriter/Shared/PSDWriter.h b/Dependencies/PSDWriter/Shared/PSDWriter.h new file mode 100755 index 0000000..757571a --- /dev/null +++ b/Dependencies/PSDWriter/Shared/PSDWriter.h @@ -0,0 +1,101 @@ +// +// PSDWriter.h +// PSDWriter +// +// Created by Ben Gotow on 5/23/09. +// Copyright 2009 __MyCompanyName__. All rights reserved. +// + +#import +#import +#if TARGET_OS_IPHONE +#import +#endif + +@interface PSDWriter : NSObject +{ + CGSize documentSize; + NSMutableArray * layers; + int layerChannelCount; + + NSData * flattenedData; + CGContextRef flattenedContext; + + BOOL shouldFlipLayerData; + BOOL shouldUnpremultiplyLayerData; +} + +/** The PSDLayer objects with layer data, names, etc... Note that when you call +createPSDData, this array is slowly emptied - the PSDWriter removes the individual layers +from memory as it builds the PSD file. */ +@property (nonatomic, retain) NSMutableArray *layers; + +/** The size of the PSD you're exporting. */ +@property (nonatomic, assign) CGSize documentSize; + +/** The number of channels in each layer. Defaults to 4, unless layers +are not transparent. At the moment, this setting applies to all layers.*/ +@property (nonatomic, assign) int layerChannelCount; + +/** Optional. The RGBA data for a flattened "preview" of the PSD. */ +@property (nonatomic, retain) NSData * flattenedData; + +/** Allows you to automatically vertically flip the image data when it's being +written to PSD. This is important if the source images are coming from OpenGL or +another drawing system with an inverted coordinate system.*/ +@property (nonatomic, assign) BOOL shouldFlipLayerData; + +/** Allows you to automatically unpremultiply the image data. Premultiplication is +a process by which the R,G, and B values are multiplied by the alpha. Setting this +to YES will cause RGB to be divided by A. You'll know you need to do this if the +image comes out darker than you expect. */ +@property (nonatomic, assign) BOOL shouldUnpremultiplyLayerData; + +/** Initializes a new PSDWriter for creating a PSD document with the specified size. +@param s The document size*/ +- (id)initWithDocumentSize:(CGSize)s; + +/** Adds a new layer to the PSD image with the provided properties. + +If you are using NSImages and not CGImages, use the following code to convert to CGImageRefs: + + NSImage* yourImage; + CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)[yourImage TIFFRepresentation], NULL); + CGImageRef imageRef = CGImageSourceCreateImageAtIndex(source, 0, NULL); + +If you prefer, you can setup PSDLayers by yourself +and put them in the PSDWriter.layers array, but this method automatically creates the flattenedData, +an image that is a flattened preview of the layered PSD. If you populate the layer objects yourself, +you need to provide the flattened image data yourself. + +Note: Having layers partially off the edge of the canvas is not currently supported. + +@param image The image to be added. Does not need to be the same size as the document, but it cannot be larger. +@param name The name you'd like to give the layer. +@param opacity The opacity of the layer, from [0-1] +@param offset The offset of the layer within the document. Use this to position layers within the PSD. +*/ +- (void)addLayerWithCGImage:(CGImageRef)image andName:(NSString*)name andOpacity:(float)opacity andOffset:(CGPoint)offset; +- (void)addLayerWithCGImage:(CGImageRef)image + andName:(NSString*)name + andOpacity:(float)opacity + andOffset:(CGPoint)offset + andBlendMode: (NSInteger) blendMode + andIsNonBaseLayer:(bool)isNonBase; + +/* Generates an NSData object representing a PSD image with the width and height specified by documentSize +and the contents specified by the layers array. Note that this function can be (and really should be) +called on a separate thread. + +@return PSD data. Write this data to a file or attach it to an email, etc... + +Note: You cannot call this function multiple times. After calling createPSDData and getting the document data, +you should discard the PSDWriter object. This function is destructive and deletes the information you provided +in the layers array to conserve memory as it writes the PSD data. +*/ +- (NSData *)createPSDData; + +@end + +/** A convenience function for getting RGBA NSData from a CGImageRef. */ +NSData *CGImageGetData(CGImageRef image, CGRect region); diff --git a/Dependencies/PSDWriter/Shared/PSDWriter.m b/Dependencies/PSDWriter/Shared/PSDWriter.m new file mode 100755 index 0000000..143f6ae --- /dev/null +++ b/Dependencies/PSDWriter/Shared/PSDWriter.m @@ -0,0 +1,817 @@ +// +// PSDWriter.m +// PSDWriter +// +// Created by Ben Gotow on 5/23/09. +// Copyright 2009 __MyCompanyName__. All rights reserved. +// + +#import "PSDWriter.h" +#import "NSDataPSDAdditions.h" +#import "PSDLayer.h" + + char signature8BIM[4] = {'8','B','I','M'}; + +// Blend mode key: 'pass' = pass through, +// 'norm' = normal, 'diss' = dissolve, 'dark' = darken, 'mul ' = multiply, +char blendModeNormKey[4] = {'n','o','r','m'}; +char blendModeDissKey[4] = {'d','i','s','s'}; +char blendModeDarkKey[4] = {'d','a','r','k'}; +char blendModeMulKey[4] = {'m','u','l',' '}; + +// 'idiv' = color burn, 'lbrn' = linear burn, 'dkCl' = darker color, 'lite' = lighten, +char blendModeIdivKey[4] = {'i','d','i','v'}; +char blendModeLbrnKey[4] = {'l','b','r','n'}; +char blendModeDkclKey[4] = {'d','k','C','l'}; +char blendModeLiteKey[4] = {'l','i','t','e'}; + +// 'scrn' = screen, 'div ' = color dodge, 'lddg' = linear dodge, 'lgCl' = lighter +char blendModeScrnKey[4] = {'s','c','r','n'}; +char blendModeDivKey[4] = {'d','i','v',' '}; +char blendModeLddgKey[4] = {'l','d','d','g'}; +char blendModeLgClKey[4] = {'l','g','C','l'}; + +// color, 'over' = overlay, 'sLit' = soft light, 'hLit' = hard light, 'vLit' = vivid light, +// 'lLit' = linear light, 'pLit' = pin light, 'hMix' = hard mix, 'diff' = difference, +// 'smud' = exclusion, 'fsub' = subtract, 'fdiv' = divide, +// 'hue ' = hue, 'sat ' = saturation, 'colr' = color, 'lum ' = luminosity, +char blendModeHueKey[4] = {'h','u','e',' '}; +char blendModeSatKey[4] = {'s','a','t',' '}; +char blendModeColKey[4] = {'c','o','l','r'}; +char blendModeLumKey[4] = {'l','u','m',' '}; +char *blendModes[36] = +{ &blendModeNormKey, + &blendModeDissKey, + &blendModeDarkKey, + &blendModeMulKey, + + &blendModeIdivKey, + &blendModeLbrnKey, + &blendModeDkclKey, + &blendModeLiteKey, + + &blendModeScrnKey, + &blendModeDivKey, + &blendModeLddgKey, + &blendModeLgClKey, + + 0 }; + + +@implementation PSDWriter + +@synthesize documentSize; +@synthesize layers; +@synthesize layerChannelCount; +@synthesize flattenedData; + +@synthesize shouldFlipLayerData; +@synthesize shouldUnpremultiplyLayerData; + +- (id)init +{ + self = [super init]; + if (self){ + layerChannelCount = 4; + shouldFlipLayerData = NO; + shouldUnpremultiplyLayerData = NO; + flattenedContext = NULL; + flattenedData = nil; + layers = [[NSMutableArray alloc] init]; + } + return self; +} + +- (id)initWithDocumentSize:(CGSize)s +{ + self = [self init]; + if (self){ + documentSize = s; + } + return self; +} +- (void)addLayerWithCGImage:(CGImageRef)image + andName:(NSString*)name + andOpacity:(float)opacity + andOffset:(CGPoint)offset +{ + [self addLayerWithCGImage:(CGImageRef)image + andName:(NSString*)name + andOpacity:(float)opacity + andOffset:(CGPoint)offset + andBlendMode: kPSDBlendModeNormal + andIsNonBaseLayer:false]; + +} +- (void)addLayerWithCGImage:(CGImageRef)image + andName:(NSString*)name + andOpacity:(float)opacity + andOffset:(CGPoint)offset + andBlendMode: (NSInteger) blendMode + andIsNonBaseLayer:(bool)isNonBase +{ + PSDLayer * l = [[[PSDLayer alloc] init] autorelease]; + + CGRect imageRegion = CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)); + CGRect screenRegion = CGRectMake(offset.x, offset.y, imageRegion.size.width, imageRegion.size.height); + CGRect drawRegion = CGRectMake(offset.x, offset.y, imageRegion.size.width, imageRegion.size.height); + + if (screenRegion.origin.x + screenRegion.size.width > documentSize.width) + imageRegion.size.width = screenRegion.size.width = documentSize.width - screenRegion.origin.x; + if (screenRegion.origin.y + screenRegion.size.height > documentSize.height) + imageRegion.size.height = screenRegion.size.height = documentSize.height - screenRegion.origin.y; + if (screenRegion.origin.x < 0) { + imageRegion.origin.x = abs(screenRegion.origin.x); + screenRegion.origin.x = 0; + screenRegion.size.width = imageRegion.size.width = imageRegion.size.width - imageRegion.origin.x; + } + if (screenRegion.origin.y < 0) { + imageRegion.origin.y = abs(screenRegion.origin.y); + screenRegion.origin.y = 0; + screenRegion.size.height = imageRegion.size.height = imageRegion.size.height - imageRegion.origin.y; + } + // get part of the image that fix on the screen. + [l setImageData: CGImageGetData(image, imageRegion)]; + [l setOpacity: opacity]; + [l setRect: screenRegion]; + [l setName: name]; // 0 - 15 char kept currently (padded with spaces) + [l setBlendMode:blendMode]; // Normal = 0. + [l setNonBaseLayer:isNonBase]; + + [layers addObject: l]; + + if (flattenedData == nil) { + if ((documentSize.width == 0) || (documentSize.height == 0)) + @throw [NSException exceptionWithName:NSGenericException reason:@"You must specify a non-zero documentSize before calling addLayer:" userInfo:nil]; + + if (flattenedContext == NULL) { + flattenedContext = CGBitmapContextCreate(NULL, documentSize.width, documentSize.height, 8, 0, CGImageGetColorSpace(image), kCGBitmapByteOrder32Host|kCGImageAlphaPremultipliedLast); + CGContextSetRGBFillColor(flattenedContext, 1, 1, 1, 1); + CGContextFillRect(flattenedContext, CGRectMake(0, 0, documentSize.width, documentSize.height)); + } + drawRegion.origin.y = documentSize.height - (drawRegion.origin.y + drawRegion.size.height); + CGContextSetAlpha(flattenedContext, opacity); + CGContextDrawImage(flattenedContext, drawRegion, image); + CGContextSetAlpha(flattenedContext, opacity); + } +} + +/* Generates an NSData object representing a PSD image. + LayerData should contain an array of NSData + objects representing the RGBA layer data (8 bits per component) and a width and height of size. + flatData should contain the RGBA data of a single image made by flattening all of the layers. */ + +- (void)dealloc +{ + if (flattenedContext != NULL) { + CGContextRelease(flattenedContext); + flattenedContext = nil; + } + + [layers release]; + layers = nil; + [flattenedData release]; + flattenedData = nil; + + [super dealloc]; +} + +- (void)preprocess +{ + // do we have a flattenedContext that needs to become flattenedData? + if (flattenedData == nil) { + if (flattenedContext) { + CGImageRef i = CGBitmapContextCreateImage(flattenedContext); + flattenedData = [CGImageGetData(i, CGRectMake(0, 0, documentSize.width, documentSize.height)) retain]; + CGImageRelease(i); + } + } + if (flattenedContext) { + CGContextRelease(flattenedContext); + flattenedContext = nil; + + } + + if ((self.shouldFlipLayerData == NO) && (self.shouldUnpremultiplyLayerData == NO)) + return; + + for (PSDLayer * layer in layers) + { + NSData *d = [layer imageData]; + + // sketchy? yes. fast? oh yes. + UInt8 *data = (UInt8 *)[d bytes]; + unsigned long length = [d length]; + + if (self.shouldUnpremultiplyLayerData) { + // perform unpremultiplication + for(long i = 0; i < length; i+=4) { + float a = ((float)data[(i + 3)]) / 255.0; + data[(i+0)] = (int) fmax(0, fmin((float)data[(i+0)] / a, 255)); + data[(i+1)] = (int) fmax(0, fmin((float)data[(i+1)] / a, 255)); + data[(i+2)] = (int) fmax(0, fmin((float)data[(i+2)] / a, 255)); + } + } + + if (self.shouldFlipLayerData) { + // perform flip over vertical axis + for (int x = 0; x < documentSize.width; x++) { + for (int y = 0; y < documentSize.height/2; y++) { + int top_index = (x+y*documentSize.width) * 4; + int bottom_index = (x+(documentSize.height-y-1)*documentSize.width) * 4; + char saved; + + for (int a = 0; a < 4; a++) { + saved = data[top_index+a]; + data[top_index+a] = data[bottom_index+a]; + data[bottom_index+a] = saved; + } + } + } + } + } +} + +// RMF Adding effects - work in progress not tested or debugged. +- (NSMutableData *) makeEffectLayer +{ // The key for the effects layer is 'lrFX' . + char effectKey[4] = {'l','r','F','X'}; + + NSMutableData *effectInfo = [[NSMutableData alloc] init]; + + NSInteger effectCnt = 1; // Effects count: may be 6 (for the 6 effects in Photoshop 5 and 6) or 7 (for Photoshop 7.0) + if (effectCnt> 7) NSLog(@"Effect Count Error"); + + /* Additional layer information - to hold effect layers + 4 Signature: '8BIM' + 4 Key: a 4-character code - The key for the effects layer is 'lrFX' + 4 Length data below, rounded up to an even byte count. */ + + NSUInteger effectLenght = 4 + 19 + 41 ; + + [effectInfo appendBytes:&signature8BIM length:4]; + [effectInfo appendBytes:&effectKey length:4]; + effectLenght = effectLenght + (effectLenght % 2); // round up to even + [effectInfo appendBytes:effectLenght length:4]; + + // add Effect header + [effectInfo appendValue:0 withLength:2]; // verison 0 + [effectInfo appendValue:effectCnt withLength:2]; // Effects count: may be 6 (for the 6 effects in Photoshop 5 and 6) or 7 (for Photoshop 7.0) + + /* + for each effect active.. + ouput: sign, Effects keys and effect data strucutre. + + Effects keys: OSType key for which effects type to use: + 'cmnS' = common state (see See Effects layer, common state info) + 'dsdw' = drop shadow (see See Effects layer, drop shadow and inner shadow info) + 'isdw' = inner shadow (see See Effects layer, drop shadow and inner shadow info) + 'oglw' = outer glow (see See Effects layer, outer glow info) + 'iglw' = inner glow (see See Effects layer, inner glow info) + 'bevl' = bevel (see See Effects layer, bevel info) + 'sofi' = solid fill ( Photoshop 7.0) (see See Effects layer, solid fill (added in Photoshop 7.0)) */ + char effectCommonState[4] = {'c','m','n','S'}; + char effectDropShadow[4] = {'d','s','d','w'}; + /* char effectInnerShadow[4] = {'i','s','d','w'}; + char effectOuterGlow[4] = {'o','g','l','w'}; + char effectInnerGlow[4] = {'i','g','l','w'}; + char effectBevel[4] = {'b','e','v','l'}; */ + + // commmon State (size = 19 bytes) + [effectInfo appendBytes:&signature8BIM length:4]; + [effectInfo appendBytes:&effectCommonState length:4]; + [effectInfo appendValue:7 withLength:4]; + [effectInfo appendValue:0 withLength:4]; + [effectInfo appendValue:1 withLength:1]; + [effectInfo appendValue:0 withLength:2]; + + // cDropShadow (size = ? bytes) +/* Length Description + 4 Size of the remaining items: 41 or 51 (depending on version) + 4 Version: 0 ( Photoshop 5.0) or 2 ( Photoshop 5.5) + 4 Blur value in pixels + 4 Intensity as a percent + 4 Angle in degrees + 4 Distance in pixels + 10 Color: 2 bytes for space followed by 4 * 2 byte color component + 8 Blend mode: 4 bytes for signature and 4 bytes for key + 1 Effect enabled + 1 Use this angle in all of the layer effects + 1 Opacity as a percent + 10 Native color: 2 bytes for space followed by 4 * 2 byte color component + */ + if (1) { // dropshadow effect + int dsBlurInPixels = 3; + int dsIntensity = 90; // 0-100% + int dsDistanceInPixels = 5; + int dsAngle = 60; // in Degrees + + [effectInfo appendBytes:&signature8BIM length:4]; + [effectInfo appendBytes:&effectDropShadow length:4]; + [effectInfo appendValue:41 withLength:4]; + [effectInfo appendValue:0 withLength:4]; // photoshop 5.0 + [effectInfo appendValue:dsBlurInPixels withLength:4]; + [effectInfo appendValue:dsIntensity withLength:4]; + [effectInfo appendValue:dsAngle withLength:4]; + [effectInfo appendValue:dsDistanceInPixels withLength:4]; + // FIXME -- color output + [effectInfo appendValue:255 + 255*256+255*256*256 withLength:10]; // color + // Blend Mode + [effectInfo appendBytes:&signature8BIM length:4]; + [effectInfo appendBytes:blendModes[kPSDBlendModeNormal] length:4]; + [effectInfo appendValue:1 withLength:1]; // Effect enabled + [effectInfo appendValue:0 withLength:1]; // Use this angle in all of the layer effects + [effectInfo appendValue:75 withLength:1]; // Opacity as a percent + } + +} + +- (NSData *)createPSDData +{ + char signature8BPS[4] = {'8','B','P','S'}; +// char signature8BIM[4] = {'8','B','I','M'}; + + + NSMutableData *result = [NSMutableData data]; + + // make sure the user has provided everything we need + if ((layerChannelCount < 3) || ([layers count] == 0)) + @throw [NSException exceptionWithName:NSGenericException reason:@"Please provide layer data, flattened data and set layer channel count to at least 3." userInfo:nil]; + + + // modify the input data if necessary + [self preprocess]; + +#pragma mark FILE HEADER SECTION + // ------------------------------------------------------------------------------- + // write the signature + [result appendBytes:&signature8BPS length:4]; + + // write the version number + [result appendValue:1 withLength:2]; + + // write reserved blank space + [result appendValue:0 withLength:6]; + + // write number of channels (Supported range is 1 to 56) + [result appendValue:layerChannelCount withLength:2]; + + // write height then width of the image in pixels. Supported range is 1 to 30,000. + [result appendValue:documentSize.height withLength:4]; + [result appendValue:documentSize.width withLength:4]; + + // write number of bits per channel (we only suppot 8, + // Valid values are 1, 8, 16 and 32.) + [result appendValue:8 withLength:2]; + + // write color mode (3 = RGB) + // Valid values are: Bitmap = 0; Grayscale = 1; Indexed = 2; RGB = 3; + // CMYK = 4; Multichannel = 7; Duotone = 8; Lab = 9. + [result appendValue:3 withLength:2]; + +#pragma mark COLOR MODE DATA SECTION - Only indexed color and duotone + // --------------------------------------------------------------------------------------- + // write color mode data section + // Only indexed color and duotone + // (see the mode field in the File header section) have color mode data. + // For all other modes, this section is just the 4-byte length field, which is set to zero. + // Indexed color images: length is 768; color data contains the color table for the image, in non-interleaved order. + [result appendValue:0 withLength:4]; + +#pragma mark IMAGE RESOURCES SECTION + // ------------------------------------------------------------------------------------- + // write images resources section. This is used to store things like current layer. + NSMutableData *imageResources = [[NSMutableData alloc] init]; + /* + 1005 ResolutionInfo structure + See Appendix A in Photoshop API Guide.pdf . + + 1008 The caption as a Pascal string. + + •1028 IPTC-NAA record + Contains the File Info... information. + See the documentation in the IPTC folder of the Documentation folder. + + •1039 (Photoshop 5.0) ICC Profile + The raw bytes of an ICC (International Color Consortium) format profile. + See ICC1v42_2006-05.pdf in the Documentation folder and icProfileHeader.h in Sample Code\Common\Includes . + •••••••• + + 1054 (Photoshop 6.0) URL List + 4 byte count of URLs, followed by 4 byte long, 4 byte ID, and Unicode string for each count. + + 1058 (Photoshop 7.0) EXIF data 1 + See http://www.kodak.com/global/plugins/acrobat/en/service/digCam/exifStandard2.pdf + •••••••••••••1059 (Photoshop 7.0) EXIF data 3 + See http://www.kodak.com/global/plugins/acrobat/en/service/digCam/exifStandard2.pdf + •••••••••••••1060 (Photoshop 7.0) XMP metadata + File info as XML description. See http://www.adobe.com/devnet/xmp/ + + 1065 (Photoshop CS) Layer Comps + 4 bytes (descriptor version = 16), Descriptor (see See Descriptor structure) + + 1069 (Photoshop CS2) Layer Selection ID(s) + 2 bytes count, following is repeated for each count: 4 bytes layer ID + + 1072 (Photoshop CS2) Layer Group(s) Enabled ID + 1 byte for each layer in the document, repeated by length of the resource. + NOTE: Layer groups have start and end markers + */ + + /* + // Naming the alpha channels isn't necessary, but here's how: + // Apparently those bytes contain 2 pascal strings? I think the last one is zero chars. + [imageResources appendBytes:&signature8BIM length:4]; + [imageResources appendValue:1006 withLength:2]; + [imageResources appendValue:0 withLength:2]; + [imageResources appendValue:19 withLength:4]; + Byte nameBytes[20] = {0x0C,0x54,0x72,0x61,0x6E,0x73,0x70,0x61,0x72,0x65,0x6E,0x63,0x79,0x05,0x45,0x78,0x74,0x72,0x61,0x00}; + [imageResources appendBytes:&nameBytes length:20]; + */ + + // RES: write the resolutionInfo structure. Don't have the definition for this, so we + // have to just paste in the right bytes. + [imageResources appendBytes:&signature8BIM length:4]; + [imageResources appendValue:1005 withLength:2]; + [imageResources appendValue:0 withLength:2]; + [imageResources appendValue:16 withLength:4]; + + Byte resBytes[16] = {0x00, 0x48, 0x00, 0x00,0x00,0x01,0x00,0x01,0x00,0x48,0x00,0x00,0x00,0x01,0x00,0x01}; + [imageResources appendBytes:&resBytes length:16]; + + // write the current layer structure + // RES: Layer state information + // 2 bytes containing the index of target layer (0 = bottom layer). + + [imageResources appendBytes:&signature8BIM length:4]; + [imageResources appendValue:1024 withLength:2]; + [imageResources appendValue:0 withLength:2]; + [imageResources appendValue:2 withLength:4]; + [imageResources appendValue:0 withLength:2]; // current layer = 0 + + [result appendValue:[imageResources length] withLength:4]; + [result appendData:imageResources]; + [imageResources release]; + + + // This is for later when we write the transparent top and bottom of the shape + int transparentRowSize = sizeof(Byte) * (int)ceilf(documentSize.width * 4); + Byte *transparentRow = malloc(transparentRowSize); + memset(transparentRow, 0, transparentRowSize); + + NSData *transparentRowData = [NSData dataWithBytesNoCopy:transparentRow length:transparentRowSize freeWhenDone:NO]; + NSData *packedTransparentRowData = [transparentRowData packedBitsForRange:NSMakeRange(0, transparentRowSize) skip:4]; + +#pragma mark LAYER + MASK INFORMATION SECTION + // ----------------------------------------------------------------------------------------- + // layer and mask information section. + // contains basic data about each layer (its mask, its channels, + // its layer effects, its annotations, transparency layers, wtf tons of shit.) + // We need to actually create this. + /* + The fourth section of a Photoshop file contains information about layers and masks. + This section of the document describes the formats of layer and mask records. + The complete merged image data is not stored here. + The complete merged/composite image resides in the last section of the file. + + If there are no layers or masks, this section is just 4 bytes: the length field, + which is set to zero. + NOTE: The length of the section may already be known.) + */ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + // build layer structure then add them to result + NSMutableData *layerInfo = [[NSMutableData alloc] init]; + NSMutableArray *layerChannels = [NSMutableArray array]; + NSUInteger layerCount = [layers count]; + + // Lenght value will be add at end. + // write the layer count + [layerInfo appendValue:layerCount withLength:2]; + + for (int layer = 0; layer < layerCount; layer++) + { + NSAutoreleasePool *outerPool = [[NSAutoreleasePool alloc] init]; + PSDLayer *aLayer = (PSDLayer*) [layers objectAtIndex:0]; + + NSData *imageData = [aLayer imageData]; + CGRect bounds = [aLayer rect]; + bounds.origin.x = floorf(bounds.origin.x); + bounds.origin.y = floorf(bounds.origin.y); + bounds.size.width = floorf(bounds.size.width); + bounds.size.height = floorf(bounds.size.height); + + // Check the bounds + if (bounds.origin.x < 0 || bounds.origin.y < 0) { + @throw [NSException exceptionWithName:@"LayerOutOfBounds" + reason:[NSString stringWithFormat:@"Layer %i's x or y origin is negative, which is unsupported", layer] + userInfo:nil]; + } + if (bounds.origin.x + bounds.size.width > documentSize.width || + bounds.origin.y + bounds.size.height > documentSize.height) { + @throw [NSException exceptionWithName:@"LayerOutOfBounds" + reason:[NSString stringWithFormat:@"Layer %i's bottom-right corner is beyond the edge of the canvas, which is unsupported", layer] + userInfo:nil]; + } + + int imageRowBytes = bounds.size.width * 4; // 8bit RGBA = 4 bytes + + // process Channel image data for each layer. + // + // too much padding is going on here + // FIX ME? -- only need image data area. + NSRange leftPackRange = NSMakeRange(0, (int)bounds.origin.x * 4); + NSData *packedLeftOfShape = [transparentRowData packedBitsForRange:leftPackRange skip:4]; + NSRange rightPackRange = NSMakeRange(0, (int)(documentSize.width - bounds.origin.x - bounds.size.width) * 4); + NSData *packedRightOfShape = [transparentRowData packedBitsForRange:rightPackRange skip:4]; + + for (int channel = 0; channel < layerChannelCount; channel++) + { + NSMutableData *byteCounts = [[NSMutableData alloc] initWithCapacity:documentSize.height * layerChannelCount * 2]; + NSMutableData *scanlines = [[NSMutableData alloc] init]; + + for (int row = 0; row < documentSize.height; row++) + { + // If it's above or below the shape's bounds, just write black with 0-alpha + if (row < (int)bounds.origin.y || + row >= (int)(bounds.origin.y + bounds.size.height)) { + [byteCounts appendValue:[packedTransparentRowData length] withLength:2]; + [scanlines appendData:packedTransparentRowData]; + } else { + int byteCount = 0; + + if (bounds.origin.x > 0.01) { + // Append the transparent portion to the left of the shape + [scanlines appendData:packedLeftOfShape]; + byteCount += [packedLeftOfShape length]; + } + + NSRange packRange = NSMakeRange((row - (int)bounds.origin.y) * imageRowBytes + channel, imageRowBytes); + NSData *packed = [imageData packedBitsForRange:packRange skip:4]; + [scanlines appendData:packed]; + byteCount += [packed length]; + + if (bounds.origin.x + bounds.size.width < documentSize.width) { + // Append the transparent portion to the right of the shape + [scanlines appendData:packedRightOfShape]; + byteCount += [packedRightOfShape length]; + } + + [byteCounts appendValue:byteCount withLength:2]; + } + } + + // write channel layer structure.. + // + // Image data. + // If the compression code is 0, the image data is just the raw image data, + // whose size is calculated as (LayerBottom- LayerTop)* (LayerRight-LayerLeft) + // If the compression code is 1, the image data starts with the byte counts for all the scan lines in the channel (LayerBottom- LayerTop), with each count stored as a two-byte value. + // The RLE compressed data follows, with each scan line compressed separately. + // If the layer's size, and therefore the data, is odd, a pad byte will be inserted at the end of the row. + + NSMutableData *channelData = [[NSMutableData alloc] init]; + // write channel compression format + [channelData appendValue:1 withLength:2]; // RLE = 1 + // write channel byte counts + [channelData appendData:byteCounts]; + // write channel scanlines + [channelData appendData:scanlines]; + + // add completed channel data to channels array + [layerChannels addObject:channelData]; + + [channelData release]; + [byteCounts release]; + [scanlines release]; + } // end for channel + + // print out top left bottom right 4x4 + [layerInfo appendValue:0 withLength:4]; + [layerInfo appendValue:0 withLength:4]; + [layerInfo appendValue:documentSize.height withLength:4]; + [layerInfo appendValue:documentSize.width withLength:4]; + + // print out number of channels in the layer + [layerInfo appendValue:layerChannelCount withLength:2]; + + // print out data about each channel + for (int c = 0; c < 3; c++) { + [layerInfo appendValue:c withLength:2]; + [layerInfo appendValue:[[layerChannels objectAtIndex:c + layer * 4] length] withLength:4]; + } + + // for some reason, the alpha channel is number -1, not 3... + Byte b[2] = {0xFF, 0xFF}; + [layerInfo appendBytes:&b length:2]; + [layerInfo appendValue:[[layerChannels objectAtIndex:3 + layer * 4] length] withLength:4]; + + // print out blend mode signature + [layerInfo appendBytes:&signature8BIM length:4]; + + // print out blend type + + // was: [layerInfo appendBytes:&blendModeNormKey length:4]; + [layerInfo appendBytes:blendModes[[aLayer blendMode]] length:4]; + + // print out opacity (0 = transparent ... 255 = opaque) + int opacity = ceilf([aLayer opacity] * 255.0f); + [layerInfo appendValue:opacity withLength:1]; + + // print out Clipping: 0 = base, 1 = non-base + if([aLayer nonBaseLayer]) { + [layerInfo appendValue:1 withLength:1]; + } else { + [layerInfo appendValue:0 withLength:1]; + } + + // print out flags. I think we're making the layer invisible + // Flags: + // bit 0 = transparency protected; + // bit 1 = visible; bit 2 = obsolete; + // bit 3 = 1 for Photoshop 5.0 and later, tells if bit 4 has useful information; + // bit 4 = pixel data irrelevant to appearance of document + + [layerInfo appendValue:1 withLength:1]; // Flags + [layerInfo appendValue:0 withLength:1]; // filler 0 + + // print out extra data length ( = the total length of the next five fields). + [layerInfo appendValue:4+4+16 withLength:4]; + + // print out extra data (mask info, layer name) + [layerInfo appendValue:0 withLength:4]; // Can be 40 bytes, 24 bytes, or 4 bytes if no layer mask. + [layerInfo appendValue:0 withLength:4]; // Layer blending ranges: + // char layerName[15] = {'L','a','y','e','r','s',' ','P','S','D',' ','1','2','3','4'}; + // [layerInfo appendValue:15 withLength:1]; + // [layerInfo appendBytes:&layerName length:15]; + + // NSString *layerNameString = [[layerNames objectAtIndex:layer] stringByAppendingString:@" "]; + // [layerNameString getCString:layerName maxLength:15 encoding:NSStringEncodingConversionAllowLossy]; + + NSString *layerName = [[aLayer name] stringByAppendingString:@" "]; + layerName = [layerName stringByPaddingToLength:15 withString:@" " startingAtIndex:0]; + const char *layerNameCString = [layerName cStringUsingEncoding:NSStringEncodingConversionAllowLossy]; + // Layer name: Pascal string 1 byte length + text, padded to a multiple of 4 bytes. + NSInteger len = [layerName length] ; + [layerInfo appendValue:len withLength:1]; + [layerInfo appendBytes:layerNameCString length:len]; + + [layers removeObjectAtIndex:0]; + [outerPool release]; + } // end for Layer + + free(transparentRow); + + // write the channel image data for each layer + while([layerChannels count] > 0) { + [layerInfo appendData:[layerChannels objectAtIndex:0]]; + [layerChannels removeObjectAtIndex:0]; + } + [pool release]; + + // round to length divisible by 2. + if ([layerInfo length] % 2 != 0) + [layerInfo appendValue:0 withLength:1]; + +#pragma mark - Add effect layers here. + + // Write Layer size then add layerdata (from layerInfo). + // write length of layer and mask information section + [result appendValue:[layerInfo length]+4 withLength:4]; + + // write length of layer info + [result appendValue:[layerInfo length] withLength:4]; + + + // write out actual layer info + [result appendData:layerInfo]; + [layerInfo release]; + + // This should be required. I'm not sure why it works without it. + // write out empty global layer section (globalLayerMaskLength == 0) + // [self writeValue:0 toData:result withLength:4]; + +#pragma mark IMAGE DATA SECTION + // --------------------------------------------------------------------------------------- + /* Image Data Section + + The last section of a Photoshop file contains the image pixel data. + Image data is stored in planar order: first all the red data, then all the green data, etc. + Each plane is stored in scan-line order, with no pad bytes, + + + Length Description + 2 Compression method: 0 = Raw image data +  + 1 = RLE compressed the image data starts with the byte counts for all the scan lines (rows * channels), with each count stored as a two-byte value. The RLE compressed data follows, with each scan line compressed separately. The RLE compression is the same compression algorithm used by the Macintosh ROM routine PackBits , and the TIFF standard. + 2 = ZIP without prediction + 3 = ZIP with prediction. + Variable The image data. Planar order = RRR GGG BBB, etc. + */ + // write compression format = 1 = RLE + [result appendValue:1 withLength:2]; // Compression. + + // With RLE compression, the image data starts with the byte counts for all of the scan lines (rows * channels) + // with each count stored as a 2-byte value. The RLE compressed data follows with each scan line compressed + // separately. Same as the TIFF standard. + + // in 512x512 image w/ no alpha, there are 3072 scan line bytes. + // At 2 bytes each, that means 1536 byte counts. + // 1536 = 512 rows * three channels. + + NSMutableData *byteCounts = [NSMutableData dataWithCapacity:documentSize.height * layerChannelCount * 2]; + NSMutableData *scanlines = [NSMutableData data]; + + int imageRowBytes = documentSize.width * 4; + + for (int channel = 0; channel < layerChannelCount; channel++) { + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + for (int row = 0; row < documentSize.height; row++) { + NSRange packRange = NSMakeRange(row * imageRowBytes + channel, imageRowBytes); + NSData * packed = [flattenedData packedBitsForRange:packRange skip:4]; + [byteCounts appendValue:[packed length] withLength:2]; + [scanlines appendData:packed]; + } // for row + [pool release]; + } // for channel (RGB or RGBA) + + // chop off the image data from the original file + [result appendData:byteCounts]; + [result appendData:scanlines]; + + return result; +} + +@end + + +NSData *CGImageGetData(CGImageRef image, CGRect region) +{ + // Create the bitmap context + CGContextRef context = NULL; + void * bitmapData; + int bitmapByteCount; + int bitmapBytesPerRow; + + // Get image width, height. We'll use the entire image. + int width = region.size.width; + int height = region.size.height; + + // Declare the number of bytes per row. Each pixel in the bitmap in this + // example is represented by 4 bytes; 8 bits each of red, green, blue, and + // alpha. + bitmapBytesPerRow = (width * 4); + bitmapByteCount = (bitmapBytesPerRow * height); + + // Allocate memory for image data. This is the destination in memory + // where any drawing to the bitmap context will be rendered. + // bitmapData = malloc(bitmapByteCount); + bitmapData = calloc(width * height * 4, sizeof(Byte)); + if (bitmapData == NULL) + { + return nil; + } + + // Create the bitmap context. We want pre-multiplied ARGB, 8-bits + // per component. Regardless of what the source image format is + // (CMYK, Grayscale, and so on) it will be converted over to the format + // specified here by CGBitmapContextCreate. + // CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); + CGColorSpaceRef colorspace = CGImageGetColorSpace(image); + context = CGBitmapContextCreate(bitmapData, width, height, 8, bitmapBytesPerRow, + colorspace, kCGImageAlphaPremultipliedLast); + // CGColorSpaceRelease(colorspace); + + if (context == NULL) + // error creating context + return nil; + + // Draw the image to the bitmap context. Once we draw, the memory + // allocated for the context for rendering will then contain the + // raw image data in the specified color space. + CGContextSaveGState(context); + + // CGContextTranslateCTM(context, -region.origin.x, -region.origin.y); + // CGContextDrawImage(context, region, image); + + // Draw the image without scaling it to fit the region + CGRect drawRegion; + drawRegion.origin = CGPointZero; + drawRegion.size.width = CGImageGetWidth(image); + drawRegion.size.height = CGImageGetHeight(image); + CGContextTranslateCTM(context, + -region.origin.x + (drawRegion.size.width - region.size.width), + -region.origin.y - (drawRegion.size.height - region.size.height)); + CGContextDrawImage(context, drawRegion, image); + CGContextRestoreGState(context); + + // When finished, release the context + CGContextRelease(context); + + // Now we can get a pointer to the image data associated with the bitmap context. + + NSData *data = [NSData dataWithBytes:bitmapData length:bitmapByteCount]; + free(bitmapData); + + return data; +} diff --git a/SilicaViewer.xcodeproj/project.pbxproj b/SilicaViewer.xcodeproj/project.pbxproj index 8dcee4d..04eeb44 100644 --- a/SilicaViewer.xcodeproj/project.pbxproj +++ b/SilicaViewer.xcodeproj/project.pbxproj @@ -31,9 +31,9 @@ 0371996027BAC5D800EE1DFD /* Silica_ViewerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0371995F27BAC5D800EE1DFD /* Silica_ViewerTests.swift */; }; 0371996727BACD8700EE1DFD /* ExportAccessoryView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0371996627BACD8700EE1DFD /* ExportAccessoryView.xib */; }; 0371996927BACDE800EE1DFD /* ExportAccessoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0371996827BACDE800EE1DFD /* ExportAccessoryView.swift */; }; + 03A2FE7B27CC3034004CDE91 /* libPSDWriter-Mac.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 03A2FE7927CC2EED004CDE91 /* libPSDWriter-Mac.a */; }; 03C39DE726F90734005555AE /* lzodefs.h in Headers */ = {isa = PBXBuildFile; fileRef = 03C39DE226F90733005555AE /* lzodefs.h */; }; 03C39DE826F90734005555AE /* Makefile in Sources */ = {isa = PBXBuildFile; fileRef = 03C39DE426F90734005555AE /* Makefile */; }; - 03C39DE926F90734005555AE /* testmini.c in Sources */ = {isa = PBXBuildFile; fileRef = 03C39DE526F90734005555AE /* testmini.c */; }; 03C39DEA26F90734005555AE /* minilzo.h in Headers */ = {isa = PBXBuildFile; fileRef = 03C39DE626F90734005555AE /* minilzo.h */; }; 03CB383B2419CA2D0078B3E5 /* libLZO.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 03CB382E2419C9DB0078B3E5 /* libLZO.a */; }; 03CB3840241A5AED0078B3E5 /* Shared.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03CB383F241A5AED0078B3E5 /* Shared.swift */; }; @@ -63,6 +63,13 @@ remoteGlobalIDString = 030F6FED2415C5E300A43F01; remoteInfo = SilicaViewer; }; + 03A2FE7827CC2EED004CDE91 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 03A2FE7427CC2EED004CDE91 /* PSDWriter-Mac.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 43066AF715095A06003E5DD7; + remoteInfo = "PSDWriter-Mac"; + }; 03CB383C2419CA2D0078B3E5 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 030F6FE62415C5E300A43F01 /* Project object */; @@ -120,10 +127,10 @@ 0371995F27BAC5D800EE1DFD /* Silica_ViewerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Silica_ViewerTests.swift; sourceTree = ""; }; 0371996627BACD8700EE1DFD /* ExportAccessoryView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ExportAccessoryView.xib; sourceTree = ""; }; 0371996827BACDE800EE1DFD /* ExportAccessoryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExportAccessoryView.swift; sourceTree = ""; }; + 03A2FE7427CC2EED004CDE91 /* PSDWriter-Mac.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "PSDWriter-Mac.xcodeproj"; path = "Dependencies/PSDWriter/PSDWriter-Mac.xcodeproj"; sourceTree = ""; }; 03C39DE226F90733005555AE /* lzodefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lzodefs.h; sourceTree = ""; }; 03C39DE326F90733005555AE /* COPYING */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = COPYING; sourceTree = ""; }; 03C39DE426F90734005555AE /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; - 03C39DE526F90734005555AE /* testmini.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = testmini.c; sourceTree = ""; }; 03C39DE626F90734005555AE /* minilzo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = minilzo.h; sourceTree = ""; }; 03CB382E2419C9DB0078B3E5 /* libLZO.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libLZO.a; sourceTree = BUILT_PRODUCTS_DIR; }; 03CB383F241A5AED0078B3E5 /* Shared.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Shared.swift; sourceTree = ""; }; @@ -134,6 +141,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 03A2FE7B27CC3034004CDE91 /* libPSDWriter-Mac.a in Frameworks */, 036AFBB8241687680075400A /* ZIPFoundation in Frameworks */, 03CB383B2419CA2D0078B3E5 /* libLZO.a in Frameworks */, ); @@ -178,6 +186,7 @@ 030F6FE52415C5E300A43F01 = { isa = PBXGroup; children = ( + 03A2FE7427CC2EED004CDE91 /* PSDWriter-Mac.xcodeproj */, 0371995827BAC52900EE1DFD /* SilicaViewer.xctestplan */, 0357A94826F9C71E0075D5BC /* LZO */, 035D19F726F0927200B332BE /* SilicaViewer */, @@ -233,7 +242,6 @@ 03C39DE226F90733005555AE /* lzodefs.h */, 03C39DE426F90734005555AE /* Makefile */, 03C39DE626F90734005555AE /* minilzo.h */, - 03C39DE526F90734005555AE /* testmini.c */, ); name = LZO; sourceTree = ""; @@ -276,6 +284,14 @@ path = "Silica ViewerTests"; sourceTree = ""; }; + 03A2FE7527CC2EED004CDE91 /* Products */ = { + isa = PBXGroup; + children = ( + 03A2FE7927CC2EED004CDE91 /* libPSDWriter-Mac.a */, + ); + name = Products; + sourceTree = ""; + }; 03CB383E241A5ACD0078B3E5 /* Shared */ = { isa = PBXGroup; children = ( @@ -442,6 +458,12 @@ ); productRefGroup = 030F6FEF2415C5E300A43F01 /* Products */; projectDirPath = ""; + projectReferences = ( + { + ProductGroup = 03A2FE7527CC2EED004CDE91 /* Products */; + ProjectRef = 03A2FE7427CC2EED004CDE91 /* PSDWriter-Mac.xcodeproj */; + }, + ); projectRoot = ""; targets = ( 030F6FED2415C5E300A43F01 /* SilicaViewer */, @@ -453,6 +475,16 @@ }; /* End PBXProject section */ +/* Begin PBXReferenceProxy section */ + 03A2FE7927CC2EED004CDE91 /* libPSDWriter-Mac.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libPSDWriter-Mac.a"; + remoteRef = 03A2FE7827CC2EED004CDE91 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + /* Begin PBXResourcesBuildPhase section */ 030F6FEC2415C5E300A43F01 /* Resources */ = { isa = PBXResourcesBuildPhase; @@ -534,7 +566,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 03C39DE926F90734005555AE /* testmini.c in Sources */, 03C39DE826F90734005555AE /* Makefile in Sources */, 0357A94D26F9C7370075D5BC /* minilzo.c in Sources */, ); @@ -712,12 +743,17 @@ COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 5; DEVELOPMENT_TEAM = JM5LKVKH48; + HEADER_SEARCH_PATHS = "${PROJECT_DIR}/Dependencies/PSDWriter/Shared"; INFOPLIST_FILE = SilicaViewer/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); MARKETING_VERSION = 1.1; + OTHER_LDFLAGS = ( + "-ObjC", + "-all_load", + ); PRODUCT_BUNDLE_IDENTIFIER = com.redstrate.SilicaViewer; PRODUCT_NAME = "Silica Viewer"; SWIFT_OBJC_BRIDGING_HEADER = "SilicaViewer/SilicaViewer-Bridging-Header.h"; @@ -738,12 +774,17 @@ COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 5; DEVELOPMENT_TEAM = JM5LKVKH48; + HEADER_SEARCH_PATHS = "${PROJECT_DIR}/Dependencies/PSDWriter/Shared"; INFOPLIST_FILE = SilicaViewer/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); MARKETING_VERSION = 1.1; + OTHER_LDFLAGS = ( + "-ObjC", + "-all_load", + ); PRODUCT_BUNDLE_IDENTIFIER = com.redstrate.SilicaViewer; PRODUCT_NAME = "Silica Viewer"; SWIFT_OBJC_BRIDGING_HEADER = "SilicaViewer/SilicaViewer-Bridging-Header.h"; diff --git a/SilicaViewer/AppDelegate.swift b/SilicaViewer/AppDelegate.swift index 0fd0032..e9eb0bb 100644 --- a/SilicaViewer/AppDelegate.swift +++ b/SilicaViewer/AppDelegate.swift @@ -28,17 +28,159 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations { let savePanel = NSSavePanel() savePanel.title = "Save" - savePanel.allowedFileTypes = ["public.png", "public.jpeg"] - savePanel.accessoryView = ExportAccessoryView.fromNib() + savePanel.allowedFileTypes = ["tiff"] + savePanel.nameFieldStringValue = (document?.getIdealFilename())! + + let accessoryView = (ExportAccessoryView.fromNib()! as ExportAccessoryView) + accessoryView.setSavePanel(savePanel) + + savePanel.accessoryView = accessoryView as NSView savePanel.begin { (result) in if result.rawValue == NSApplication.ModalResponse.OK.rawValue { - let canvas = document?.makeComposite() - let canvasTiff = canvas?.tiffRepresentation - let bitmapImage = NSBitmapImageRep(data: canvasTiff!) - let canvasPng = bitmapImage!.representation(using: .png, properties: [:]) - - try? canvasPng?.write(to: savePanel.url!) + if savePanel.allowedFileTypes![0] != "psd" { + var fileType: NSBitmapImageRep.FileType = .tiff + switch(savePanel.allowedFileTypes![0]) { + case "tiff": + fileType = .tiff; + break; + case "bmp": + fileType = .bmp; + break; + case "jpeg": + fileType = .jpeg; + break; + case "png": + fileType = .png; + break; + default: + break; + } + + let canvas = document?.makeComposite() + let canvasTiff = canvas?.tiffRepresentation + let bitmapImage = NSBitmapImageRep(data: canvasTiff!) + let canvasPng = bitmapImage!.representation(using: fileType, properties: [:]) + + try? canvasPng?.write(to: savePanel.url!) + } else { + let writer = PSDWriter(documentSize: (document?.info.cgSize)!) + + let cgImage = document?.makeComposite()?.cgImage(forProposedRect: nil, context: nil, hints: nil) + + let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue).union(.byteOrder32Big) + + let ccgContext = CGContext(data: nil, width: document!.info.width, height: document!.info.height, bitsPerComponent: 8, bytesPerRow: document!.info.width * 4, space: document!.info.colorSpace, bitmapInfo: bitmapInfo.rawValue) + + ccgContext?.setFillColor(document!.info.backgroundColor) + ccgContext?.fill(document!.info.cgRect) + + let context = CIContext() + + writer?.addLayer(with: ccgContext?.makeImage(), andName: "Background", andOpacity: 1.0, andOffset: .zero) + + var masterImage = CIImage(cgImage: cgImage!) + + for layer in document!.info.layers.reversed() { + var test : CGImage? = nil + + masterImage = document!.blendLayer(layer, previousImage: &test) + + let finalCgImage = context.createCGImage(masterImage, from: document!.info.cgRect, format: .RGBA8, colorSpace: document!.info.colorSpace) + + var blendMode: PSDBlendModes = kPSDBlendModeNormal + if layer.data.blendMode == 1 { + blendMode = kPSDBlendModeMultiply + } + if layer.data.blendMode == 10 { + blendMode = kPSDBlendModeColorBurn + } + if layer.data.blendMode == 19 { + blendMode = kPSDBlendModeDarken + } + if layer.data.blendMode == 8 { + blendMode = kPSDBlendModeLinearBurn + } + if layer.data.blendMode == 4 { + blendMode = kPSDBlendModeLighten + } + if layer.data.blendMode == 2 { + blendMode = kPSDBlendModeScreen + } + if layer.data.blendMode == 13 { + //blendMode = kPSDBlendModeHardLight + } + if layer.data.blendMode == 9 { + blendMode = kPSDBlendModeColorDodge + } + if layer.data.blendMode == 3 { + //blendMode = kPSDBlendModeSubtract + } + if layer.data.blendMode == 0 && layer.data.blendMode != layer.data.extendedBlend { + if layer.data.extendedBlend == 25 { + blendMode = kPSDBlendModeDarkerColor + } + if layer.data.extendedBlend == 24 { + //blendMode = kPSDBlendModeLighterColor + } + if layer.data.extendedBlend == 21 { + //blendMode = kPSDBlendModeVividLight + } + if layer.data.extendedBlend == 22 { + //blendMode = kPSdBlendModeLinearLight + } + if layer.data.extendedBlend == 23 { + //blendMode = kPSDBlendModePinLight + } + if layer.data.extendedBlend == 20 { + //blendMode = kPSDBlendModeHardMix + } + if layer.data.extendedBlend == 26 { + //blendMode = kPSDBlendModeDivide + } + } + + if layer.data.blendMode == 11 { + //blendMode = kPSDBlendModeOverlay + } + if layer.data.blendMode == 17 { + //return .softLight + } + if layer.data.blendMode == 12 { + //return .hardLight + } + if layer.data.blendMode == 6 { + //return .difference + } + if layer.data.blendMode == 5 { + //return .exclusion + } + if layer.data.blendMode == 7 { + //return .componentAdd + } + if layer.data.blendMode == 15 { + //return .hue + } + if layer.data.blendMode == 16 { + //return .saturation + } + if layer.data.blendMode == 13 { + //return .color + } + if layer.data.blendMode == 14 { + //return .luminosity + } + + if(layer.mask != nil) { + writer?.addLayer(with: document!.makeBlendImage(layer), andName: layer.name + " (Mask)", andOpacity: 1.0, andOffset: .zero) + } + + writer?.addLayer(with: finalCgImage, andName: layer.name, andOpacity: Float(layer.data.opacity), andOffset: .zero, andBlendMode: Int(blendMode.rawValue), andIsNonBaseLayer: layer.clipped) + } + + let data = writer?.createPSDData() + try? data?.write(to: savePanel.url!) + } } } } @@ -49,6 +191,13 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations { let savePanel = NSSavePanel() savePanel.title = "Save Thumbnail" savePanel.allowedFileTypes = ["public.png"] + savePanel.nameFieldStringValue = (document?.getIdealFilename())! + + let accessoryView = (ExportAccessoryView.fromNib()! as ExportAccessoryView) + accessoryView.setSavePanel(savePanel) + + savePanel.accessoryView = accessoryView as NSView + savePanel.begin { (result) in if result.rawValue == NSApplication.ModalResponse.OK.rawValue { let canvas = document?.makeThumbnail() diff --git a/SilicaViewer/Document.swift b/SilicaViewer/Document.swift index 0b1c89d..2dd374e 100644 --- a/SilicaViewer/Document.swift +++ b/SilicaViewer/Document.swift @@ -441,9 +441,11 @@ class Document: NSDocument { let nameClassKey = dict[NameKey] let nameClassID = getClassID(id: nameClassKey) - let nameString = objectsArray[nameClassID] as! String - - info.name = nameString + let nameString = objectsArray[nameClassID] as! NSString + + if nameString != "$null" { + info.name = nameString as String + } let authorClassKey = dict[AuthorNameKey] let authorClassID = getClassID(id: authorClassKey) @@ -536,6 +538,60 @@ class Document: NSDocument { parseDocument(archive: archive, dict: propertyList as! NSDictionary) } + func makeBlendImage(_ layer: SilicaLayer) -> CGImage { + var maskContext: CGContext? + + if layer.mask != nil { + let grayColorSpace = CGColorSpaceCreateDeviceGray() + let maskBitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue).union(.byteOrder16Big) + + maskContext = CGContext(data: nil, width: info.width, height: info.height, bitsPerComponent: 16, bytesPerRow: 0, space: grayColorSpace, bitmapInfo: maskBitmapInfo.rawValue) + + maskContext?.setFillColor(.white) + maskContext?.fill(info.cgRect) + + for chunk in layer.mask!.chunks { + maskContext?.draw(chunk.image!, in: getChunkRect(chunk)) + } + } + + return (maskContext?.makeImage())! + } + + func blendLayer(_ layer : SilicaLayer, previousImage : inout CGImage?) -> CIImage { + let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue).union(.byteOrder32Big) + + // start by creating a new layer composite image, needed for image masking + let layerContext = CGContext(data: nil, width: info.width, height: info.height, bitsPerComponent: 8, bytesPerRow: info.width * 4, space: info.colorSpace, bitmapInfo: bitmapInfo.rawValue) + + layerContext?.clear(info.cgRect) + + let kernel = getBlendKernel(layer) + + for chunk in layer.data.chunks { + layerContext?.setAlpha(CGFloat(layer.data.opacity)) + layerContext?.setBlendMode(.normal) + + if !layer.data.hidden { + layerContext?.draw(chunk.image!, in: getChunkRect(chunk)) + } + } + + let layerImage = layerContext?.makeImage() + + if layer.clipped && previousImage != nil { + let result = previousImage!.toGrayscale() + let newImage = layerImage!.masking(result!) + + previousImage = newImage + } else { + previousImage = layerImage + } + + // apply image + return kernel!.apply(foreground: CIImage(cgImage: previousImage!), background: CIImage(color: .clear), colorSpace: info.colorSpace)! + } + func makeComposite() -> NSImage? { // create the final composite output image let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue).union(.byteOrder32Big) diff --git a/SilicaViewer/ExportAccessoryView.swift b/SilicaViewer/ExportAccessoryView.swift index c575272..5ddfb2d 100644 --- a/SilicaViewer/ExportAccessoryView.swift +++ b/SilicaViewer/ExportAccessoryView.swift @@ -3,6 +3,35 @@ import AppKit class ExportAccessoryView : NSView { + @IBOutlet weak var typeBox: NSPopUpButton! + + var savePanel: NSSavePanel? = nil + + func setSavePanel(_ savePanel: NSSavePanel?) { + self.savePanel = savePanel + } + + @IBAction func changeFileFormat(_ sender: Any) { + switch(typeBox.indexOfSelectedItem) { + case 0: + savePanel?.allowedFileTypes = ["tiff"] + break + case 1: + savePanel?.allowedFileTypes = ["bmp"] + break + case 2: + savePanel?.allowedFileTypes = ["jpeg"] + break + case 3: + savePanel?.allowedFileTypes = ["png"] + break + case 4: + savePanel?.allowedFileTypes = ["psd"] + break + default: + break + } + } } extension NSView { diff --git a/SilicaViewer/ExportAccessoryView.xib b/SilicaViewer/ExportAccessoryView.xib index 5225ac1..34262b2 100644 --- a/SilicaViewer/ExportAccessoryView.xib +++ b/SilicaViewer/ExportAccessoryView.xib @@ -9,27 +9,44 @@ - - + + - - + + - + + + + + + + + + + - - - + + + + + + + + - + + + + diff --git a/SilicaViewer/SilicaViewer-Bridging-Header.h b/SilicaViewer/SilicaViewer-Bridging-Header.h index 6616edf..878250b 100644 --- a/SilicaViewer/SilicaViewer-Bridging-Header.h +++ b/SilicaViewer/SilicaViewer-Bridging-Header.h @@ -1,5 +1,8 @@ #include #include "minilzo.h" +#include +#include +#include uint32_t valueForKeyedArchiverUID(uint64_t keyedArchiverUID) { void *uid = (void*)keyedArchiverUID;