diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ab0187..72fcc50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,114 +1,123 @@ -# Changelog -## [3.1.4] - 2020-04-09 -### Fixed -- Fix PSD import issues with PSD file without unique layer id -- Fix crash on importing huge PSD files -- Fix metafile not updated when reimporting -- Fix error when importing PSB files with 32-bit color - -### Changed -- Improve PSD file import performance - -## [3.1.3] - 2020-03-20 -### Changed -- Update 2D Animation dependency - -## [3.1.2] - 2020-02-27 -### Fixed -- Fixed broken documentation links in inspectors -- Fixed empty GameObjects created in certain cases - -## [3.1.1] - 2020-01-09 -### Fixed -- Fix wrong dependency version - -## [3.1.0] - 2019-12-16 -### Added -- Expose PSDImporter class to be accessible via scripting -- Added example in manual to show how to set PSDImporter as default importer for PSD files. - -## [3.0.0] - 2019-11-06 -### Changed -- Update version number for Unity 2020.1 -- Update documentation - -## [2.0.6] - 2019-10-18 -### Fixed -- Fixed SpriteRect name clash when Photoshop layer is renamed to the same name as an exisiting user created SpriteRect - -## [2.0.5] - 2019-08-06 -### Fixed -- Physics Shape not saved into Sprite when importing with AssetDatabase V2 - -### Added -- Experimental feature to have Sprites with same name generated from source file -- Support for providing Layer and Group order to Animation Skinning Module - -## [2.0.4] - 2019-08-09 -### Added -- Add related test packages -- Add support Secondary Texture Module in Sprite Editor Window - -### Fixed -- Texture and SpriteLibraryAsset subassets in PSDImporter now follows the main asset's name. - -## [2.0.3] - 2019-07-20 -### Changed -- Update 2D Animation dependency - -## [2.0.2] - 2019-07-13 -### Changed -- Mark package to support Unity 2019.3.0a10 onwards. - -## [2.0.1] - 2019-06-12 -### Changed -- Update 2D Animation dependency - -## [2.0.0] - 2019-06-17 -### Changed -- Remove preview tag -- Remove experimental namespace - -## [1.2.0-preview.2] - 2019-06-07 -### Added -- Change API to internal access -- Only generate Sprite Library Asset if there is entry -- Do not reset Reslice checkbox after Inspector apply - -## [1.2.0-preview.1] - 2019-03-15 -### Added -- Update support for 2019.2 -- Integrate with 2D Animation Sprite Library -- Integrate with new 2D Animation Character Group -- Fix asset name conflict - -## [1.1.0-preview.2] - 2019-04-23 -### Added -- Fix potential name clashing issues with ScriptedImporter -- Fix Prefab asset using wrong name. Note this will break Prefab references if upgrading from previous versions. - -## [1.1.0-preview.1] - 2019-02-19 -### Added -- Update dependency for 2019.1 support - -## [1.0.0-preview.3] - 2019-02-19 -### Added -- Fix compilation error in .NET 3.5 - -## [1.0.0-preview.2] - 2019-01-25 -### Added -- Fix unable to rig Sprites created manually -- Remove legacy packing tag -- Default Texture Type is changed to 'Sprite (2D and UI)' -- Default Sprite Mode is changed to 'Multiple' - -## [1.0.0-preview.1] - 2018-11-20 -### Added -- New release -- ScriptedImporter for importing Adobe Photoshop file -- Supports handling of Adobe Photoshop layers - - Creates Sprites from individual layers - - Handles include or exclude hidden layers -- Supports Prefab generation that reconstruct generated Sprites to original art asset layout - - Prefab generation supports GameObject grouping based on Adobe Photoshop layer grouping -- Supports 2D Animation v2 single character with multiple Sprites workflow +# Changelog + +## [4.0.0] - 2020-05-11 +### Changed +- Version bump for Unity 2020.2 + +## [3.1.4] - 2020-04-09 +### Fixed +- Fix PSD import issues with PSD file without unique layer id +- Fix crash on importing huge PSD files +- Fix metafile not updated when reimporting +- Fix error when importing PSB files with 32-bit color + +### Changed +- Improve PSD file import performance + +## [3.1.3] - 2020-03-20 +### Changed +- Update 2D Animation dependency + +## [4.0.0] - 2020-03-11 +### Changed +- Version bump for Unity 2020.2 + +## [3.1.2] - 2020-02-27 +### Fixed +- Fixed broken documentation links in inspectors +- Fixed empty GameObjects created in certain cases + +## [3.1.1] - 2020-01-09 +### Fixed +- Fix wrong dependency version + +## [3.1.0] - 2019-12-16 +### Added +- Expose PSDImporter class to be accessible via scripting +- Added example in manual to show how to set PSDImporter as default importer for PSD files. + +## [3.0.0] - 2019-11-06 +### Changed +- Update version number for Unity 2020.1 +- Update documentation + +## [2.0.6] - 2019-10-18 +### Fixed +- Fixed SpriteRect name clash when Photoshop layer is renamed to the same name as an exisiting user created SpriteRect + +## [2.0.5] - 2019-08-06 +### Fixed +- Physics Shape not saved into Sprite when importing with AssetDatabase V2 + +### Added +- Experimental feature to have Sprites with same name generated from source file +- Support for providing Layer and Group order to Animation Skinning Module + +## [2.0.4] - 2019-08-09 +### Added +- Add related test packages +- Add support Secondary Texture Module in Sprite Editor Window + +### Fixed +- Texture and SpriteLibraryAsset subassets in PSDImporter now follows the main asset's name. + +## [2.0.3] - 2019-07-20 +### Changed +- Update 2D Animation dependency + +## [2.0.2] - 2019-07-13 +### Changed +- Mark package to support Unity 2019.3.0a10 onwards. + +## [2.0.1] - 2019-06-12 +### Changed +- Update 2D Animation dependency + +## [2.0.0] - 2019-06-17 +### Changed +- Remove preview tag +- Remove experimental namespace + +## [1.2.0-preview.2] - 2019-06-07 +### Added +- Change API to internal access +- Only generate Sprite Library Asset if there is entry +- Do not reset Reslice checkbox after Inspector apply + +## [1.2.0-preview.1] - 2019-03-15 +### Added +- Update support for 2019.2 +- Integrate with 2D Animation Sprite Library +- Integrate with new 2D Animation Character Group +- Fix asset name conflict + +## [1.1.0-preview.2] - 2019-04-23 +### Added +- Fix potential name clashing issues with ScriptedImporter +- Fix Prefab asset using wrong name. Note this will break Prefab references if upgrading from previous versions. + +## [1.1.0-preview.1] - 2019-02-19 +### Added +- Update dependency for 2019.1 support + +## [1.0.0-preview.3] - 2019-02-19 +### Added +- Fix compilation error in .NET 3.5 + +## [1.0.0-preview.2] - 2019-01-25 +### Added +- Fix unable to rig Sprites created manually +- Remove legacy packing tag +- Default Texture Type is changed to 'Sprite (2D and UI)' +- Default Sprite Mode is changed to 'Multiple' + +## [1.0.0-preview.1] - 2018-11-20 +### Added +- New release +- ScriptedImporter for importing Adobe Photoshop file +- Supports handling of Adobe Photoshop layers + - Creates Sprites from individual layers + - Handles include or exclude hidden layers +- Supports Prefab generation that reconstruct generated Sprites to original art asset layout + - Prefab generation supports GameObject grouping based on Adobe Photoshop layer grouping +- Supports 2D Animation v2 single character with multiple Sprites workflow diff --git a/CHANGELOG.md.meta b/CHANGELOG.md.meta index d288b53..6d4519a 100644 --- a/CHANGELOG.md.meta +++ b/CHANGELOG.md.meta @@ -1,7 +1,7 @@ -fileFormatVersion: 2 -guid: 2e891b338ba9c514b871d785976f600e -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 2e891b338ba9c514b871d785976f600e +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Documentation~/PSDImporter.md b/Documentation~/PSDImporter.md index ceb6e5d..bd5d7df 100644 --- a/Documentation~/PSDImporter.md +++ b/Documentation~/PSDImporter.md @@ -1,222 +1,222 @@ -# Summary - -The PSD Importer is an Asset importer that is specialized for importing Adobe Photoshop .psb files into Unity and generating a Prefab made of Sprites based on the source file. The .psb file format is functionally identical to the more common Adobe .psd format and can support much larger images than the .psd format (up to 300,000 by 300,000 pixels in size). - -You can save or convert your Photoshop artwork files into the .psb format and import them into Unity with the PSD Importer. When you import .psb files with the PSD Importer, you can use features such as [Mosaic](#Mosaic) to automatically generate a Sprite sheet from the imported layers; or [Character Rig](#Rig) where Unity reassembles the Sprites of a character as they are arranged in their source files. - -## Non-importable Photoshop effects - -The PSD Importer only supports two [Texture Modes](https://docs.unity3d.com/Manual/TextureTypes.html): [Default](https://docs.unity3d.com/Manual/TextureTypes.html#Default) and [Sprite](https://docs.unity3d.com/Manual/TextureTypes.html#Sprite). Other Texture Modes might be supported in the future. - -The following Photoshop features are not supported by the PSD Importer and it ignores the following layer effects and features while it generates Sprites: - -* Channels - -* Blend Modes - -* Layer Opacity - -* Effects - -You can also add additional Textures to the Sprites with the [Sprite Edito](https://docs.unity3d.com/Manual/SpriteEditor.html)r’s [Secondary Textures](https://docs.unity3d.com/Manual/SpriteEditor-SecondaryTextures.html) module. Shaders can sample these Secondary Textures to apply additional effects to the Sprite, such as normal mapping. For more information, see documentation on [Sprite Editor: Secondary Textures](https://docs.unity3d.com/Manual/SpriteEditor-SecondaryTextures.html). - -## Inspector properties - -After importing a .psb file into your Project, select the Asset file to find the following properties in its Inspector window. - -### Texture Type - Default - -This is the default Texture Type that Unity uses when you import an image without a specific Texture Type selected. For more information, refer to the documentation on [Texture Types](https://docs.unity3d.com/Manual/TextureTypes.html). - -### Texture Type - Sprite (2D and UI) - -![](images/propertysettings.png)
_Importer Inspector properties_ - -Set the Texture Type to __Sprite (2D and UI)__ when you want to import a .psb file with character graphics on multiple layers. The following property settings are available: - -| Property | Function | -| ------------------------------------------------------------ | ------------------------------------------------------------ | -| __Texture Type__ | Select [Sprite (2D and UI)](https://docs.unity3d.com/Manual/TextureTypes.html#Sprite) to import the Texture as a [Sprite](https://docs.unity3d.com/Manual/Sprites.html). This is required to begin using the imported images with the [2D Animation](https://docs.unity3d.com/Packages/com.unity.2d.animation@latest/) package. | -| __Sprite Mode__ | Use this property to specify how Unity extracts the Sprite graphic from the image. The default option is __Multiple__. | -|     Single | Choose this option if the imported image contains a single element. | -|     Multiple | This is the default option. Choose this option if the imported image contains multiple elements. Choose this option when importing artwork meant for animation with the [2D Animation](https://docs.unity3d.com/Packages/com.unity.2d.animation@latest/) package. | -| __Pixels Per Unit__ | The number of pixels that equal to one Unity unit. | -| __Mesh Type__ | This defines the __Mesh__ type that Unity generates for the __Sprite__. This is set to __Tight__ by default. | -|     [Full Rect](https://docs.unity3d.com/Documentation/ScriptReference/SpriteMeshType.FullRect.html) | Unity maps the Sprite onto a rectangular Mesh. | -|     [Tight](https://docs.unity3d.com/Documentation/ScriptReference/SpriteMeshType.Tight.html) | Unity generates a Mesh based on the outline of the Sprite. If the Sprite is smaller than 32 x 32 pixels, Unity always maps it onto a __Full Rect__ quad Mesh, even if you select __Tight__. | -| [__Extrude Edges__](https://docs.unity3d.com/Manual/Glossary.html#ExtrudeEdges) | Use the slider to determine how much to extend the Mesh from the edge of the Sprite. | -| __Import Hidden__ | Enable this property to include the hidden [layers](https://helpx.adobe.com/photoshop/using/layer-basics.html#layers_panel_overview) of the .psb file in the import. This produces the same import result as making all layers visible in the source file unhiding all layers in the source file before you importing it into Unity. Clear this option if you want to only import the visible layers in the .psb file. | -| __Mosaic__ | This setting is only available if you set the __Texture Type__ to __Multiple__. Enable this setting to make the PSD Importer generate Sprites from the imported layers and combine them into a single Texture in a Sprite sheet layout. | -| [__Character Rig__](#Rig) | Enable this property to make the importer generate a [Prefab](https://docs.unity3d.com/Manual/Prefabs.html) based on the imported source file. The PSD Importer generates Sprites from the imported layers of the source file, and the Sprites’ [hierarchy](https://docs.unity3d.com/Manual/Hierarchy.html) and positions are based on their [layer hierarchy](https://helpx.adobe.com/photoshop/using/layer-basics.html#layers_panel_overview) and their positions in the .psb file. | -| __Use Layer Grouping__ | This setting is only available when you enable __Character Rig__. Enable this setting to make the importer generate a Prefab that follows the layer and grouping hierarchy of the imported .psb. file. | -| __Pivot__ | Choose the pivot point of the Sprite. | -|      Custom | Define the X and Y coordinates of a custom __Pivot__ location. | -| [__Reslice__](#Reslice) | Available only when you enable __Mosaic__. Enable this setting to regenerate the Sprite from the imported layers and clear any changes you have made to the Sprite and its metadata. | -| __Experimental__ | The following feature is experimental and might be changed or removed in the future. It is only available for the following Editor and package versions:
- __Unity 2019.2__: 2D PSD Importer version 1.2.0-preview.4 or newer.
- __Unity 2019.3__: 2D PSD Importer version 2.0.5 or newer. | -|      [Keep Duplicate Name](#Duplicate) | Enable this setting to make the PSD Importer generate Sprites from the source files with the exact same name as their source layers, even when there are multiple layers with the same name. | - - - -## Property details - -### Character Rig - -The __Character Rig__ setting makes the PSD Importer generate a Prefab that contains [Sprites](https://docs.unity3d.com/Manual/Sprites.html) it generates from each layer of the imported source file. The PSD Importer automatically gives the Sprites an [Order in Layer](https://docs.unity3d.com/Manual/2DSorting.html#sortlayer) value that sorts them according to the layer hierarchy in the source file. This ensures that Unity recreates the character artwork in the correct order in the Prefab. - -The name of each Sprite in the Prefab is the same as their respective source layer, unless a [name collision error](#NameCollision) occurs, which is usually due to duplicate names in the source layers. - -If the Sprite contains bone or weight data, the PSD Importer automatically adds the __Sprite Skin__ component to it. This happens if the Sprite has been [rigged](https://docs.unity3d.com/Packages/com.unity.2d.animation@3.0/manual/CharacterRig.html) with bones and weights in the [Skinning Editor](https://docs.unity3d.com/Packages/com.unity.2d.animation@3.0/manual/SkinningEditor.html) already and the source file is being reimported, or you have manually [copied and pasted](https://docs.unity3d.com/Packages/com.unity.2d.animation@3.0/manual/CopyPasteSkele.html) the bone and weight data onto the Sprites. - -Refer to the examples below of a character designed in Photoshop with its various parts and limbs separated onto different layers. - -![](images/PhotoshopSetup.png)
_Character artwork in Photoshop with different parts separated into different Photoshop layers._ - -![](images/LayerHierarchy.png)
_The generated Prefab with Sprites sorted according to the source file’s layer hierarchy._ - -![](images/LayerGrouping.png)
_The Prefab with the Layer Grouping setting enabled._ - -### Reslice - -Enable this setting to discard all user modifications for the current set of SpriteRect data and regenerate all SpriteRects based on the current source file. Extra SpriteRect metadata (such as weights and bones data) persist if they remain valid with the regenerated SpriteRects. - - - -## How the PSD Importer uses SpriteRect data - -The PSD Importer can store four separate sets of [SpriteRect](https://docs.unity3d.com/ScriptReference/Sprite-rect.html) data, with a set for each of the four combinations of importer property settings below: - -1. __Sprite Mode__ set to __Single__. - -2. __Sprite Mode__ set to __Multiple__. - -3. __Sprite Mode__ set to __Multiple,__ and __Mosaic__ enabled. - -4. __Sprite Mode__ set to __Multiple__, and both __Mosaic__ and __Character Rig__ enabled. - -Each set of data is persistent, and does not affect or overwrite the data of other sets. This means you can save different SpriteRect data for different importer settings for the same source file. The SpriteRect data persists even if you modify the dimensions and position of images in the source file, as long as the original [Layer ID](https://github.com/adobe-photoshop/generator-core/wiki/Understanding-Layer-IDs-and-Layer-Indices) of the source layers remain the same. - - - -### Modifying the SpriteRect data - -The SpriteRect defines the location of the Sprite on the Texture that Unity generates from the imported source file. You can modify the location and size of each SpriteRect in the Sprite Editor. - -![](images/SpriteRect1.png)
_Original SpriteRect location of the ‘head’ Sprite on the combined Sprite sheet Texture._ - -![](images/SpriteRect2.png)
_Drag the corners of the SpriteRect to modify its dimensions and location, or enter the coordinates and dimensions in the Sprite panel._ - -A SpriteRect’s modified dimensions and location on the Texture is reflected for its respective Sprite in the Scene view. - -| ![](images/SpriteRect_table1.png) | ![](images/SpriteRect_table2.png) | -| ------------------------------------------------------------ | ------------------------------------------------------------ | -| _Original character prefab and its ‘head’ Sprite with unmodified SpriteRect data._ | _Character prefab with its ‘head’ Sprite’s SpriteRect data modified._ | - - -When you enable the [Mosaic](#Mosaic) importer setting, the PSD Importer arranges the different layers of the source file together to form a single combined Texture when you import it. The importer generates a SpriteRect for each of these imported layers, and follows the position of its associated layer wherever it is placed in the Mosaic Texture. - -![](images/MovedSpriteRect.png)
_The SpriteRect of the ‘head’ layer. The SpriteRect has been moved from its original position._ - -![](images/SpriteRect_following.png)
_The source file reimported after hiding several layers. The SpriteRect follows the ‘head’ layer’s placement in the new Texture._ - -However, a SpriteRect’s size and position remains the same if you change the image or canvas size of its source layer in the source file. You must manually edit the size and position of the SpriteRect in the Sprite Editor, or select and apply the [Reslice](#heading=h.i7pxu2xdxrji) option to regenerate it from the source file. - -![](images/OriginalSpriteRect.png)
_Original position and size of the SpriteRect for the generated ‘head’ Sprite._ - -![image alt text](images/IncreaseSize.png)
_Position and size of the SpriteRect remains the same after increasing the image size of its source layer._ - -SpriteRect data persists until you manually delete the SpriteRect, or select the [Reslice](#heading=h.i7pxu2xdxrji) option and apply it in the importer settings. When you do this, Unity discards all user modifications for the current set of SpriteRect data and regenerates all the SpriteRects from the current source file. - -### Summary of source file modifications and their effects on SpriteRect data - -| __Modification to the source file__ | __Effect on SpriteRect data__ | -| ----------------------------------------------- | ------------------------------------------------------------ | -| __New layer added /layer visibility turned on__ | The PSD importer automatically generates a new Sprite from the new layer, or newly visible layer, with its associated SpriteRect. | -| __Layer deleted /layer visibility turned off__ | The Sprite and SpriteRect that the PSD Importer generated from the deleted or previously visible layer are also deleted from the Project file. | -| __Layer is renamed__ | By default, the SpriteRect copies the new name of its source layer. However if you rename the SpriteRect in the Sprite Editor, then it retains its modified name and does not copy the source layer’s new name. | -| __Layer or canvas size changed__ | When a source layer is resized, the size and position of its related SpriteRect remains the same and does not reflect the changes made to its source layer. To make the SpriteRect reflect the changes made to its source layer, manually edit the SpriteRect’s dimensions in the Sprite Editor or select and apply the [Reslice](#Reslice) option in the PSD Importer settings. | - - - -## Name collision errors - -A name collision error can happen due to the following : - -1. Two or more layers in the imported source file have the same name. However, Photoshop [group layers](https://helpx.adobe.com/photoshop/using/selecting-grouping-linking-layers.html#group_and_link_layers) with the same names do not cause this issue. - -2. A new layer that the PSD Importer creates in the source file has the same name as a SpriteRect you have created or modified. - -3. A layer is renamed to the same name as a SpriteRect you have modified. - -4. A previously hidden layer is made visible and imported, and it has the same name as an existing SpriteRect. - -When a name collision occurs, one SpriteRect retains the original name while the other is appended with a running number. Which SpriteRect retains their original name is based on the following priority: - -1. A SpriteRect you have created or modified. - -2. The first layer in the source file, starting from the bottom of the layer stack. - -3. Currently existing SpriteRects in the Project. - -## Experimental feature: Keep duplicate names - -Unity’s default import behavior when there are duplicate names is to append "_[number]" to Sprites and SpriteRects it generates from source layers with identical names. Enable this experimental feature to instead have Unity give both Sprites/SpriteRects the exact same name as their source layer even if they have duplicate names. - - -## PSD File Importer Override - -In Unity 2019.30f1, it is possible to use PSDImporter to import files with 'psd' extensions. -To do that you will need to have custom scripts that allows you to do that by calling the `AssetDatabaseExperimental.SetImporterOverride` method. -The following is an example on how to use the API - -#### PSDImporterOverride.cs -``` -using System.IO; -using UnityEditor.Experimental; -using UnityEditor.Experimental.AssetImporters; -using UnityEngine; - -namespace UnityEditor.U2D.PSD -{ - [ScriptedImporter(1, "psd", AutoSelect = false)] - internal class PSDImporterOverride : PSDImporter - { - - [MenuItem("Assets/2D Importer", false, 30)] - [MenuItem("Assets/2D Importer/Change PSD File Importer", false, 30)] - static void ChangeImporter() - { - foreach (var obj in Selection.objects) - { - var path = AssetDatabase.GetAssetPath(obj); - var ext = System.IO.Path.GetExtension(path); - if (ext == ".psd") - { - var importer = AssetImporter.GetAtPath(path); - if (importer is PSDImporterOverride) - { - Debug.Log(string.Format("{0} is now imported with TextureImporter", path)); - AssetDatabaseExperimental.ClearImporterOverride(path); - } - else - { - Debug.Log(string.Format("{0} is now imported with PSDImporter", path)); - AssetDatabaseExperimental.SetImporterOverride(path); - } - } - } - } - } -} -``` - -#### PSDImporterOverrideEditor.cs -``` -namespace UnityEditor.U2D.PSD -{ - [CustomEditor(typeof(UnityEditor.U2D.PSD.PSDImporterOverride))] - internal class PSDImporterOverrideEditor : PSDImporterEditor - { - } - -} +# Summary + +The PSD Importer is an Asset importer that is specialized for importing Adobe Photoshop .psb files into Unity and generating a Prefab made of Sprites based on the source file. The .psb file format is functionally identical to the more common Adobe .psd format and can support much larger images than the .psd format (up to 300,000 by 300,000 pixels in size). + +You can save or convert your Photoshop artwork files into the .psb format and import them into Unity with the PSD Importer. When you import .psb files with the PSD Importer, you can use features such as [Mosaic](#Mosaic) to automatically generate a Sprite sheet from the imported layers; or [Character Rig](#Rig) where Unity reassembles the Sprites of a character as they are arranged in their source files. + +## Non-importable Photoshop effects + +The PSD Importer only supports two [Texture Modes](https://docs.unity3d.com/Manual/TextureTypes.html): [Default](https://docs.unity3d.com/Manual/TextureTypes.html#Default) and [Sprite](https://docs.unity3d.com/Manual/TextureTypes.html#Sprite). Other Texture Modes might be supported in the future. + +The following Photoshop features are not supported by the PSD Importer and it ignores the following layer effects and features while it generates Sprites: + +* Channels + +* Blend Modes + +* Layer Opacity + +* Effects + +You can also add additional Textures to the Sprites with the [Sprite Edito](https://docs.unity3d.com/Manual/SpriteEditor.html)r’s [Secondary Textures](https://docs.unity3d.com/Manual/SpriteEditor-SecondaryTextures.html) module. Shaders can sample these Secondary Textures to apply additional effects to the Sprite, such as normal mapping. For more information, see documentation on [Sprite Editor: Secondary Textures](https://docs.unity3d.com/Manual/SpriteEditor-SecondaryTextures.html). + +## Inspector properties + +After importing a .psb file into your Project, select the Asset file to find the following properties in its Inspector window. + +### Texture Type - Default + +This is the default Texture Type that Unity uses when you import an image without a specific Texture Type selected. For more information, refer to the documentation on [Texture Types](https://docs.unity3d.com/Manual/TextureTypes.html). + +### Texture Type - Sprite (2D and UI) + +![](images/propertysettings.png)
_Importer Inspector properties_ + +Set the Texture Type to __Sprite (2D and UI)__ when you want to import a .psb file with character graphics on multiple layers. The following property settings are available: + +| Property | Function | +| ------------------------------------------------------------ | ------------------------------------------------------------ | +| __Texture Type__ | Select [Sprite (2D and UI)](https://docs.unity3d.com/Manual/TextureTypes.html#Sprite) to import the Texture as a [Sprite](https://docs.unity3d.com/Manual/Sprites.html). This is required to begin using the imported images with the [2D Animation](https://docs.unity3d.com/Packages/com.unity.2d.animation@latest/) package. | +| __Sprite Mode__ | Use this property to specify how Unity extracts the Sprite graphic from the image. The default option is __Multiple__. | +|     Single | Choose this option if the imported image contains a single element. | +|     Multiple | This is the default option. Choose this option if the imported image contains multiple elements. Choose this option when importing artwork meant for animation with the [2D Animation](https://docs.unity3d.com/Packages/com.unity.2d.animation@latest/) package. | +| __Pixels Per Unit__ | The number of pixels that equal to one Unity unit. | +| __Mesh Type__ | This defines the __Mesh__ type that Unity generates for the __Sprite__. This is set to __Tight__ by default. | +|     [Full Rect](https://docs.unity3d.com/Documentation/ScriptReference/SpriteMeshType.FullRect.html) | Unity maps the Sprite onto a rectangular Mesh. | +|     [Tight](https://docs.unity3d.com/Documentation/ScriptReference/SpriteMeshType.Tight.html) | Unity generates a Mesh based on the outline of the Sprite. If the Sprite is smaller than 32 x 32 pixels, Unity always maps it onto a __Full Rect__ quad Mesh, even if you select __Tight__. | +| [__Extrude Edges__](https://docs.unity3d.com/Manual/Glossary.html#ExtrudeEdges) | Use the slider to determine how much to extend the Mesh from the edge of the Sprite. | +| __Import Hidden__ | Enable this property to include the hidden [layers](https://helpx.adobe.com/photoshop/using/layer-basics.html#layers_panel_overview) of the .psb file in the import. This produces the same import result as making all layers visible in the source file unhiding all layers in the source file before you importing it into Unity. Clear this option if you want to only import the visible layers in the .psb file. | +| __Mosaic__ | This setting is only available if you set the __Texture Type__ to __Multiple__. Enable this setting to make the PSD Importer generate Sprites from the imported layers and combine them into a single Texture in a Sprite sheet layout. | +| [__Character Rig__](#Rig) | Enable this property to make the importer generate a [Prefab](https://docs.unity3d.com/Manual/Prefabs.html) based on the imported source file. The PSD Importer generates Sprites from the imported layers of the source file, and the Sprites’ [hierarchy](https://docs.unity3d.com/Manual/Hierarchy.html) and positions are based on their [layer hierarchy](https://helpx.adobe.com/photoshop/using/layer-basics.html#layers_panel_overview) and their positions in the .psb file. | +| __Use Layer Grouping__ | This setting is only available when you enable __Character Rig__. Enable this setting to make the importer generate a Prefab that follows the layer and grouping hierarchy of the imported .psb. file. | +| __Pivot__ | Choose the pivot point of the Sprite. | +|      Custom | Define the X and Y coordinates of a custom __Pivot__ location. | +| [__Reslice__](#Reslice) | Available only when you enable __Mosaic__. Enable this setting to regenerate the Sprite from the imported layers and clear any changes you have made to the Sprite and its metadata. | +| __Experimental__ | The following feature is experimental and might be changed or removed in the future. It is only available for the following Editor and package versions:
- __Unity 2019.2__: 2D PSD Importer version 1.2.0-preview.4 or newer.
- __Unity 2019.3__: 2D PSD Importer version 2.0.5 or newer. | +|      [Keep Duplicate Name](#Duplicate) | Enable this setting to make the PSD Importer generate Sprites from the source files with the exact same name as their source layers, even when there are multiple layers with the same name. | + + + +## Property details + +### Character Rig + +The __Character Rig__ setting makes the PSD Importer generate a Prefab that contains [Sprites](https://docs.unity3d.com/Manual/Sprites.html) it generates from each layer of the imported source file. The PSD Importer automatically gives the Sprites an [Order in Layer](https://docs.unity3d.com/Manual/2DSorting.html#sortlayer) value that sorts them according to the layer hierarchy in the source file. This ensures that Unity recreates the character artwork in the correct order in the Prefab. + +The name of each Sprite in the Prefab is the same as their respective source layer, unless a [name collision error](#NameCollision) occurs, which is usually due to duplicate names in the source layers. + +If the Sprite contains bone or weight data, the PSD Importer automatically adds the __Sprite Skin__ component to it. This happens if the Sprite has been [rigged](https://docs.unity3d.com/Packages/com.unity.2d.animation@3.0/manual/CharacterRig.html) with bones and weights in the [Skinning Editor](https://docs.unity3d.com/Packages/com.unity.2d.animation@3.0/manual/SkinningEditor.html) already and the source file is being reimported, or you have manually [copied and pasted](https://docs.unity3d.com/Packages/com.unity.2d.animation@3.0/manual/CopyPasteSkele.html) the bone and weight data onto the Sprites. + +Refer to the examples below of a character designed in Photoshop with its various parts and limbs separated onto different layers. + +![](images/PhotoshopSetup.png)
_Character artwork in Photoshop with different parts separated into different Photoshop layers._ + +![](images/LayerHierarchy.png)
_The generated Prefab with Sprites sorted according to the source file’s layer hierarchy._ + +![](images/LayerGrouping.png)
_The Prefab with the Layer Grouping setting enabled._ + +### Reslice + +Enable this setting to discard all user modifications for the current set of SpriteRect data and regenerate all SpriteRects based on the current source file. Extra SpriteRect metadata (such as weights and bones data) persist if they remain valid with the regenerated SpriteRects. + + + +## How the PSD Importer uses SpriteRect data + +The PSD Importer can store four separate sets of [SpriteRect](https://docs.unity3d.com/ScriptReference/Sprite-rect.html) data, with a set for each of the four combinations of importer property settings below: + +1. __Sprite Mode__ set to __Single__. + +2. __Sprite Mode__ set to __Multiple__. + +3. __Sprite Mode__ set to __Multiple,__ and __Mosaic__ enabled. + +4. __Sprite Mode__ set to __Multiple__, and both __Mosaic__ and __Character Rig__ enabled. + +Each set of data is persistent, and does not affect or overwrite the data of other sets. This means you can save different SpriteRect data for different importer settings for the same source file. The SpriteRect data persists even if you modify the dimensions and position of images in the source file, as long as the original [Layer ID](https://github.com/adobe-photoshop/generator-core/wiki/Understanding-Layer-IDs-and-Layer-Indices) of the source layers remain the same. + + + +### Modifying the SpriteRect data + +The SpriteRect defines the location of the Sprite on the Texture that Unity generates from the imported source file. You can modify the location and size of each SpriteRect in the Sprite Editor. + +![](images/SpriteRect1.png)
_Original SpriteRect location of the ‘head’ Sprite on the combined Sprite sheet Texture._ + +![](images/SpriteRect2.png)
_Drag the corners of the SpriteRect to modify its dimensions and location, or enter the coordinates and dimensions in the Sprite panel._ + +A SpriteRect’s modified dimensions and location on the Texture is reflected for its respective Sprite in the Scene view. + +| ![](images/SpriteRect_table1.png) | ![](images/SpriteRect_table2.png) | +| ------------------------------------------------------------ | ------------------------------------------------------------ | +| _Original character prefab and its ‘head’ Sprite with unmodified SpriteRect data._ | _Character prefab with its ‘head’ Sprite’s SpriteRect data modified._ | + + +When you enable the [Mosaic](#Mosaic) importer setting, the PSD Importer arranges the different layers of the source file together to form a single combined Texture when you import it. The importer generates a SpriteRect for each of these imported layers, and follows the position of its associated layer wherever it is placed in the Mosaic Texture. + +![](images/MovedSpriteRect.png)
_The SpriteRect of the ‘head’ layer. The SpriteRect has been moved from its original position._ + +![](images/SpriteRect_following.png)
_The source file reimported after hiding several layers. The SpriteRect follows the ‘head’ layer’s placement in the new Texture._ + +However, a SpriteRect’s size and position remains the same if you change the image or canvas size of its source layer in the source file. You must manually edit the size and position of the SpriteRect in the Sprite Editor, or select and apply the [Reslice](#heading=h.i7pxu2xdxrji) option to regenerate it from the source file. + +![](images/OriginalSpriteRect.png)
_Original position and size of the SpriteRect for the generated ‘head’ Sprite._ + +![image alt text](images/IncreaseSize.png)
_Position and size of the SpriteRect remains the same after increasing the image size of its source layer._ + +SpriteRect data persists until you manually delete the SpriteRect, or select the [Reslice](#heading=h.i7pxu2xdxrji) option and apply it in the importer settings. When you do this, Unity discards all user modifications for the current set of SpriteRect data and regenerates all the SpriteRects from the current source file. + +### Summary of source file modifications and their effects on SpriteRect data + +| __Modification to the source file__ | __Effect on SpriteRect data__ | +| ----------------------------------------------- | ------------------------------------------------------------ | +| __New layer added /layer visibility turned on__ | The PSD importer automatically generates a new Sprite from the new layer, or newly visible layer, with its associated SpriteRect. | +| __Layer deleted /layer visibility turned off__ | The Sprite and SpriteRect that the PSD Importer generated from the deleted or previously visible layer are also deleted from the Project file. | +| __Layer is renamed__ | By default, the SpriteRect copies the new name of its source layer. However if you rename the SpriteRect in the Sprite Editor, then it retains its modified name and does not copy the source layer’s new name. | +| __Layer or canvas size changed__ | When a source layer is resized, the size and position of its related SpriteRect remains the same and does not reflect the changes made to its source layer. To make the SpriteRect reflect the changes made to its source layer, manually edit the SpriteRect’s dimensions in the Sprite Editor or select and apply the [Reslice](#Reslice) option in the PSD Importer settings. | + + + +## Name collision errors + +A name collision error can happen due to the following : + +1. Two or more layers in the imported source file have the same name. However, Photoshop [group layers](https://helpx.adobe.com/photoshop/using/selecting-grouping-linking-layers.html#group_and_link_layers) with the same names do not cause this issue. + +2. A new layer that the PSD Importer creates in the source file has the same name as a SpriteRect you have created or modified. + +3. A layer is renamed to the same name as a SpriteRect you have modified. + +4. A previously hidden layer is made visible and imported, and it has the same name as an existing SpriteRect. + +When a name collision occurs, one SpriteRect retains the original name while the other is appended with a running number. Which SpriteRect retains their original name is based on the following priority: + +1. A SpriteRect you have created or modified. + +2. The first layer in the source file, starting from the bottom of the layer stack. + +3. Currently existing SpriteRects in the Project. + +## Experimental feature: Keep duplicate names + +Unity’s default import behavior when there are duplicate names is to append "_[number]" to Sprites and SpriteRects it generates from source layers with identical names. Enable this experimental feature to instead have Unity give both Sprites/SpriteRects the exact same name as their source layer even if they have duplicate names. + + +## PSD File Importer Override + +In Unity 2019.30f1, it is possible to use PSDImporter to import files with 'psd' extensions. +To do that you will need to have custom scripts that allows you to do that by calling the `AssetDatabaseExperimental.SetImporterOverride` method. +The following is an example on how to use the API + +#### PSDImporterOverride.cs +``` +using System.IO; +using UnityEditor.Experimental; +using UnityEditor.Experimental.AssetImporters; +using UnityEngine; + +namespace UnityEditor.U2D.PSD +{ + [ScriptedImporter(1, "psd", AutoSelect = false)] + internal class PSDImporterOverride : PSDImporter + { + + [MenuItem("Assets/2D Importer", false, 30)] + [MenuItem("Assets/2D Importer/Change PSD File Importer", false, 30)] + static void ChangeImporter() + { + foreach (var obj in Selection.objects) + { + var path = AssetDatabase.GetAssetPath(obj); + var ext = System.IO.Path.GetExtension(path); + if (ext == ".psd") + { + var importer = AssetImporter.GetAtPath(path); + if (importer is PSDImporterOverride) + { + Debug.Log(string.Format("{0} is now imported with TextureImporter", path)); + AssetDatabaseExperimental.ClearImporterOverride(path); + } + else + { + Debug.Log(string.Format("{0} is now imported with PSDImporter", path)); + AssetDatabaseExperimental.SetImporterOverride(path); + } + } + } + } + } +} +``` + +#### PSDImporterOverrideEditor.cs +``` +namespace UnityEditor.U2D.PSD +{ + [CustomEditor(typeof(UnityEditor.U2D.PSD.PSDImporterOverride))] + internal class PSDImporterOverrideEditor : PSDImporterEditor + { + } + +} ``` \ No newline at end of file diff --git a/Editor.meta b/Editor.meta index 8f026e5..9486471 100644 --- a/Editor.meta +++ b/Editor.meta @@ -1,8 +1,8 @@ -fileFormatVersion: 2 -guid: 23888dc58bcb0814389c9fd915521b77 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 23888dc58bcb0814389c9fd915521b77 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Analytics.cs b/Editor/Analytics.cs index 0ee3ff0..015c2f4 100644 --- a/Editor/Analytics.cs +++ b/Editor/Analytics.cs @@ -1,64 +1,64 @@ -using System; -using PhotoshopFile; -using UnityEngine; -using UnityEngine.Analytics; - -namespace UnityEditor.U2D.PSD -{ - [Serializable] - internal struct PSDApplyEvent - { - public int instance_id; - public int texture_type; - public int sprite_mode; - public bool mosaic_layer; - public bool import_hidden_layer; - public bool character_mode; - public bool generate_go_hierarchy; - public bool reslice_from_layer; - public bool is_character_rigged; - public SpriteAlignment character_alignment; - public bool is_psd; - public PsdColorMode color_mode; - - } - - internal interface IAnalytics - { - AnalyticsResult SendApplyEvent(PSDApplyEvent evt); - } - - internal static class AnalyticFactory - { - static IAnalytics s_Analytics; - static public IAnalytics analytics - { - get - { - if (s_Analytics == null) - s_Analytics = new Analytics(); - return s_Analytics; - } - set { s_Analytics = value; } - } - } - - [InitializeOnLoad] - internal class Analytics : IAnalytics - { - const int k_MaxEventsPerHour = 100; - const int k_MaxNumberOfElements = 1000; - const string k_VendorKey = "unity.2d.psdimporter"; - const int k_Version = 1; - - static Analytics() - { - EditorAnalytics.RegisterEventWithLimit("psdImporterApply", k_MaxEventsPerHour, k_MaxNumberOfElements, k_VendorKey, k_Version); - } - - public AnalyticsResult SendApplyEvent(PSDApplyEvent evt) - { - return EditorAnalytics.SendEventWithLimit("psdImporterApply", evt, k_Version); - } - } -} +using System; +using PhotoshopFile; +using UnityEngine; +using UnityEngine.Analytics; + +namespace UnityEditor.U2D.PSD +{ + [Serializable] + internal struct PSDApplyEvent + { + public int instance_id; + public int texture_type; + public int sprite_mode; + public bool mosaic_layer; + public bool import_hidden_layer; + public bool character_mode; + public bool generate_go_hierarchy; + public bool reslice_from_layer; + public bool is_character_rigged; + public SpriteAlignment character_alignment; + public bool is_psd; + public PsdColorMode color_mode; + + } + + internal interface IAnalytics + { + AnalyticsResult SendApplyEvent(PSDApplyEvent evt); + } + + internal static class AnalyticFactory + { + static IAnalytics s_Analytics; + static public IAnalytics analytics + { + get + { + if (s_Analytics == null) + s_Analytics = new Analytics(); + return s_Analytics; + } + set { s_Analytics = value; } + } + } + + [InitializeOnLoad] + internal class Analytics : IAnalytics + { + const int k_MaxEventsPerHour = 100; + const int k_MaxNumberOfElements = 1000; + const string k_VendorKey = "unity.2d.psdimporter"; + const int k_Version = 1; + + static Analytics() + { + EditorAnalytics.RegisterEventWithLimit("psdImporterApply", k_MaxEventsPerHour, k_MaxNumberOfElements, k_VendorKey, k_Version); + } + + public AnalyticsResult SendApplyEvent(PSDApplyEvent evt) + { + return EditorAnalytics.SendEventWithLimit("psdImporterApply", evt, k_Version); + } + } +} diff --git a/Editor/Analytics.cs.meta b/Editor/Analytics.cs.meta index 746b657..42d8343 100644 --- a/Editor/Analytics.cs.meta +++ b/Editor/Analytics.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 9c2f00f81f6586446909cd337be9a6c7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 9c2f00f81f6586446909cd337be9a6c7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/AssemblyInfo.cs b/Editor/AssemblyInfo.cs index 9b1adea..4061cce 100644 --- a/Editor/AssemblyInfo.cs +++ b/Editor/AssemblyInfo.cs @@ -1,2 +1,2 @@ -using System.Runtime.CompilerServices; -[assembly: InternalsVisibleTo("Unity.2D.Psdimporter.Tests.EditorTests")] +using System.Runtime.CompilerServices; +[assembly: InternalsVisibleTo("Unity.2D.Psdimporter.Tests.EditorTests")] diff --git a/Editor/AssemblyInfo.cs.meta b/Editor/AssemblyInfo.cs.meta index 9ff8a2f..ed3981f 100644 --- a/Editor/AssemblyInfo.cs.meta +++ b/Editor/AssemblyInfo.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 3073eb37881ce394f83060fd73c2d98d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 3073eb37881ce394f83060fd73c2d98d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDImportPostProcessor.cs b/Editor/PSDImportPostProcessor.cs index 0bfb1e4..3726445 100644 --- a/Editor/PSDImportPostProcessor.cs +++ b/Editor/PSDImportPostProcessor.cs @@ -1,48 +1,72 @@ -using System.Collections.Generic; -using System.Linq; -using UnityEditor.U2D; -using UnityEditor.U2D.Sprites; -using UnityEngine; - -namespace UnityEditor.U2D.PSD -{ - internal class PSDImportPostProcessor : AssetPostprocessor - { - void OnPostprocessSprites(Texture2D texture, Sprite[] sprites) - { - var dataProviderFactories = new SpriteDataProviderFactories(); - dataProviderFactories.Init(); - ISpriteEditorDataProvider importer = dataProviderFactories.GetSpriteEditorDataProviderFromObject(AssetImporter.GetAtPath(assetPath)); - if (importer != null) - { - importer.InitSpriteEditorDataProvider(); - var physicsOutlineDataProvider = importer.GetDataProvider(); - var textureDataProvider = importer.GetDataProvider(); - int actualWidth = 0, actualHeight = 0; - textureDataProvider.GetTextureActualWidthAndHeight(out actualWidth, out actualHeight); - float definitionScaleW = (float)texture.width / actualWidth; - float definitionScaleH = (float)texture.height / actualHeight; - float definitionScale = Mathf.Min(definitionScaleW, definitionScaleH); - foreach (var sprite in sprites) - { - var guid = sprite.GetSpriteID(); - var outline = physicsOutlineDataProvider.GetOutlines(guid); - var outlineOffset = sprite.rect.size / 2; - if (outline != null && outline.Count > 0) - { - var convertedOutline = new Vector2[outline.Count][]; - for (int i = 0; i < outline.Count; ++i) - { - convertedOutline[i] = new Vector2[outline[i].Length]; - for (int j = 0; j < outline[i].Length; ++j) - { - convertedOutline[i][j] = outline[i][j] * definitionScale + outlineOffset; - } - } - sprite.OverridePhysicsShape(convertedOutline); - } - } - } - } - } -} +using System.Collections.Generic; +using System.Linq; +using UnityEditor.U2D; +using UnityEditor.U2D.Sprites; +using UnityEngine; + +namespace UnityEditor.U2D.PSD +{ + internal class PSDImportPostProcessor : AssetPostprocessor + { + private static string s_CurrentApplyAssetPath = null; + + void OnPostprocessSprites(Texture2D texture, Sprite[] sprites) + { + var dataProviderFactories = new SpriteDataProviderFactories(); + dataProviderFactories.Init(); + ISpriteEditorDataProvider importer = dataProviderFactories.GetSpriteEditorDataProviderFromObject(AssetImporter.GetAtPath(assetPath)); + if (importer != null) + { + importer.InitSpriteEditorDataProvider(); + var physicsOutlineDataProvider = importer.GetDataProvider(); + var textureDataProvider = importer.GetDataProvider(); + int actualWidth = 0, actualHeight = 0; + textureDataProvider.GetTextureActualWidthAndHeight(out actualWidth, out actualHeight); + float definitionScaleW = (float)texture.width / actualWidth; + float definitionScaleH = (float)texture.height / actualHeight; + float definitionScale = Mathf.Min(definitionScaleW, definitionScaleH); + foreach (var sprite in sprites) + { + var guid = sprite.GetSpriteID(); + var outline = physicsOutlineDataProvider.GetOutlines(guid); + var outlineOffset = sprite.rect.size / 2; + if (outline != null && outline.Count > 0) + { + var convertedOutline = new Vector2[outline.Count][]; + for (int i = 0; i < outline.Count; ++i) + { + convertedOutline[i] = new Vector2[outline[i].Length]; + for (int j = 0; j < outline[i].Length; ++j) + { + convertedOutline[i][j] = outline[i][j] * definitionScale + outlineOffset; + } + } + sprite.OverridePhysicsShape(convertedOutline); + } + } + } + } + + public static string currentApplyAssetPath + { + set { s_CurrentApplyAssetPath = value; } + } + static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromPath) + { + if (!string.IsNullOrEmpty(s_CurrentApplyAssetPath)) + { + foreach (var asset in importedAssets) + { + if (asset == s_CurrentApplyAssetPath) + { + var obj = AssetDatabase.LoadMainAssetAtPath(asset); + Selection.activeObject = obj; + Unsupported.SceneTrackerFlushDirty(); + s_CurrentApplyAssetPath = null; + break; + } + } + } + } + } +} diff --git a/Editor/PSDImportPostProcessor.cs.meta b/Editor/PSDImportPostProcessor.cs.meta index 76ceb50..370ee65 100644 --- a/Editor/PSDImportPostProcessor.cs.meta +++ b/Editor/PSDImportPostProcessor.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 96feaa0b12eabfe44b345be97ea0029c -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 96feaa0b12eabfe44b345be97ea0029c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDImporter.cs b/Editor/PSDImporter.cs index 278fa4d..0314a6b 100644 --- a/Editor/PSDImporter.cs +++ b/Editor/PSDImporter.cs @@ -1,1380 +1,1408 @@ -using System; -using System.Collections.Generic; -using System.IO; -using PDNWrapper; -using UnityEngine; -using Unity.Collections; -using System.Linq; -using UnityEditor.Experimental.AssetImporters; -using UnityEditor.U2D.Animation; -using UnityEditor.U2D.Common; -using UnityEditor.U2D.Sprites; -using UnityEngine.Assertions; -using UnityEngine.Experimental.U2D.Animation; -using UnityEngine.U2D; -using UnityEngine.U2D.Animation; -using UnityEditor.MemoryProfiler; -using UnityEngine.Profiling.Memory.Experimental; - -namespace UnityEditor.U2D.PSD -{ - /// - /// ScriptedImporter to import Photoshop files - /// - [ScriptedImporter(4, "psb")] - [HelpURL("https://docs.unity3d.com/Packages/com.unity.2d.psdimporter@3.1/manual/index.html")] - public class PSDImporter : ScriptedImporter, ISpriteEditorDataProvider - { - class UniqueNameGenerator - { - List m_NameHash = new List(); - - public bool ContainHash(int i) - { - return m_NameHash.Contains(i); - } - - public void AddHash(int i) - { - m_NameHash.Add(i); - } - - public string GetUniqueName(string name) - { - return PSDImporter.GetUniqueName(name, m_NameHash); - } - } - - class GameObjectCreationFactory : UniqueNameGenerator - { - - public GameObject CreateGameObject(string name, params System.Type[] components) - { - var newName = GetUniqueName(name); - return new GameObject(newName, components); - } - } - - struct BoneGO - { - public GameObject go; - public int index; - } - - [SerializeField] - TextureImporterSettings m_TextureImporterSettings = new TextureImporterSettings() { - mipmapEnabled = true, - mipmapFilter = TextureImporterMipFilter.BoxFilter, - sRGBTexture = true, - borderMipmap = false, - mipMapsPreserveCoverage = false, - alphaTestReferenceValue = 0.5f, - readable = false, - -#if ENABLE_TEXTURE_STREAMING - streamingMipmaps = true, -#endif - - fadeOut = false, - mipmapFadeDistanceStart = 1, - mipmapFadeDistanceEnd = 3, - - convertToNormalMap = false, - heightmapScale = 0.25F, - normalMapFilter = 0, - - generateCubemap = TextureImporterGenerateCubemap.AutoCubemap, - cubemapConvolution = 0, - - seamlessCubemap = false, - - npotScale = TextureImporterNPOTScale.ToNearest, - - spriteMode = (int)SpriteImportMode.Multiple, - spriteExtrude = 1, - spriteMeshType = SpriteMeshType.Tight, - spriteAlignment = (int)SpriteAlignment.Center, - spritePivot = new Vector2(0.5f, 0.5f), - spritePixelsPerUnit = 100.0f, - spriteBorder = new Vector4(0.0f, 0.0f, 0.0f, 0.0f), - - alphaSource = TextureImporterAlphaSource.FromInput, - alphaIsTransparency = true, - spriteTessellationDetail = -1.0f, - - textureType = TextureImporterType.Sprite, - textureShape = TextureImporterShape.Texture2D, - - filterMode = FilterMode.Bilinear, - aniso = 1, - mipmapBias = 0.0f, - wrapModeU = TextureWrapMode.Repeat, - wrapModeV = TextureWrapMode.Repeat, - wrapModeW = TextureWrapMode.Repeat, - }; - - [SerializeField] - List m_SpriteImportData = new List(); // we use index 0 for single sprite and the rest for multiple sprites - [SerializeField] - List m_MosaicSpriteImportData = new List(); - [SerializeField] - List m_RigSpriteImportData = new List(); - - [SerializeField] - List m_PlatformSettings = new List(); - [SerializeField] - bool m_MosaicLayers = true; - [SerializeField] - Vector2 m_DocumentPivot = Vector2.zero; - [SerializeField] - SpriteAlignment m_DocumentAlignment = SpriteAlignment.BottomCenter; - [SerializeField] - bool m_ImportHiddenLayers = false; - [SerializeField] - int m_ImportedTextureWidth; - [SerializeField] - int m_ImportedTextureHeight; - [SerializeField] - Vector2Int m_DocumentSize; - - [SerializeField] - bool m_PaperDollMode = false; - - [SerializeField] - bool m_KeepDupilcateSpriteName = false; - - [SerializeField] - SpriteCategoryList m_SpriteCategoryList = new SpriteCategoryList() {categories = new List()}; - GameObjectCreationFactory m_GameObjectFactory = new GameObjectCreationFactory(); - - internal SpriteCategoryList spriteCategoryList { get { return m_SpriteCategoryList; } set { m_SpriteCategoryList = value; } } - - [SerializeField] - int m_TextureActualWidth; - internal int textureActualWidth - { - get { return m_TextureActualWidth; } - private set { m_TextureActualWidth = value; } - } - - [SerializeField] - int m_TextureActualHeight; - internal int textureActualHeight - { - get { return m_TextureActualHeight; } - private set { m_TextureActualHeight = value; } - } - - [SerializeField] - string m_SpritePackingTag = ""; - - [SerializeField] - bool m_ResliceFromLayer = false; - [SerializeField] - bool m_CharacterMode = true; - - [SerializeField] - List m_MosaicPSDLayers = new List(); - [SerializeField] - List m_RigPSDLayers = new List(); - - [SerializeField] - CharacterData m_CharacterData = new CharacterData(); - - [SerializeField] - bool m_GenerateGOHierarchy = false; - - [SerializeField] - string m_TextureAssetName = null; - - [SerializeField] - string m_PrefabAssetName = null; - - [SerializeField] - string m_SpriteLibAssetName = null; - - [SerializeField] - SecondarySpriteTexture[] m_SecondarySpriteTextures; - - /// - /// Implementation of ScriptedImporter.OnImportAsset - /// - /// - /// This argument contains all the contextual information needed to process the import - /// event and is also used by the custom importer to store the resulting Unity Asset. - /// - public override void OnImportAsset(AssetImportContext ctx) - { - FileStream fileStream = new FileStream(ctx.assetPath, FileMode.Open, FileAccess.Read); - Document doc = null; - try - { - UnityEngine.Profiling.Profiler.BeginSample("OnImportAsset"); - - UnityEngine.Profiling.Profiler.BeginSample("PsdLoad"); - doc = PaintDotNet.Data.PhotoshopFileType.PsdLoad.Load(fileStream); - UnityEngine.Profiling.Profiler.EndSample(); - - ValidatePSDLayerId(doc); - - m_DocumentSize = new Vector2Int(doc.width, doc.height); - bool singleSpriteMode = m_TextureImporterSettings.textureType == TextureImporterType.Sprite && m_TextureImporterSettings.spriteMode != (int)SpriteImportMode.Multiple; - EnsureSingleSpriteExist(); - - if (m_TextureImporterSettings.textureType != TextureImporterType.Sprite || - m_MosaicLayers == false || singleSpriteMode) - { - var image = new NativeArray(doc.width * doc.height, Allocator.Persistent); - try - { - var spriteImportData = GetSpriteImportData(); - FlattenImageTask.Execute(doc.Layers, m_ImportHiddenLayers, doc.width, doc.height, image); - - int spriteCount = spriteDataCount; - int spriteIndexStart = 1; - - if (spriteImportData.Count <= 0 || spriteImportData[0] == null) - { - spriteImportData.Add(new SpriteMetaData()); - } - spriteImportData[0].name = System.IO.Path.GetFileNameWithoutExtension(ctx.assetPath) + "_1"; - spriteImportData[0].alignment = (SpriteAlignment)m_TextureImporterSettings.spriteAlignment; - spriteImportData[0].border = m_TextureImporterSettings.spriteBorder; - spriteImportData[0].pivot = m_TextureImporterSettings.spritePivot; - spriteImportData[0].rect = new Rect(0, 0, doc.width, doc.height); - if (singleSpriteMode) - { - spriteCount = 1; - spriteIndexStart = 0; - } - textureActualWidth = doc.width; - textureActualHeight = doc.height; - var output = ImportTexture(ctx, image, doc.width, doc.height, spriteIndexStart, spriteCount); - RegisterAssets(ctx, output); - } - finally - { - image.Dispose(); - } - } - else - { - ImportFromLayers(ctx, doc); - } - } - finally - { - fileStream.Close(); - if (doc != null) - doc.Dispose(); - UnityEngine.Profiling.Profiler.EndSample(); - EditorUtility.SetDirty(this); - } - - - // Debug Profiler. - // UnityEngine.Profiling.Memory.Experimental.MemoryProfiler.TakeSnapshot("snapshot.snap", MemorySnapshotFinish, CaptureFlags.ManagedObjects | CaptureFlags.NativeObjects | CaptureFlags.NativeAllocations | CaptureFlags.NativeStackTraces); - } - - static void ValidatePSDLayerId(List layers, UniqueNameGenerator uniqueNameGenerator) - { - for (int i = 0; i < layers.Count; ++i) - { - if (uniqueNameGenerator.ContainHash(layers[i].LayerID)) - { - var importWarning = string.Format("Layer {0}: LayerId is not unique. Mapping will be done by Layer's name.", layers[i].Name); - var layerName = uniqueNameGenerator.GetUniqueName(layers[i].Name); - if (layerName != layers[i].Name) - importWarning += "\nLayer names are not unique. Please ensure they are unique to for SpriteRect to be mapped back correctly."; - layers[i].LayerID = layerName.GetHashCode(); - Debug.LogWarning(importWarning); - } - else - uniqueNameGenerator.AddHash(layers[i].LayerID); - if (layers[i].ChildLayer != null) - { - ValidatePSDLayerId(layers[i].ChildLayer, uniqueNameGenerator); - } - } - } - - - void ValidatePSDLayerId(Document doc) - { - UniqueNameGenerator uniqueNameGenerator = new UniqueNameGenerator(); - - ValidatePSDLayerId(doc.Layers, uniqueNameGenerator); - } - - TextureGenerationOutput ImportTexture(AssetImportContext ctx, NativeArray imageData, int textureWidth, int textureHeight, int spriteStart, int spriteCount) - { - if (!imageData.IsCreated || imageData.Length == 0) - return new TextureGenerationOutput(); - - UnityEngine.Profiling.Profiler.BeginSample("ImportTexture"); - var platformSettings = GetPlatformTextureSettings(ctx.selectedBuildTarget); - - var textureSettings = m_TextureImporterSettings.ExtractTextureSettings(); - textureSettings.assetPath = ctx.assetPath; - textureSettings.enablePostProcessor = true; - textureSettings.containsAlpha = true; - textureSettings.hdr = false; - - var textureAlphaSettings = m_TextureImporterSettings.ExtractTextureAlphaSettings(); - var textureMipmapSettings = m_TextureImporterSettings.ExtractTextureMipmapSettings(); - var textureCubemapSettings = m_TextureImporterSettings.ExtractTextureCubemapSettings(); - var textureWrapSettings = m_TextureImporterSettings.ExtractTextureWrapSettings(); - - TextureGenerationOutput output; - switch (m_TextureImporterSettings.textureType) - { - case TextureImporterType.Default: - output = TextureGeneratorHelper.GenerateTextureDefault(imageData, textureWidth, textureHeight, textureSettings, platformSettings, textureAlphaSettings, textureMipmapSettings, textureCubemapSettings, textureWrapSettings); - break; - case TextureImporterType.NormalMap: - var textureNormalSettings = m_TextureImporterSettings.ExtractTextureNormalSettings(); - output = TextureGeneratorHelper.GenerateNormalMap(imageData, textureWidth, textureHeight, textureSettings, platformSettings, textureNormalSettings, textureMipmapSettings, textureCubemapSettings, textureWrapSettings); - break; - case TextureImporterType.GUI: - output = TextureGeneratorHelper.GenerateTextureGUI(imageData, textureWidth, textureHeight, textureSettings, platformSettings, textureAlphaSettings, textureMipmapSettings, textureWrapSettings); - break; - case TextureImporterType.Sprite: - var textureSpriteSettings = m_TextureImporterSettings.ExtractTextureSpriteSettings(); - textureSpriteSettings.packingTag = m_SpritePackingTag; - textureSpriteSettings.qualifyForPacking = !string.IsNullOrEmpty(m_SpritePackingTag); - textureSpriteSettings.spriteSheetData = new UnityEditor.Experimental.AssetImporters.SpriteImportData[spriteCount]; - textureSettings.npotScale = TextureImporterNPOTScale.None; - textureSettings.secondaryTextures = secondaryTextures; - var spriteImportData = GetSpriteImportData(); - for (int i = 0; i < spriteCount; ++i) - { - //AutoGenerateSpriteSkinData(m_SpriteImportData[spriteStart + i]); - textureSpriteSettings.spriteSheetData[i] = spriteImportData[spriteStart + i]; - } - output = TextureGeneratorHelper.GenerateTextureSprite(imageData, textureWidth, textureHeight, textureSettings, platformSettings, textureSpriteSettings, textureAlphaSettings, textureMipmapSettings, textureWrapSettings); - break; - case TextureImporterType.Cursor: - output = TextureGeneratorHelper.GenerateTextureCursor(imageData, textureWidth, textureHeight, textureSettings, platformSettings, textureAlphaSettings, textureMipmapSettings, textureWrapSettings); - break; - case TextureImporterType.Cookie: - output = TextureGeneratorHelper.GenerateCookie(imageData, textureWidth, textureHeight, textureSettings, platformSettings, textureAlphaSettings, textureMipmapSettings, textureCubemapSettings, textureWrapSettings); - break; - case TextureImporterType.Lightmap: - output = TextureGeneratorHelper.GenerateLightmap(imageData, textureWidth, textureHeight, textureSettings, platformSettings, textureMipmapSettings, textureWrapSettings); - break; - case TextureImporterType.SingleChannel: - output = TextureGeneratorHelper.GenerateTextureSingleChannel(imageData, textureWidth, textureHeight, textureSettings, platformSettings, textureAlphaSettings, textureMipmapSettings, textureCubemapSettings, textureWrapSettings); - break; - default: - Debug.LogAssertion("Unknown texture type for import"); - output = default(TextureGenerationOutput); - break; - } - UnityEngine.Profiling.Profiler.EndSample(); - return output; - } - - void AutoGenerateSpriteSkinData(SpriteMetaData metaData) - { - //If bone data exist but skinning data doesn't exist, auto generate them - if (metaData.spriteBone != null && metaData.spriteBone.Count > 0 && - (metaData.vertices == null || metaData.vertices.Count == 0)) - { - var spriteMeshDataController = new SpriteMeshDataController(); - var smd = new SpriteMeshData(); - smd.spriteID = metaData.spriteID; - smd.frame = metaData.rect; - smd.pivot = metaData.pivot; - smd.bones = ModuleUtility.CreateSpriteBoneData(metaData.spriteBone.ToArray(), Matrix4x4.TRS(metaData.rect.position, Quaternion.identity, Vector3.one)); - spriteMeshDataController.spriteMeshData = smd; - spriteMeshDataController.OutlineFromAlpha(new OutlineGenerator(), GetDataProvider(), 0.05f, 200); - spriteMeshDataController.Triangulate(new Triangulator()); - spriteMeshDataController.Subdivide(new Triangulator(), 0.25f); - spriteMeshDataController.CalculateWeights(new BoundedBiharmonicWeightsGenerator(), null, 0.01f); - spriteMeshDataController.SortTrianglesByDepth(); - - List vmd = new List(smd.vertices.Count); - foreach (var v in smd.vertices) - vmd.Add(new Vertex2DMetaData() { position = v.position - smd.frame.position, boneWeight = v.editableBoneWeight.ToBoneWeight(true) }); - List emd = new List(smd.edges.Count); - foreach (var e in smd.edges) - emd.Add(new Vector2Int(e.index1, e.index2)); - - metaData.vertices = vmd; - metaData.indices = smd.indices.ToArray(); - metaData.edges = emd.ToArray(); - } - } - - string GetUniqueSpriteName(string name, List namehash) - { - if (m_KeepDupilcateSpriteName) - return name; - return GetUniqueName(name, namehash); - } - - void ImportFromLayers(AssetImportContext ctx, Document doc) - { - NativeArray output = default(NativeArray); - - List layerIndex = new List(); - List spriteNameHash = new List(); - var oldPsdLayers = GetPSDLayers(); - try - { - var psdLayers = new List(); - ExtractLayerTask.Execute(psdLayers, doc.Layers, m_ImportHiddenLayers); - var removedLayersSprite = oldPsdLayers.Where(x => psdLayers.FirstOrDefault(y => y.layerID == x.layerID) == null).Select(z => z.spriteID).ToArray(); - for (int i = 0; i < psdLayers.Count; ++i) - { - int j = 0; - var psdLayer = psdLayers[i]; - for (; j < oldPsdLayers.Count; ++j) - { - if (psdLayer.layerID == oldPsdLayers[j].layerID) - { - psdLayer.spriteID = oldPsdLayers[j].spriteID; - psdLayer.spriteName = oldPsdLayers[j].spriteName; - psdLayer.mosaicPosition = oldPsdLayers[j].mosaicPosition; - break; - } - } - } - - int expectedBufferLength = doc.width * doc.height; - var layerBuffers = new List>(); - for (int i = 0; i < psdLayers.Count; ++i) - { - var l = psdLayers[i]; - if (l.texture.IsCreated && l.texture.Length == expectedBufferLength) - { - layerBuffers.Add(l.texture); - layerIndex.Add(i); - } - } - - RectInt[] spritedata; - int width, height; - int padding = 4; - Vector2Int[] uvTransform; - ImagePacker.Pack(layerBuffers.ToArray(), doc.width, doc.height, padding, out output, out width, out height, out spritedata, out uvTransform); - var spriteImportData = GetSpriteImportData(); - if (spriteImportData.Count <= 0 || shouldResliceFromLayer) - { - var newSpriteMeta = new List(); - - for (int i = 0; i < spritedata.Length && i < layerIndex.Count; ++i) - { - var spriteSheet = spriteImportData.FirstOrDefault(x => x.spriteID == psdLayers[layerIndex[i]].spriteID); - if (spriteSheet == null) - { - spriteSheet = new SpriteMetaData(); - spriteSheet.border = Vector4.zero; - spriteSheet.alignment = (SpriteAlignment)m_TextureImporterSettings.spriteAlignment; - spriteSheet.pivot = m_TextureImporterSettings.spritePivot; - } - - psdLayers[layerIndex[i]].spriteName = GetUniqueSpriteName(psdLayers[layerIndex[i]].name, spriteNameHash); - spriteSheet.name = psdLayers[layerIndex[i]].spriteName; - spriteSheet.rect = new Rect(spritedata[i].x, spritedata[i].y, spritedata[i].width, spritedata[i].height); - spriteSheet.uvTransform = uvTransform[i]; - - psdLayers[layerIndex[i]].spriteID = spriteSheet.spriteID; - psdLayers[layerIndex[i]].mosaicPosition = spritedata[i].position; - newSpriteMeta.Add(spriteSheet); - } - spriteImportData.Clear(); - spriteImportData.AddRange(newSpriteMeta); - } - else - { - spriteImportData.RemoveAll(x => removedLayersSprite.Contains(x.spriteID)); - - // First look for any user created SpriteRect and add those into the name hash - foreach (var spriteData in spriteImportData) - { - var psdLayer = psdLayers.FirstOrDefault(x => x.spriteID == spriteData.spriteID); - if (psdLayer == null) - spriteNameHash.Add(spriteData.name.GetHashCode()); - } - - foreach (var spriteData in spriteImportData) - { - var psdLayer = psdLayers.FirstOrDefault(x => x.spriteID == spriteData.spriteID); - if (psdLayer == null) - spriteData.uvTransform = new Vector2Int((int)spriteData.rect.position.x, (int)spriteData.rect.position.y); - // If it is user created rect or the name has been changed before - // add it into the spriteNameHash and we don't copy it over from the layer - if (psdLayer == null || psdLayer.spriteName != spriteData.name) - spriteNameHash.Add(spriteData.name.GetHashCode()); - - // If the sprite name has not been changed, we ensure the new - // layer name is still unique and use it as the sprite name - if (psdLayer != null && psdLayer.spriteName == spriteData.name) - { - psdLayer.spriteName = GetUniqueSpriteName(psdLayer.name, spriteNameHash); - spriteData.name = psdLayer.spriteName; - } - } - - //Update names for those user has not changed and add new sprite rect based on PSD file. - for (int k = 0; k < layerIndex.Count; ++k) - { - int i = layerIndex[k]; - var spriteSheet = spriteImportData.FirstOrDefault(x => x.spriteID == psdLayers[i].spriteID); - var inOldLayer = oldPsdLayers.FindIndex(x => x.layerID == psdLayers[i].layerID) != -1; - if (spriteSheet == null && !inOldLayer) - { - spriteSheet = new SpriteMetaData(); - spriteImportData.Add(spriteSheet); - spriteSheet.rect = new Rect(spritedata[k].x, spritedata[k].y, spritedata[k].width, spritedata[k].height); - spriteSheet.border = Vector4.zero; - spriteSheet.alignment = (SpriteAlignment)m_TextureImporterSettings.spriteAlignment; - spriteSheet.pivot = m_TextureImporterSettings.spritePivot; - psdLayers[i].spriteName = GetUniqueSpriteName(psdLayers[i].name, spriteNameHash); - spriteSheet.name = psdLayers[i].spriteName; - } - else if (spriteSheet != null) - { - var r = spriteSheet.rect; - r.position = spriteSheet.rect.position - psdLayers[i].mosaicPosition + spritedata[k].position; - spriteSheet.rect = r; - } - - if (spriteSheet != null) - { - spriteSheet.uvTransform = uvTransform[k]; - psdLayers[i].spriteID = spriteSheet.spriteID; - psdLayers[i].mosaicPosition = spritedata[k].position; - } - } - } - - foreach (var l in oldPsdLayers) - l.Dispose(); - oldPsdLayers.Clear(); - - oldPsdLayers.AddRange(psdLayers); - m_ImportedTextureHeight = textureActualHeight = height; - m_ImportedTextureWidth = textureActualWidth = width; - var generatedTexture = ImportTexture(ctx, output, width, height, 0, spriteImportData.Count); - - if (generatedTexture.texture) - { - m_ImportedTextureHeight = generatedTexture.texture.height; - m_ImportedTextureWidth = generatedTexture.texture.width; - } - - RegisterAssets(ctx, generatedTexture); - } - finally - { - if (output.IsCreated) - output.Dispose(); - foreach (var l in oldPsdLayers) - l.Dispose(); - } - - } - - void MemorySnapshotFinish(string path, bool done) - { - - } - - void EnsureSingleSpriteExist() - { - if (m_SpriteImportData.Count <= 0) - m_SpriteImportData.Add(new SpriteMetaData()); // insert default for single sprite mode - } - - internal TextureImporterPlatformSettings GetPlatformTextureSettings(BuildTarget buildTarget) - { - var buildTargetName = TexturePlatformSettingsModal.kValidBuildPlatform.FirstOrDefault(x => x.buildTarget.Contains(buildTarget)); - var defaultTargetName = TexturePlatformSettingsModal.kValidBuildPlatform.FirstOrDefault(x => x.buildTarget.Contains(BuildTarget.NoTarget)); - TextureImporterPlatformSettings platformSettings = null; - platformSettings = m_PlatformSettings.SingleOrDefault(x => x.name == buildTargetName.buildTargetName); - platformSettings = platformSettings ?? m_PlatformSettings.SingleOrDefault(x => x.name == defaultTargetName.buildTargetName); - - if (platformSettings == null) - { - platformSettings = new TextureImporterPlatformSettings(); - platformSettings.name = name; - platformSettings.overridden = false; - } - return platformSettings; - } - - void RegisterAssets(AssetImportContext ctx, TextureGenerationOutput output) - { - List assetNameHash = new List(); - if (!string.IsNullOrEmpty(output.importInspectorWarnings)) - { - Debug.LogWarning(output.importInspectorWarnings); - } - if (output.importWarnings != null && output.importWarnings.Length != 0) - { - foreach (var warning in output.importWarnings) - Debug.LogWarning(warning); - } - if (output.thumbNail == null) - Debug.LogWarning("Thumbnail generation fail"); - if (output.texture == null) - { - throw new Exception("Texture import fail"); - } - - var assetName = GetUniqueName(System.IO.Path.GetFileNameWithoutExtension(ctx.assetPath), assetNameHash, true); - // Setup all fixed name on the hash table - if (string.IsNullOrEmpty(m_TextureAssetName)) - m_TextureAssetName = GetUniqueName(string.Format("{0} Texture",assetName), assetNameHash, true); - if (string.IsNullOrEmpty(m_PrefabAssetName)) - m_PrefabAssetName = GetUniqueName(string.Format("{0} Prefab", assetName), assetNameHash, true); - if (string.IsNullOrEmpty(m_SpriteLibAssetName)) - m_SpriteLibAssetName = GetUniqueName(string.Format("{0} Sprite Lib", assetName), assetNameHash, true); - - output.texture.name = assetName; - ctx.AddObjectToAsset(m_TextureAssetName, output.texture, output.thumbNail); - UnityEngine.Object mainAsset = output.texture; - - - if (output.sprites != null) - { - var slAsset = ProduceSpriteLibAsset(output.sprites); - - if (shouldProduceGameObject) - { - GameObject prefab = null; - if (m_PaperDollMode) - prefab = OnProducePaperDollPrefab(m_TextureAssetName, output.sprites, slAsset); - else - prefab = OnProducePrefab(m_TextureAssetName, output.sprites, slAsset); - if (prefab != null) - { - ctx.AddObjectToAsset(m_PrefabAssetName, prefab); - mainAsset = prefab; - } - } - - foreach (var s in output.sprites) - { - var spriteAssetName = GetUniqueName(s.GetSpriteID().ToString(), assetNameHash, false, s); - ctx.AddObjectToAsset(spriteAssetName, s); - } - - if (slAsset != null) - { - slAsset.name = assetName; - ctx.AddObjectToAsset(m_SpriteLibAssetName, slAsset); - } - } - ctx.SetMainObject(mainAsset); - } - - bool SpriteIsMainFromSpriteLib(string spriteId, out string categoryName) - { - categoryName = ""; - if (m_SpriteCategoryList.categories != null) - { - foreach (var category in m_SpriteCategoryList.categories) - { - var index = category.labels.FindIndex(x => x.spriteId == spriteId); - if (index == 0) - { - categoryName = category.name; - return true; - } - if (index > 0) - return false; - } - } - return true; - } - - void BuildGroupGameObject(List psdGroup, int index, Transform root) - { - var spriteData = GetSpriteImportData().FirstOrDefault(x => x.spriteID == psdGroup[index].spriteID); - if (psdGroup[index].gameObject == null) - { - if (m_GenerateGOHierarchy || (!psdGroup[index].spriteID.Empty() && psdGroup[index].isGroup == false)) - { - // Determine if need to create GameObject i.e. if the sprite is not in a SpriteLib or if it is the first one - string categoryName; - var b = SpriteIsMainFromSpriteLib(psdGroup[index].spriteID.ToString(), out categoryName); - string goName = string.IsNullOrEmpty(categoryName) ? spriteData != null ? spriteData.name : psdGroup[index].name : categoryName; - if (b) - psdGroup[index].gameObject = m_GameObjectFactory.CreateGameObject(goName); - } - if (psdGroup[index].parentIndex >= 0 && m_GenerateGOHierarchy) - { - BuildGroupGameObject(psdGroup, psdGroup[index].parentIndex, root); - root = psdGroup[psdGroup[index].parentIndex].gameObject.transform; - } - - if (psdGroup[index].gameObject != null) - psdGroup[index].gameObject.transform.SetParent(root); - } - } - - bool shouldProduceGameObject - { - get { return m_CharacterMode && m_MosaicLayers && spriteImportMode == SpriteImportMode.Multiple; } - } - - bool shouldResliceFromLayer - { - get { return m_ResliceFromLayer && m_MosaicLayers && spriteImportMode == SpriteImportMode.Multiple; } - } - - bool characterMode - { - get { return mosaicMode && m_CharacterMode == true; } - } - - float definitionScale - { - get - { - float definitionScaleW = m_ImportedTextureWidth / (float)textureActualWidth; - float definitionScaleH = m_ImportedTextureHeight / (float)textureActualHeight; - return Mathf.Min(definitionScaleW, definitionScaleH); - } - } - - private Vector2 GetPivotPoint(Rect rect, SpriteAlignment alignment) - { - switch (alignment) - { - case SpriteAlignment.TopLeft: - return new Vector2(rect.xMin, rect.yMax); - - case SpriteAlignment.TopCenter: - return new Vector2(rect.center.x, rect.yMax); - - case SpriteAlignment.TopRight: - return new Vector2(rect.xMax, rect.yMax); - - case SpriteAlignment.LeftCenter: - return new Vector2(rect.xMin, rect.center.y); - - case SpriteAlignment.Center: - return new Vector2(rect.center.x, rect.center.y); - - case SpriteAlignment.RightCenter: - return new Vector2(rect.xMax, rect.center.y); - - case SpriteAlignment.BottomLeft: - return new Vector2(rect.xMin, rect.yMin); - - case SpriteAlignment.BottomCenter: - return new Vector2(rect.center.x, rect.yMin); - - case SpriteAlignment.BottomRight: - return new Vector2(rect.xMax, rect.yMin); - - case SpriteAlignment.Custom: - return new Vector2(m_DocumentPivot.x * rect.width, m_DocumentPivot.y * rect.height); - } - return Vector2.zero; - } - - void CreateBoneGO(int index, SpriteBone[] bones, BoneGO[] bonesGO, Transform defaultRoot) - { - if (bonesGO[index].go != null) - return; - var bone = bones[index]; - if (bone.parentId != -1 && bonesGO[bone.parentId].go == null) - CreateBoneGO(bone.parentId, bones, bonesGO, defaultRoot); - - var go = m_GameObjectFactory.CreateGameObject(bone.name); - if (bone.parentId == -1) - go.transform.SetParent(defaultRoot); - else - go.transform.SetParent(bonesGO[bone.parentId].go.transform); - go.transform.localPosition = bone.position * 1 / pixelsPerUnit; - go.transform.localRotation = bone.rotation; - bonesGO[index] = new BoneGO() - { - go = go, - index = index - }; - } - - BoneGO[] CreateBonesGO(Transform root) - { - if (characterMode) - { - var characterSkeleton = GetDataProvider().GetCharacterData(); - var bones = characterSkeleton.bones; - if (bones != null) - { - var boneGOs = new BoneGO[bones.Length]; - for (int i = 0; i < bones.Length; ++i) - { - CreateBoneGO(i, bones, boneGOs, root); - } - return boneGOs; - } - } - return new BoneGO[0]; - } - - void GetSpriteLiblabel(string spriteId, out string category, out string label) - { - category = ""; - label = ""; - var index = -1; - foreach (var cat in m_SpriteCategoryList.categories) - { - index = cat.labels.FindIndex(x => x.spriteId == spriteId); - if (index != -1) - { - category = cat.name; - label = cat.labels[index].name; - break; - } - } - } - - GameObject OnProducePaperDollPrefab(string assetname, Sprite[] sprites, SpriteLibraryAsset spriteLib) - { - GameObject root = null; - CharacterData? characterSkeleton = characterMode ? new CharacterData ? (GetDataProvider().GetCharacterData()) : null; - if (sprites != null && sprites.Length > 0) - { - root = new GameObject(); - root.name = assetname + "_GO"; - var spriteImportData = GetSpriteImportData(); - var psdLayers = GetPSDLayers(); - var boneGOs = CreateBonesGO(root.transform); - if (spriteLib != null) - root.AddComponent().spriteLibraryAsset = spriteLib; - for (int i = 0; i < sprites.Length; ++i) - { - string categoryName; - if (SpriteIsMainFromSpriteLib(sprites[i].GetSpriteID().ToString(), out categoryName)) - { - var spriteBones = m_CharacterData.parts.FirstOrDefault(x => new GUID(x.spriteId) == sprites[i].GetSpriteID()).bones; - var rootBone = root; - if (spriteBones != null && spriteBones.Any()) - { - var b = spriteBones.Where(x => x >= 0 && x < boneGOs.Length).Select(x => boneGOs[x]).OrderBy(x => x.index); - if (b.Any()) - rootBone = b.First().go; - } - - var srGameObject = m_GameObjectFactory.CreateGameObject(string.IsNullOrEmpty(categoryName) ? sprites[i].name : categoryName); - var sr = srGameObject.AddComponent(); - sr.sprite = sprites[i]; - sr.sortingOrder = psdLayers.Count - psdLayers.FindIndex(x => x.spriteID == sprites[i].GetSpriteID()); - srGameObject.transform.parent = rootBone.transform; - var spriteMetaData = spriteImportData.FirstOrDefault(x => x.spriteID == sprites[i].GetSpriteID()); - if (spriteMetaData != null) - { - var uvTransform = spriteMetaData.uvTransform; - var outlineOffset = new Vector2(spriteMetaData.rect.x - uvTransform.x + (spriteMetaData.pivot.x * spriteMetaData.rect.width), - spriteMetaData.rect.y - uvTransform.y + (spriteMetaData.pivot.y * spriteMetaData.rect.height)) * definitionScale / sprites[i].pixelsPerUnit; - srGameObject.transform.position = new Vector3(outlineOffset.x, outlineOffset.y, 0); - } - var category = ""; - var labelName = ""; - GetSpriteLiblabel(sprites[i].GetSpriteID().ToString(), out category, out labelName); - if (!string.IsNullOrEmpty(category) && !string.IsNullOrEmpty(labelName)) - { - var sresolver = srGameObject.AddComponent(); - sresolver.SetCategoryAndLabel(category, labelName); - sresolver.ResolveSpriteToSpriteRenderer(); - } - } - } - } - return root; - } - - GameObject OnProducePrefab(string assetname, Sprite[] sprites, SpriteLibraryAsset spriteLib) - { - GameObject root = null; - CharacterData? characterSkeleton = characterMode ? new CharacterData ? (GetDataProvider().GetCharacterData()) : null; - if (sprites != null && sprites.Length > 0) - { - var spriteImportData = GetSpriteImportData(); - root = new GameObject(); - root.name = assetname + "_GO"; - if (spriteLib != null) - root.AddComponent().spriteLibraryAsset = spriteLib; - - var psdLayers = GetPSDLayers(); - for (int i = 0; i < psdLayers.Count; ++i) - { - BuildGroupGameObject(psdLayers, i, root.transform); - } - var boneGOs = CreateBonesGO(root.transform); - for (int i = 0; i < psdLayers.Count; ++i) - { - var l = psdLayers[i]; - GUID layerSpriteID = l.spriteID; - var sprite = sprites.FirstOrDefault(x => x.GetSpriteID() == layerSpriteID); - var spriteMetaData = spriteImportData.FirstOrDefault(x => x.spriteID == layerSpriteID); - if (sprite != null && spriteMetaData != null && l.gameObject != null) - { - var spriteRenderer = l.gameObject.AddComponent(); - spriteRenderer.sprite = sprite; - spriteRenderer.sortingOrder = psdLayers.Count - i; - var uvTransform = spriteMetaData.uvTransform; - var outlineOffset = new Vector2(spriteMetaData.rect.x - uvTransform.x + (spriteMetaData.pivot.x * spriteMetaData.rect.width), - spriteMetaData.rect.y - uvTransform.y + (spriteMetaData.pivot.y * spriteMetaData.rect.height)) * definitionScale / sprite.pixelsPerUnit; - l.gameObject.transform.position = new Vector3(outlineOffset.x, outlineOffset.y, 0); - - if (characterSkeleton != null) - { - var part = characterSkeleton.Value.parts.FirstOrDefault(x => x.spriteId == spriteMetaData.spriteID.ToString()); - if (part.bones != null && part.bones.Length > 0) - { - var spriteSkin = l.gameObject.AddComponent(); - if (spriteRenderer.sprite != null && spriteRenderer.sprite.GetBindPoses().Length > 0) - { - var spriteBones = m_CharacterData.parts.FirstOrDefault(x => new GUID(x.spriteId) == spriteRenderer.sprite.GetSpriteID()).bones.Where(x => x >= 0 && x < boneGOs.Length).Select(x => boneGOs[x]); - if (spriteBones.Any()) - { - spriteSkin.rootBone = spriteBones.OrderBy(x => x.index).First().go.transform; - spriteSkin.boneTransforms = spriteBones.Select(x => x.go.transform).ToArray(); - if (spriteSkin.isValid) - spriteSkin.CalculateBounds(); - } - } - } - } - - var category = ""; - var labelName = ""; - GetSpriteLiblabel(layerSpriteID.ToString(), out category, out labelName); - if (!string.IsNullOrEmpty(category) && !string.IsNullOrEmpty(labelName)) - { - var sresolver = l.gameObject.AddComponent(); - sresolver.SetCategoryAndLabel(category, labelName); - sresolver.ResolveSpriteToSpriteRenderer(); - } - } - } - - var prefabBounds = new Rect(0 , 0, m_DocumentSize.x / pixelsPerUnit, m_DocumentSize.y / pixelsPerUnit); - var documentPivot = (Vector3)GetPivotPoint(prefabBounds, m_DocumentAlignment); - for (int i = 0; i < psdLayers.Count; ++i) - { - var l = psdLayers[i]; - if (l.gameObject == null || l.gameObject.GetComponent() == null) - continue; - var p = l.gameObject.transform.localPosition; - p -= documentPivot; - l.gameObject.transform.localPosition = p; - } - for (int i = 0; i < boneGOs.Length; ++i) - { - if (boneGOs[i].go.transform.parent != root.transform) - continue; - var p = boneGOs[i].go.transform.position; - p -= documentPivot; - boneGOs[i].go.transform.position = p; - } - } - - return root; - } - - Bounds? GetBoundingBox(GameObject root) - { - Bounds? prefabBounds1 = null; - var sr = root.GetComponent(); - if (sr != null) - { - prefabBounds1 = sr.bounds; - } - for (int i = 0; i < root.transform.childCount; ++i) - { - var b = GetBoundingBox(root.transform.GetChild(i).gameObject); - if (prefabBounds1 == null) - prefabBounds1 = b; - else - { - if (b.HasValue) - { - var bb = prefabBounds1.Value; - bb.Encapsulate(b.Value); - prefabBounds1 = bb; - } - } - } - return prefabBounds1; - } - - bool CleanUpGameobjectsWithOutRig(GameObject root) - { - var sr = root.GetComponent(); - var canDelete = true; - if (sr != null && sr.sprite != null) - { - try - { - var bones = GetDataProvider().GetBones(sr.sprite.GetSpriteID()); - canDelete = bones == null || bones.Count == 0; - } - catch (Exception e) - { - Debug.LogError(e); - } - } - - - List cleanup = new List(); - for (int i = 0; i < root.transform.childCount; ++i) - { - var go = root.transform.GetChild(i); - if (CleanUpGameobjectsWithOutRig(go.gameObject)) - cleanup.Add(go.gameObject); - } - - for (int i = 0; i < cleanup.Count; ++i) - GameObject.DestroyImmediate(cleanup[i]); - cleanup.Clear(); - - if (root.transform.childCount == 0 && canDelete) - return true; - - return false; - } - - static string SanitizeName(string name) - { - string newName = null; - // We can't create asset name with these name. - if ((name.Length == 2 && name[0] == '.' && name[1] == '.') - || (name.Length == 1 && name[0] == '.') - || (name.Length == 1 && name[0] == '/')) - newName += name + "_"; - - if (!string.IsNullOrEmpty(newName)) - { - Debug.LogWarning(string.Format("File contains layer with invalid name for generating asset. {0} is renamed to {1}", name, newName)); - return newName; - } - return name; - } - - static string GetUniqueName(string name, List stringHash, bool logNewNameGenerated = false, UnityEngine.Object context = null) - { - string uniqueName = string.Copy(SanitizeName(name)); - int index = 1; - while (true) - { - int hash = uniqueName.GetHashCode(); - var p = stringHash.Where(x => x == hash); - if (!p.Any()) - { - stringHash.Add(hash); - if (logNewNameGenerated && name != uniqueName) - Debug.Log(string.Format("Asset name {0} is changed to {1} to ensure uniqueness", name, uniqueName), context); - return uniqueName; - } - uniqueName = string.Format("{0}_{1}", name, index); - ++index; - } - } - - // ISpriteEditorDataProvider interface - internal SpriteImportMode spriteImportMode - { - get - { - return m_TextureImporterSettings.textureType != TextureImporterType.Sprite ? - SpriteImportMode.None : - (SpriteImportMode)m_TextureImporterSettings.spriteMode; - } - } - - SpriteImportMode ISpriteEditorDataProvider.spriteImportMode => spriteImportMode; - - internal int spriteDataCount - { - get - { - var spriteImportData = GetSpriteImportData(); - if (mosaicMode) - return spriteImportData.Count; - if (spriteImportMode != SpriteImportMode.Multiple) - return 1; - return spriteImportData.Count - 1; - } - } - - internal UnityEngine.Object targetObject - { - get { return this; } - } - UnityEngine.Object ISpriteEditorDataProvider.targetObject => targetObject; - - internal float pixelsPerUnit - { - get { return m_TextureImporterSettings.spritePixelsPerUnit; } - } - - float ISpriteEditorDataProvider.pixelsPerUnit =>pixelsPerUnit; - - internal T GetDataProvider() where T : class - { - if (typeof(T) == typeof(ISpriteBoneDataProvider)) - { - return new SpriteBoneDataProvider { dataProvider = this } as T; - } - if (typeof(T) == typeof(ISpriteMeshDataProvider)) - { - return new SpriteMeshDataProvider { dataProvider = this } as T; - } - if (typeof(T) == typeof(ISpriteOutlineDataProvider)) - { - return new SpriteOutlineDataProvider { dataProvider = this } as T; - } - if (typeof(T) == typeof(ISpritePhysicsOutlineDataProvider)) - { - return new SpritePhysicsOutlineProvider { dataProvider = this } as T; - } - if (typeof(T) == typeof(ITextureDataProvider)) - { - return new TextureDataProvider { dataProvider = this } as T; - } - if (typeof(T) == typeof(ICharacterDataProvider)) - { - return characterMode ? new CharacterDataProvider { dataProvider = this } as T : null; - } - if (typeof(T) == typeof(ISpriteLibDataProvider)) - { - return new SpriteLibraryDataProvider() { dataProvider = this } as T; - } - if (typeof(T) == typeof(ISecondaryTextureDataProvider)) - { - return new SecondaryTextureDataProvider() { dataProvider = this } as T; - } - else - return this as T; - } - - T ISpriteEditorDataProvider.GetDataProvider() - { - return GetDataProvider(); - } - - internal bool HasDataProvider(Type type) - { - if (characterMode && type == typeof(ICharacterDataProvider)) - return true; - if (type == typeof(ISpriteBoneDataProvider) || - type == typeof(ISpriteMeshDataProvider) || - type == typeof(ISpriteOutlineDataProvider) || - type == typeof(ISpritePhysicsOutlineDataProvider) || - type == typeof(ITextureDataProvider) || - type == typeof(ISpriteLibDataProvider) || - type == typeof(ISecondaryTextureDataProvider)) - { - return true; - } - else - return type.IsAssignableFrom(GetType()); - } - - bool ISpriteEditorDataProvider.HasDataProvider(Type type) - { - return HasDataProvider(type); - } - - internal void AddSpriteData(SpriteRect spriteRect) - { - if (spriteImportMode != SpriteImportMode.Multiple) - Debug.LogWarning("Can only add sprite data when import mode is multiple"); - else - { - GetSpriteImportData().Add(new SpriteMetaData(spriteRect)); - } - } - - internal void DeleteSpriteData(SpriteRect spriteRect) - { - if (spriteImportMode != SpriteImportMode.Multiple) - Debug.LogWarning("Can only add sprite data when import mode is multiple"); - else - { - var spriteImportData = GetSpriteImportData(); - int index = spriteImportData.FindIndex(x => x.spriteID == spriteRect.spriteID); - Assert.AreEqual(0, index, "Cannot delete Sprite from single sprite mode"); - spriteImportData.RemoveAt(index); - } - } - - internal int GetSpriteDataIndex(GUID guid) - { - switch (spriteImportMode) - { - case SpriteImportMode.Single: - case SpriteImportMode.Polygon: - return 0; - case SpriteImportMode.Multiple: - { - var spriteImportData = GetSpriteImportData(); - return spriteImportData.FindIndex(x => x.spriteID == guid); - } - default: - throw new InvalidOperationException("GUID not found"); - } - } - - internal void Apply() - { - // Do this so that asset change save dialog will not show - var originalValue = EditorPrefs.GetBool("VerifySavingAssets", false); - EditorPrefs.SetBool("VerifySavingAssets", false); - AssetDatabase.ForceReserializeAssets(new string[] { assetPath }, ForceReserializeAssetsOptions.ReserializeMetadata); - EditorPrefs.SetBool("VerifySavingAssets", originalValue); - } - - void ISpriteEditorDataProvider.Apply() - { - Apply(); - } - - internal void InitSpriteEditorDataProvider() {} - void ISpriteEditorDataProvider.InitSpriteEditorDataProvider() - { - InitSpriteEditorDataProvider(); - } - - internal SpriteRect[] GetSpriteRects() - { - var spriteImportData = GetSpriteImportData(); - var skip = mosaicMode ? 0 : 1; - return spriteImportMode == SpriteImportMode.Multiple ? spriteImportData.Skip(skip).Select(x => new SpriteMetaData(x) as SpriteRect).ToArray() : new[] {new SpriteMetaData(spriteImportData[0]) }; - } - - SpriteRect[] ISpriteEditorDataProvider.GetSpriteRects() - { - return GetSpriteRects(); - } - - List GetSpriteImportData() - { - return mosaicMode ? (characterMode ? m_RigSpriteImportData : m_MosaicSpriteImportData) : m_SpriteImportData; - } - - internal List GetPSDLayers() - { - return mosaicMode ? (characterMode ? m_RigPSDLayers : m_MosaicPSDLayers) : null; - } - - internal SpriteMetaData[] GetSpriteMetaData() - { - var spriteImportData = GetSpriteImportData(); - var skip = mosaicMode ? 0 : 1; - return spriteImportMode == SpriteImportMode.Multiple ? spriteImportData.Skip(skip).ToArray() : new[] { new SpriteMetaData(spriteImportData[0]) }; - } - - internal SpriteRect GetSpriteData(GUID guid) - { - var spriteImportData = GetSpriteImportData(); - var skip = mosaicMode ? 0 : 1; - return spriteImportMode == SpriteImportMode.Multiple ? spriteImportData.Skip(skip).FirstOrDefault(x => x.spriteID == guid) : spriteImportData[0]; - } - - internal void SetSpriteRects(SpriteRect[] spriteRects) - { - var spriteImportData = GetSpriteImportData(); - if (spriteImportMode == SpriteImportMode.Multiple) - { - var singleSpriteID = mosaicMode ? new GUID() : spriteImportData[0].spriteID; - spriteImportData.RemoveAll(data => data.spriteID != singleSpriteID && spriteRects.FirstOrDefault(x => x.spriteID == data.spriteID) == null); - foreach (var sr in spriteRects) - { - var importData = spriteImportData.FirstOrDefault(x => x.spriteID == sr.spriteID); - if (importData == null) - spriteImportData.Add(new SpriteMetaData(sr)); - else - { - importData.name = sr.name; - importData.alignment = sr.alignment; - importData.border = sr.border; - importData.pivot = sr.pivot; - importData.rect = sr.rect; - } - } - } - else if (spriteRects.Length == 1 && (spriteImportMode == SpriteImportMode.Single || spriteImportMode == SpriteImportMode.Polygon)) - { - if (spriteImportData[0].spriteID == spriteRects[0].spriteID) - { - spriteImportData[0].name = spriteRects[0].name; - spriteImportData[0].alignment = spriteRects[0].alignment; - m_TextureImporterSettings.spriteAlignment = (int)spriteRects[0].alignment; - m_TextureImporterSettings.spriteBorder = spriteImportData[0].border = spriteRects[0].border; - m_TextureImporterSettings.spritePivot = spriteImportData[0].pivot = spriteRects[0].pivot; - spriteImportData[0].rect = spriteRects[0].rect; - } - else - { - spriteImportData[0] = new SpriteMetaData(spriteRects[0]); - } - } - } - - void ISpriteEditorDataProvider.SetSpriteRects(SpriteRect[] spriteRects) - { - SetSpriteRects(spriteRects); - } - - bool mosaicMode - { - get { return spriteImportMode == SpriteImportMode.Multiple && m_MosaicLayers; } - } - - internal CharacterData characterData - { - get { return m_CharacterData; } - set { m_CharacterData = value; } - } - - internal Vector2Int documentSize - { - get { return m_DocumentSize; } - } - - SpriteLibraryAsset ProduceSpriteLibAsset(Sprite[] sprites) - { - if (!characterMode || m_SpriteCategoryList.categories == null) - return null; - var sla = ScriptableObject.CreateInstance(); - sla.name = "Sprite Lib"; - sla.categories = m_SpriteCategoryList.categories.Select(x => - new SpriteLibCategory() - { - name = x.name, - categoryList = x.labels.Select(y => - { - var sprite = sprites.FirstOrDefault(z => z.GetSpriteID().ToString() == y.spriteId); - return new Categorylabel() - { - name = y.name, - sprite = sprite - }; - }).ToList() - }).ToList(); - sla.categories.RemoveAll(x => x.categoryList.Count == 0); - if (sla.categories.Count > 0) - { - sla.UpdateHashes(); - return sla; - } - return null; - } - - internal SecondarySpriteTexture[] secondaryTextures - { - get { return m_SecondarySpriteTextures; } - set { m_SecondarySpriteTextures = value; } - } - } -} +using System; +using System.Collections.Generic; +using System.IO; +using PDNWrapper; +using UnityEngine; +using Unity.Collections; +using System.Linq; +using UnityEditor.Experimental.AssetImporters; +using UnityEditor.U2D.Animation; +using UnityEditor.U2D.Common; +using UnityEditor.U2D.Sprites; +using UnityEngine.Assertions; +using UnityEngine.Experimental.U2D.Animation; +using UnityEngine.U2D; +using UnityEngine.U2D.Animation; +using UnityEditor.MemoryProfiler; +using UnityEngine.Profiling.Memory.Experimental; + +namespace UnityEditor.U2D.PSD +{ + /// + /// ScriptedImporter to import Photoshop files + /// + [ScriptedImporter(4, "psb")] + [HelpURL("https://docs.unity3d.com/Packages/com.unity.2d.psdimporter@3.1/manual/index.html")] + public class PSDImporter : ScriptedImporter, ISpriteEditorDataProvider + { + class UniqueNameGenerator + { + List m_NameHash = new List(); + + public bool ContainHash(int i) + { + return m_NameHash.Contains(i); + } + + public void AddHash(int i) + { + m_NameHash.Add(i); + } + + public string GetUniqueName(string name) + { + return PSDImporter.GetUniqueName(name, m_NameHash); + } + } + + class GameObjectCreationFactory : UniqueNameGenerator + { + + public GameObject CreateGameObject(string name, params System.Type[] components) + { + var newName = GetUniqueName(name); + return new GameObject(newName, components); + } + } + + struct BoneGO + { + public GameObject go; + public int index; + } + + [SerializeField] + TextureImporterSettings m_TextureImporterSettings = new TextureImporterSettings() { + mipmapEnabled = true, + mipmapFilter = TextureImporterMipFilter.BoxFilter, + sRGBTexture = true, + borderMipmap = false, + mipMapsPreserveCoverage = false, + alphaTestReferenceValue = 0.5f, + readable = false, + +#if ENABLE_TEXTURE_STREAMING + streamingMipmaps = true, +#endif + + fadeOut = false, + mipmapFadeDistanceStart = 1, + mipmapFadeDistanceEnd = 3, + + convertToNormalMap = false, + heightmapScale = 0.25F, + normalMapFilter = 0, + + generateCubemap = TextureImporterGenerateCubemap.AutoCubemap, + cubemapConvolution = 0, + + seamlessCubemap = false, + + npotScale = TextureImporterNPOTScale.ToNearest, + + spriteMode = (int)SpriteImportMode.Multiple, + spriteExtrude = 1, + spriteMeshType = SpriteMeshType.Tight, + spriteAlignment = (int)SpriteAlignment.Center, + spritePivot = new Vector2(0.5f, 0.5f), + spritePixelsPerUnit = 100.0f, + spriteBorder = new Vector4(0.0f, 0.0f, 0.0f, 0.0f), + + alphaSource = TextureImporterAlphaSource.FromInput, + alphaIsTransparency = true, + spriteTessellationDetail = -1.0f, + + textureType = TextureImporterType.Sprite, + textureShape = TextureImporterShape.Texture2D, + + filterMode = FilterMode.Bilinear, + aniso = 1, + mipmapBias = 0.0f, + wrapModeU = TextureWrapMode.Repeat, + wrapModeV = TextureWrapMode.Repeat, + wrapModeW = TextureWrapMode.Repeat, + }; + + [SerializeField] + List m_SpriteImportData = new List(); // we use index 0 for single sprite and the rest for multiple sprites + [SerializeField] + List m_MosaicSpriteImportData = new List(); + [SerializeField] + List m_RigSpriteImportData = new List(); + + [SerializeField] + List m_PlatformSettings = new List(); + [SerializeField] + bool m_MosaicLayers = true; + [SerializeField] + Vector2 m_DocumentPivot = Vector2.zero; + [SerializeField] + SpriteAlignment m_DocumentAlignment = SpriteAlignment.BottomCenter; + [SerializeField] + bool m_ImportHiddenLayers = false; + [SerializeField] + int m_ImportedTextureWidth; + [SerializeField] + int m_ImportedTextureHeight; + [SerializeField] + Vector2Int m_DocumentSize; + + [SerializeField] + bool m_PaperDollMode = false; + + [SerializeField] + bool m_KeepDupilcateSpriteName = false; + + [SerializeField] + SpriteCategoryList m_SpriteCategoryList = new SpriteCategoryList() {categories = new List()}; + GameObjectCreationFactory m_GameObjectFactory = new GameObjectCreationFactory(); + + internal SpriteCategoryList spriteCategoryList { get { return m_SpriteCategoryList; } set { m_SpriteCategoryList = value; } } + + [SerializeField] + int m_TextureActualWidth; + internal int textureActualWidth + { + get { return m_TextureActualWidth; } + private set { m_TextureActualWidth = value; } + } + + [SerializeField] + int m_TextureActualHeight; + internal int textureActualHeight + { + get { return m_TextureActualHeight; } + private set { m_TextureActualHeight = value; } + } + + [SerializeField] + string m_SpritePackingTag = ""; + + [SerializeField] + bool m_ResliceFromLayer = false; + [SerializeField] + bool m_CharacterMode = true; + + [SerializeField] + List m_MosaicPSDLayers = new List(); + [SerializeField] + List m_RigPSDLayers = new List(); + + [SerializeField] + CharacterData m_CharacterData = new CharacterData(); + + [SerializeField] + bool m_GenerateGOHierarchy = false; + + [SerializeField] + string m_TextureAssetName = null; + + [SerializeField] + string m_PrefabAssetName = null; + + [SerializeField] + string m_SpriteLibAssetName = null; + + [SerializeField] + SecondarySpriteTexture[] m_SecondarySpriteTextures; + + /// + /// Implementation of ScriptedImporter.OnImportAsset + /// + /// + /// This argument contains all the contextual information needed to process the import + /// event and is also used by the custom importer to store the resulting Unity Asset. + /// + public override void OnImportAsset(AssetImportContext ctx) + { + FileStream fileStream = new FileStream(ctx.assetPath, FileMode.Open, FileAccess.Read); + Document doc = null; + try + { + UnityEngine.Profiling.Profiler.BeginSample("OnImportAsset"); + + UnityEngine.Profiling.Profiler.BeginSample("PsdLoad"); + doc = PaintDotNet.Data.PhotoshopFileType.PsdLoad.Load(fileStream); + UnityEngine.Profiling.Profiler.EndSample(); + + ValidatePSDLayerId(doc); + + m_DocumentSize = new Vector2Int(doc.width, doc.height); + bool singleSpriteMode = m_TextureImporterSettings.textureType == TextureImporterType.Sprite && m_TextureImporterSettings.spriteMode != (int)SpriteImportMode.Multiple; + EnsureSingleSpriteExist(); + + if (m_TextureImporterSettings.textureType != TextureImporterType.Sprite || + m_MosaicLayers == false || singleSpriteMode) + { + var image = new NativeArray(doc.width * doc.height, Allocator.Persistent); + try + { + var spriteImportData = GetSpriteImportData(); + FlattenImageTask.Execute(doc.Layers, m_ImportHiddenLayers, doc.width, doc.height, image); + + int spriteCount = spriteDataCount; + int spriteIndexStart = 1; + + if (spriteImportData.Count <= 0 || spriteImportData[0] == null) + { + spriteImportData.Add(new SpriteMetaData()); + } + spriteImportData[0].name = System.IO.Path.GetFileNameWithoutExtension(ctx.assetPath) + "_1"; + spriteImportData[0].alignment = (SpriteAlignment)m_TextureImporterSettings.spriteAlignment; + spriteImportData[0].border = m_TextureImporterSettings.spriteBorder; + spriteImportData[0].pivot = m_TextureImporterSettings.spritePivot; + spriteImportData[0].rect = new Rect(0, 0, doc.width, doc.height); + if (singleSpriteMode) + { + spriteCount = 1; + spriteIndexStart = 0; + } + textureActualWidth = doc.width; + textureActualHeight = doc.height; + var output = ImportTexture(ctx, image, doc.width, doc.height, spriteIndexStart, spriteCount); + RegisterAssets(ctx, output); + } + finally + { + image.Dispose(); + } + } + else + { + ImportFromLayers(ctx, doc); + } + } + finally + { + fileStream.Close(); + if (doc != null) + doc.Dispose(); + UnityEngine.Profiling.Profiler.EndSample(); + EditorUtility.SetDirty(this); + } + + + // Debug Profiler. + // UnityEngine.Profiling.Memory.Experimental.MemoryProfiler.TakeSnapshot("snapshot.snap", MemorySnapshotFinish, CaptureFlags.ManagedObjects | CaptureFlags.NativeObjects | CaptureFlags.NativeAllocations | CaptureFlags.NativeStackTraces); + } + + static void ValidatePSDLayerId(List layers, UniqueNameGenerator uniqueNameGenerator) + { + for (int i = 0; i < layers.Count; ++i) + { + if (uniqueNameGenerator.ContainHash(layers[i].LayerID)) + { + var importWarning = string.Format("Layer {0}: LayerId is not unique. Mapping will be done by Layer's name.", layers[i].Name); + var layerName = uniqueNameGenerator.GetUniqueName(layers[i].Name); + if (layerName != layers[i].Name) + importWarning += "\nLayer names are not unique. Please ensure they are unique to for SpriteRect to be mapped back correctly."; + layers[i].LayerID = layerName.GetHashCode(); + Debug.LogWarning(importWarning); + } + else + uniqueNameGenerator.AddHash(layers[i].LayerID); + if (layers[i].ChildLayer != null) + { + ValidatePSDLayerId(layers[i].ChildLayer, uniqueNameGenerator); + } + } + } + + + void ValidatePSDLayerId(Document doc) + { + UniqueNameGenerator uniqueNameGenerator = new UniqueNameGenerator(); + + ValidatePSDLayerId(doc.Layers, uniqueNameGenerator); + } + + TextureGenerationOutput ImportTexture(AssetImportContext ctx, NativeArray imageData, int textureWidth, int textureHeight, int spriteStart, int spriteCount) + { + if (!imageData.IsCreated || imageData.Length == 0) + return new TextureGenerationOutput(); + + UnityEngine.Profiling.Profiler.BeginSample("ImportTexture"); + var platformSettings = GetPlatformTextureSettings(ctx.selectedBuildTarget); + + var textureSettings = m_TextureImporterSettings.ExtractTextureSettings(); + textureSettings.assetPath = ctx.assetPath; + textureSettings.enablePostProcessor = true; + textureSettings.containsAlpha = true; + textureSettings.hdr = false; + + var textureAlphaSettings = m_TextureImporterSettings.ExtractTextureAlphaSettings(); + var textureMipmapSettings = m_TextureImporterSettings.ExtractTextureMipmapSettings(); + var textureCubemapSettings = m_TextureImporterSettings.ExtractTextureCubemapSettings(); + var textureWrapSettings = m_TextureImporterSettings.ExtractTextureWrapSettings(); + + TextureGenerationOutput output; + switch (m_TextureImporterSettings.textureType) + { + case TextureImporterType.Default: + output = TextureGeneratorHelper.GenerateTextureDefault(imageData, textureWidth, textureHeight, textureSettings, platformSettings, textureAlphaSettings, textureMipmapSettings, textureCubemapSettings, textureWrapSettings); + break; + case TextureImporterType.NormalMap: + var textureNormalSettings = m_TextureImporterSettings.ExtractTextureNormalSettings(); + output = TextureGeneratorHelper.GenerateNormalMap(imageData, textureWidth, textureHeight, textureSettings, platformSettings, textureNormalSettings, textureMipmapSettings, textureCubemapSettings, textureWrapSettings); + break; + case TextureImporterType.GUI: + output = TextureGeneratorHelper.GenerateTextureGUI(imageData, textureWidth, textureHeight, textureSettings, platformSettings, textureAlphaSettings, textureMipmapSettings, textureWrapSettings); + break; + case TextureImporterType.Sprite: + var textureSpriteSettings = m_TextureImporterSettings.ExtractTextureSpriteSettings(); + textureSpriteSettings.packingTag = m_SpritePackingTag; + textureSpriteSettings.qualifyForPacking = !string.IsNullOrEmpty(m_SpritePackingTag); + textureSpriteSettings.spriteSheetData = new UnityEditor.Experimental.AssetImporters.SpriteImportData[spriteCount]; + textureSettings.npotScale = TextureImporterNPOTScale.None; + textureSettings.secondaryTextures = secondaryTextures; + var spriteImportData = GetSpriteImportData(); + for (int i = 0; i < spriteCount; ++i) + { + //AutoGenerateSpriteSkinData(m_SpriteImportData[spriteStart + i]); + textureSpriteSettings.spriteSheetData[i] = spriteImportData[spriteStart + i]; + } + output = TextureGeneratorHelper.GenerateTextureSprite(imageData, textureWidth, textureHeight, textureSettings, platformSettings, textureSpriteSettings, textureAlphaSettings, textureMipmapSettings, textureWrapSettings); + break; + case TextureImporterType.Cursor: + output = TextureGeneratorHelper.GenerateTextureCursor(imageData, textureWidth, textureHeight, textureSettings, platformSettings, textureAlphaSettings, textureMipmapSettings, textureWrapSettings); + break; + case TextureImporterType.Cookie: + output = TextureGeneratorHelper.GenerateCookie(imageData, textureWidth, textureHeight, textureSettings, platformSettings, textureAlphaSettings, textureMipmapSettings, textureCubemapSettings, textureWrapSettings); + break; + case TextureImporterType.Lightmap: + output = TextureGeneratorHelper.GenerateLightmap(imageData, textureWidth, textureHeight, textureSettings, platformSettings, textureMipmapSettings, textureWrapSettings); + break; + case TextureImporterType.SingleChannel: + output = TextureGeneratorHelper.GenerateTextureSingleChannel(imageData, textureWidth, textureHeight, textureSettings, platformSettings, textureAlphaSettings, textureMipmapSettings, textureCubemapSettings, textureWrapSettings); + break; + default: + Debug.LogAssertion("Unknown texture type for import"); + output = default(TextureGenerationOutput); + break; + } + UnityEngine.Profiling.Profiler.EndSample(); + return output; + } + + void AutoGenerateSpriteSkinData(SpriteMetaData metaData) + { + //If bone data exist but skinning data doesn't exist, auto generate them + if (metaData.spriteBone != null && metaData.spriteBone.Count > 0 && + (metaData.vertices == null || metaData.vertices.Count == 0)) + { + var spriteMeshDataController = new SpriteMeshDataController(); + var smd = new SpriteMeshData(); + smd.spriteID = metaData.spriteID; + smd.frame = metaData.rect; + smd.pivot = metaData.pivot; + smd.bones = ModuleUtility.CreateSpriteBoneData(metaData.spriteBone.ToArray(), Matrix4x4.TRS(metaData.rect.position, Quaternion.identity, Vector3.one)); + spriteMeshDataController.spriteMeshData = smd; + spriteMeshDataController.OutlineFromAlpha(new OutlineGenerator(), GetDataProvider(), 0.05f, 200); + spriteMeshDataController.Triangulate(new Triangulator()); + spriteMeshDataController.Subdivide(new Triangulator(), 0.25f); + spriteMeshDataController.CalculateWeights(new BoundedBiharmonicWeightsGenerator(), null, 0.01f); + spriteMeshDataController.SortTrianglesByDepth(); + + List vmd = new List(smd.vertices.Count); + foreach (var v in smd.vertices) + vmd.Add(new Vertex2DMetaData() { position = v.position - smd.frame.position, boneWeight = v.editableBoneWeight.ToBoneWeight(true) }); + List emd = new List(smd.edges.Count); + foreach (var e in smd.edges) + emd.Add(new Vector2Int(e.index1, e.index2)); + + metaData.vertices = vmd; + metaData.indices = smd.indices.ToArray(); + metaData.edges = emd.ToArray(); + } + } + + string GetUniqueSpriteName(string name, List namehash) + { + if (m_KeepDupilcateSpriteName) + return name; + return GetUniqueName(name, namehash); + } + + void ImportFromLayers(AssetImportContext ctx, Document doc) + { + NativeArray output = default(NativeArray); + + List layerIndex = new List(); + List spriteNameHash = new List(); + var oldPsdLayers = GetPSDLayers(); + try + { + var psdLayers = new List(); + ExtractLayerTask.Execute(psdLayers, doc.Layers, m_ImportHiddenLayers); + var removedLayersSprite = oldPsdLayers.Where(x => psdLayers.FirstOrDefault(y => y.layerID == x.layerID) == null).Select(z => z.spriteID).ToArray(); + for (int i = 0; i < psdLayers.Count; ++i) + { + int j = 0; + var psdLayer = psdLayers[i]; + for (; j < oldPsdLayers.Count; ++j) + { + if (psdLayer.layerID == oldPsdLayers[j].layerID) + { + psdLayer.spriteID = oldPsdLayers[j].spriteID; + psdLayer.spriteName = oldPsdLayers[j].spriteName; + psdLayer.mosaicPosition = oldPsdLayers[j].mosaicPosition; + break; + } + } + } + + int expectedBufferLength = doc.width * doc.height; + var layerBuffers = new List>(); + for (int i = 0; i < psdLayers.Count; ++i) + { + var l = psdLayers[i]; + if (l.texture.IsCreated && l.texture.Length == expectedBufferLength) + { + layerBuffers.Add(l.texture); + layerIndex.Add(i); + } + } + + RectInt[] spritedata; + int width, height; + int padding = 4; + Vector2Int[] uvTransform; + ImagePacker.Pack(layerBuffers.ToArray(), doc.width, doc.height, padding, out output, out width, out height, out spritedata, out uvTransform); + var spriteImportData = GetSpriteImportData(); + if (spriteImportData.Count <= 0 || shouldResliceFromLayer) + { + var newSpriteMeta = new List(); + + for (int i = 0; i < spritedata.Length && i < layerIndex.Count; ++i) + { + var spriteSheet = spriteImportData.FirstOrDefault(x => x.spriteID == psdLayers[layerIndex[i]].spriteID); + if (spriteSheet == null) + { + spriteSheet = new SpriteMetaData(); + spriteSheet.border = Vector4.zero; + spriteSheet.alignment = (SpriteAlignment)m_TextureImporterSettings.spriteAlignment; + spriteSheet.pivot = m_TextureImporterSettings.spritePivot; + } + + psdLayers[layerIndex[i]].spriteName = GetUniqueSpriteName(psdLayers[layerIndex[i]].name, spriteNameHash); + spriteSheet.name = psdLayers[layerIndex[i]].spriteName; + spriteSheet.rect = new Rect(spritedata[i].x, spritedata[i].y, spritedata[i].width, spritedata[i].height); + spriteSheet.uvTransform = uvTransform[i]; + + psdLayers[layerIndex[i]].spriteID = spriteSheet.spriteID; + psdLayers[layerIndex[i]].mosaicPosition = spritedata[i].position; + newSpriteMeta.Add(spriteSheet); + } + spriteImportData.Clear(); + spriteImportData.AddRange(newSpriteMeta); + } + else + { + spriteImportData.RemoveAll(x => removedLayersSprite.Contains(x.spriteID)); + + // First look for any user created SpriteRect and add those into the name hash + foreach (var spriteData in spriteImportData) + { + var psdLayer = psdLayers.FirstOrDefault(x => x.spriteID == spriteData.spriteID); + if (psdLayer == null) + spriteNameHash.Add(spriteData.name.GetHashCode()); + } + + foreach (var spriteData in spriteImportData) + { + var psdLayer = psdLayers.FirstOrDefault(x => x.spriteID == spriteData.spriteID); + if (psdLayer == null) + spriteData.uvTransform = new Vector2Int((int)spriteData.rect.position.x, (int)spriteData.rect.position.y); + // If it is user created rect or the name has been changed before + // add it into the spriteNameHash and we don't copy it over from the layer + if (psdLayer == null || psdLayer.spriteName != spriteData.name) + spriteNameHash.Add(spriteData.name.GetHashCode()); + + // If the sprite name has not been changed, we ensure the new + // layer name is still unique and use it as the sprite name + if (psdLayer != null && psdLayer.spriteName == spriteData.name) + { + psdLayer.spriteName = GetUniqueSpriteName(psdLayer.name, spriteNameHash); + spriteData.name = psdLayer.spriteName; + } + } + + //Update names for those user has not changed and add new sprite rect based on PSD file. + for (int k = 0; k < layerIndex.Count; ++k) + { + int i = layerIndex[k]; + var spriteSheet = spriteImportData.FirstOrDefault(x => x.spriteID == psdLayers[i].spriteID); + var inOldLayer = oldPsdLayers.FindIndex(x => x.layerID == psdLayers[i].layerID) != -1; + if (spriteSheet == null && !inOldLayer) + { + spriteSheet = new SpriteMetaData(); + spriteImportData.Add(spriteSheet); + spriteSheet.rect = new Rect(spritedata[k].x, spritedata[k].y, spritedata[k].width, spritedata[k].height); + spriteSheet.border = Vector4.zero; + spriteSheet.alignment = (SpriteAlignment)m_TextureImporterSettings.spriteAlignment; + spriteSheet.pivot = m_TextureImporterSettings.spritePivot; + psdLayers[i].spriteName = GetUniqueSpriteName(psdLayers[i].name, spriteNameHash); + spriteSheet.name = psdLayers[i].spriteName; + } + else if (spriteSheet != null) + { + var r = spriteSheet.rect; + r.position = spriteSheet.rect.position - psdLayers[i].mosaicPosition + spritedata[k].position; + spriteSheet.rect = r; + } + + if (spriteSheet != null) + { + spriteSheet.uvTransform = uvTransform[k]; + psdLayers[i].spriteID = spriteSheet.spriteID; + psdLayers[i].mosaicPosition = spritedata[k].position; + } + } + } + + foreach (var l in oldPsdLayers) + l.Dispose(); + oldPsdLayers.Clear(); + + oldPsdLayers.AddRange(psdLayers); + m_ImportedTextureHeight = textureActualHeight = height; + m_ImportedTextureWidth = textureActualWidth = width; + var generatedTexture = ImportTexture(ctx, output, width, height, 0, spriteImportData.Count); + + if (generatedTexture.texture) + { + m_ImportedTextureHeight = generatedTexture.texture.height; + m_ImportedTextureWidth = generatedTexture.texture.width; + } + + RegisterAssets(ctx, generatedTexture); + } + finally + { + if (output.IsCreated) + output.Dispose(); + foreach (var l in oldPsdLayers) + l.Dispose(); + } + + } + + void MemorySnapshotFinish(string path, bool done) + { + + } + + void EnsureSingleSpriteExist() + { + if (m_SpriteImportData.Count <= 0) + m_SpriteImportData.Add(new SpriteMetaData()); // insert default for single sprite mode + } + + internal TextureImporterPlatformSettings GetPlatformTextureSettings(BuildTarget buildTarget) + { + var buildTargetName = TexturePlatformSettingsHelper.GetBuildTargetName(buildTarget); + TextureImporterPlatformSettings platformSettings = null; + platformSettings = m_PlatformSettings.SingleOrDefault(x => x.name == buildTargetName && x.overridden == true); + platformSettings = platformSettings ?? m_PlatformSettings.SingleOrDefault(x => x.name == TexturePlatformSettingsHelper.defaultPlatformName); + + if (platformSettings == null) + { + platformSettings = new TextureImporterPlatformSettings(); + platformSettings.name = buildTargetName; + platformSettings.overridden = false; + } + return platformSettings; + } + + void RegisterAssets(AssetImportContext ctx, TextureGenerationOutput output) + { + List assetNameHash = new List(); + if (!string.IsNullOrEmpty(output.importInspectorWarnings)) + { + Debug.LogWarning(output.importInspectorWarnings); + } + if (output.importWarnings != null && output.importWarnings.Length != 0) + { + foreach (var warning in output.importWarnings) + Debug.LogWarning(warning); + } + if (output.thumbNail == null) + Debug.LogWarning("Thumbnail generation fail"); + if (output.texture == null) + { + throw new Exception("Texture import fail"); + } + + var assetName = GetUniqueName(System.IO.Path.GetFileNameWithoutExtension(ctx.assetPath), assetNameHash, true); + // Setup all fixed name on the hash table + if (string.IsNullOrEmpty(m_TextureAssetName)) + m_TextureAssetName = GetUniqueName(string.Format("{0} Texture",assetName), assetNameHash, true); + if (string.IsNullOrEmpty(m_PrefabAssetName)) + m_PrefabAssetName = GetUniqueName(string.Format("{0} Prefab", assetName), assetNameHash, true); + if (string.IsNullOrEmpty(m_SpriteLibAssetName)) + m_SpriteLibAssetName = GetUniqueName(string.Format("{0} Sprite Lib", assetName), assetNameHash, true); + + output.texture.name = assetName; + ctx.AddObjectToAsset(m_TextureAssetName, output.texture, output.thumbNail); + UnityEngine.Object mainAsset = output.texture; + + + if (output.sprites != null) + { + var slAsset = ProduceSpriteLibAsset(output.sprites); + + if (shouldProduceGameObject) + { + GameObject prefab = null; + if (m_PaperDollMode) + prefab = OnProducePaperDollPrefab(m_TextureAssetName, output.sprites, slAsset); + else + prefab = OnProducePrefab(m_TextureAssetName, output.sprites, slAsset); + if (prefab != null) + { + ctx.AddObjectToAsset(m_PrefabAssetName, prefab); + mainAsset = prefab; + } + } + + foreach (var s in output.sprites) + { + var spriteAssetName = GetUniqueName(s.GetSpriteID().ToString(), assetNameHash, false, s); + ctx.AddObjectToAsset(spriteAssetName, s); + } + + if (slAsset != null) + { + slAsset.name = assetName; + ctx.AddObjectToAsset(m_SpriteLibAssetName, slAsset); + } + } + ctx.SetMainObject(mainAsset); + } + + bool SpriteIsMainFromSpriteLib(string spriteId, out string categoryName) + { + categoryName = ""; + if (m_SpriteCategoryList.categories != null) + { + foreach (var category in m_SpriteCategoryList.categories) + { + var index = category.labels.FindIndex(x => x.spriteId == spriteId); + if (index == 0) + { + categoryName = category.name; + return true; + } + if (index > 0) + return false; + } + } + return true; + } + + void BuildGroupGameObject(List psdGroup, int index, Transform root) + { + var spriteData = GetSpriteImportData().FirstOrDefault(x => x.spriteID == psdGroup[index].spriteID); + if (psdGroup[index].gameObject == null) + { + if (m_GenerateGOHierarchy || (!psdGroup[index].spriteID.Empty() && psdGroup[index].isGroup == false)) + { + // Determine if need to create GameObject i.e. if the sprite is not in a SpriteLib or if it is the first one + string categoryName; + var b = SpriteIsMainFromSpriteLib(psdGroup[index].spriteID.ToString(), out categoryName); + string goName = string.IsNullOrEmpty(categoryName) ? spriteData != null ? spriteData.name : psdGroup[index].name : categoryName; + if (b) + psdGroup[index].gameObject = m_GameObjectFactory.CreateGameObject(goName); + } + if (psdGroup[index].parentIndex >= 0 && m_GenerateGOHierarchy) + { + BuildGroupGameObject(psdGroup, psdGroup[index].parentIndex, root); + root = psdGroup[psdGroup[index].parentIndex].gameObject.transform; + } + + if (psdGroup[index].gameObject != null) + psdGroup[index].gameObject.transform.SetParent(root); + } + } + + bool shouldProduceGameObject + { + get { return m_CharacterMode && m_MosaicLayers && spriteImportMode == SpriteImportMode.Multiple; } + } + + bool shouldResliceFromLayer + { + get { return m_ResliceFromLayer && m_MosaicLayers && spriteImportMode == SpriteImportMode.Multiple; } + } + + bool characterMode + { + get { return mosaicMode && m_CharacterMode == true; } + } + + float definitionScale + { + get + { + float definitionScaleW = m_ImportedTextureWidth / (float)textureActualWidth; + float definitionScaleH = m_ImportedTextureHeight / (float)textureActualHeight; + return Mathf.Min(definitionScaleW, definitionScaleH); + } + } + + private Vector2 GetPivotPoint(Rect rect, SpriteAlignment alignment) + { + switch (alignment) + { + case SpriteAlignment.TopLeft: + return new Vector2(rect.xMin, rect.yMax); + + case SpriteAlignment.TopCenter: + return new Vector2(rect.center.x, rect.yMax); + + case SpriteAlignment.TopRight: + return new Vector2(rect.xMax, rect.yMax); + + case SpriteAlignment.LeftCenter: + return new Vector2(rect.xMin, rect.center.y); + + case SpriteAlignment.Center: + return new Vector2(rect.center.x, rect.center.y); + + case SpriteAlignment.RightCenter: + return new Vector2(rect.xMax, rect.center.y); + + case SpriteAlignment.BottomLeft: + return new Vector2(rect.xMin, rect.yMin); + + case SpriteAlignment.BottomCenter: + return new Vector2(rect.center.x, rect.yMin); + + case SpriteAlignment.BottomRight: + return new Vector2(rect.xMax, rect.yMin); + + case SpriteAlignment.Custom: + return new Vector2(m_DocumentPivot.x * rect.width, m_DocumentPivot.y * rect.height); + } + return Vector2.zero; + } + + void CreateBoneGO(int index, SpriteBone[] bones, BoneGO[] bonesGO, Transform defaultRoot) + { + if (bonesGO[index].go != null) + return; + var bone = bones[index]; + if (bone.parentId != -1 && bonesGO[bone.parentId].go == null) + CreateBoneGO(bone.parentId, bones, bonesGO, defaultRoot); + + var go = m_GameObjectFactory.CreateGameObject(bone.name); + if (bone.parentId == -1) + go.transform.SetParent(defaultRoot); + else + go.transform.SetParent(bonesGO[bone.parentId].go.transform); + go.transform.localPosition = bone.position * 1 / pixelsPerUnit; + go.transform.localRotation = bone.rotation; + bonesGO[index] = new BoneGO() + { + go = go, + index = index + }; + } + + BoneGO[] CreateBonesGO(Transform root) + { + if (characterMode) + { + var characterSkeleton = GetDataProvider().GetCharacterData(); + var bones = characterSkeleton.bones; + if (bones != null) + { + var boneGOs = new BoneGO[bones.Length]; + for (int i = 0; i < bones.Length; ++i) + { + CreateBoneGO(i, bones, boneGOs, root); + } + return boneGOs; + } + } + return new BoneGO[0]; + } + + void GetSpriteLiblabel(string spriteId, out string category, out string label) + { + category = ""; + label = ""; + var index = -1; + foreach (var cat in m_SpriteCategoryList.categories) + { + index = cat.labels.FindIndex(x => x.spriteId == spriteId); + if (index != -1) + { + category = cat.name; + label = cat.labels[index].name; + break; + } + } + } + + GameObject OnProducePaperDollPrefab(string assetname, Sprite[] sprites, SpriteLibraryAsset spriteLib) + { + GameObject root = null; + CharacterData? characterSkeleton = characterMode ? new CharacterData ? (GetDataProvider().GetCharacterData()) : null; + if (sprites != null && sprites.Length > 0) + { + root = new GameObject(); + root.name = assetname + "_GO"; + var spriteImportData = GetSpriteImportData(); + var psdLayers = GetPSDLayers(); + var boneGOs = CreateBonesGO(root.transform); + if (spriteLib != null) + root.AddComponent().spriteLibraryAsset = spriteLib; + for (int i = 0; i < sprites.Length; ++i) + { + string categoryName; + if (SpriteIsMainFromSpriteLib(sprites[i].GetSpriteID().ToString(), out categoryName)) + { + var spriteBones = m_CharacterData.parts.FirstOrDefault(x => new GUID(x.spriteId) == sprites[i].GetSpriteID()).bones; + var rootBone = root; + if (spriteBones != null && spriteBones.Any()) + { + var b = spriteBones.Where(x => x >= 0 && x < boneGOs.Length).Select(x => boneGOs[x]).OrderBy(x => x.index); + if (b.Any()) + rootBone = b.First().go; + } + + var srGameObject = m_GameObjectFactory.CreateGameObject(string.IsNullOrEmpty(categoryName) ? sprites[i].name : categoryName); + var sr = srGameObject.AddComponent(); + sr.sprite = sprites[i]; + sr.sortingOrder = psdLayers.Count - psdLayers.FindIndex(x => x.spriteID == sprites[i].GetSpriteID()); + srGameObject.transform.parent = rootBone.transform; + var spriteMetaData = spriteImportData.FirstOrDefault(x => x.spriteID == sprites[i].GetSpriteID()); + if (spriteMetaData != null) + { + var uvTransform = spriteMetaData.uvTransform; + var outlineOffset = new Vector2(spriteMetaData.rect.x - uvTransform.x + (spriteMetaData.pivot.x * spriteMetaData.rect.width), + spriteMetaData.rect.y - uvTransform.y + (spriteMetaData.pivot.y * spriteMetaData.rect.height)) * definitionScale / sprites[i].pixelsPerUnit; + srGameObject.transform.position = new Vector3(outlineOffset.x, outlineOffset.y, 0); + } + var category = ""; + var labelName = ""; + GetSpriteLiblabel(sprites[i].GetSpriteID().ToString(), out category, out labelName); + if (!string.IsNullOrEmpty(category) && !string.IsNullOrEmpty(labelName)) + { + var sresolver = srGameObject.AddComponent(); + sresolver.SetCategoryAndLabel(category, labelName); + sresolver.ResolveSpriteToSpriteRenderer(); + } + } + } + } + return root; + } + + internal void SetPlatformTextureSettings(TextureImporterPlatformSettings platformSettings) + { + var index = m_PlatformSettings.FindIndex(x => x.name == platformSettings.name); + if(index < 0) + m_PlatformSettings.Add(platformSettings); + else + m_PlatformSettings[index] = platformSettings; + } + + internal TextureImporterPlatformSettings[] GetAllPlatformSettings() + { + return m_PlatformSettings.ToArray(); + } + + GameObject OnProducePrefab(string assetname, Sprite[] sprites, SpriteLibraryAsset spriteLib) + { + GameObject root = null; + CharacterData? characterSkeleton = characterMode ? new CharacterData ? (GetDataProvider().GetCharacterData()) : null; + if (sprites != null && sprites.Length > 0) + { + var spriteImportData = GetSpriteImportData(); + root = new GameObject(); + root.name = assetname + "_GO"; + if (spriteLib != null) + root.AddComponent().spriteLibraryAsset = spriteLib; + + var psdLayers = GetPSDLayers(); + for (int i = 0; i < psdLayers.Count; ++i) + { + BuildGroupGameObject(psdLayers, i, root.transform); + } + var boneGOs = CreateBonesGO(root.transform); + for (int i = 0; i < psdLayers.Count; ++i) + { + var l = psdLayers[i]; + GUID layerSpriteID = l.spriteID; + var sprite = sprites.FirstOrDefault(x => x.GetSpriteID() == layerSpriteID); + var spriteMetaData = spriteImportData.FirstOrDefault(x => x.spriteID == layerSpriteID); + if (sprite != null && spriteMetaData != null && l.gameObject != null) + { + var spriteRenderer = l.gameObject.AddComponent(); + spriteRenderer.sprite = sprite; + spriteRenderer.sortingOrder = psdLayers.Count - i; + var uvTransform = spriteMetaData.uvTransform; + var outlineOffset = new Vector2(spriteMetaData.rect.x - uvTransform.x + (spriteMetaData.pivot.x * spriteMetaData.rect.width), + spriteMetaData.rect.y - uvTransform.y + (spriteMetaData.pivot.y * spriteMetaData.rect.height)) * definitionScale / sprite.pixelsPerUnit; + l.gameObject.transform.position = new Vector3(outlineOffset.x, outlineOffset.y, 0); + + if (characterSkeleton != null) + { + var part = characterSkeleton.Value.parts.FirstOrDefault(x => x.spriteId == spriteMetaData.spriteID.ToString()); + if (part.bones != null && part.bones.Length > 0) + { + var spriteSkin = l.gameObject.AddComponent(); + if (spriteRenderer.sprite != null && spriteRenderer.sprite.GetBindPoses().Length > 0) + { + var spriteBones = m_CharacterData.parts.FirstOrDefault(x => new GUID(x.spriteId) == spriteRenderer.sprite.GetSpriteID()).bones.Where(x => x >= 0 && x < boneGOs.Length).Select(x => boneGOs[x]); + if (spriteBones.Any()) + { + spriteSkin.rootBone = spriteBones.OrderBy(x => x.index).First().go.transform; + spriteSkin.boneTransforms = spriteBones.Select(x => x.go.transform).ToArray(); + if (spriteSkin.isValid) + spriteSkin.CalculateBounds(); + } + } + } + } + + var category = ""; + var labelName = ""; + GetSpriteLiblabel(layerSpriteID.ToString(), out category, out labelName); + if (!string.IsNullOrEmpty(category) && !string.IsNullOrEmpty(labelName)) + { + var sresolver = l.gameObject.AddComponent(); + sresolver.SetCategoryAndLabel(category, labelName); + sresolver.ResolveSpriteToSpriteRenderer(); + } + } + } + + var prefabBounds = new Rect(0 , 0, m_DocumentSize.x / pixelsPerUnit, m_DocumentSize.y / pixelsPerUnit); + var documentPivot = (Vector3)GetPivotPoint(prefabBounds, m_DocumentAlignment); + for (int i = 0; i < psdLayers.Count; ++i) + { + var l = psdLayers[i]; + if (l.gameObject == null || l.gameObject.GetComponent() == null) + continue; + var p = l.gameObject.transform.localPosition; + p -= documentPivot; + l.gameObject.transform.localPosition = p; + } + for (int i = 0; i < boneGOs.Length; ++i) + { + if (boneGOs[i].go.transform.parent != root.transform) + continue; + var p = boneGOs[i].go.transform.position; + p -= documentPivot; + boneGOs[i].go.transform.position = p; + } + } + + return root; + } + + Bounds? GetBoundingBox(GameObject root) + { + Bounds? prefabBounds1 = null; + var sr = root.GetComponent(); + if (sr != null) + { + prefabBounds1 = sr.bounds; + } + for (int i = 0; i < root.transform.childCount; ++i) + { + var b = GetBoundingBox(root.transform.GetChild(i).gameObject); + if (prefabBounds1 == null) + prefabBounds1 = b; + else + { + if (b.HasValue) + { + var bb = prefabBounds1.Value; + bb.Encapsulate(b.Value); + prefabBounds1 = bb; + } + } + } + return prefabBounds1; + } + + bool CleanUpGameobjectsWithOutRig(GameObject root) + { + var sr = root.GetComponent(); + var canDelete = true; + if (sr != null && sr.sprite != null) + { + try + { + var bones = GetDataProvider().GetBones(sr.sprite.GetSpriteID()); + canDelete = bones == null || bones.Count == 0; + } + catch (Exception e) + { + Debug.LogError(e); + } + } + + + List cleanup = new List(); + for (int i = 0; i < root.transform.childCount; ++i) + { + var go = root.transform.GetChild(i); + if (CleanUpGameobjectsWithOutRig(go.gameObject)) + cleanup.Add(go.gameObject); + } + + for (int i = 0; i < cleanup.Count; ++i) + GameObject.DestroyImmediate(cleanup[i]); + cleanup.Clear(); + + if (root.transform.childCount == 0 && canDelete) + return true; + + return false; + } + + static string SanitizeName(string name) + { + string newName = null; + // We can't create asset name with these name. + if ((name.Length == 2 && name[0] == '.' && name[1] == '.') + || (name.Length == 1 && name[0] == '.') + || (name.Length == 1 && name[0] == '/')) + newName += name + "_"; + + if (!string.IsNullOrEmpty(newName)) + { + Debug.LogWarning(string.Format("File contains layer with invalid name for generating asset. {0} is renamed to {1}", name, newName)); + return newName; + } + return name; + } + + static string GetUniqueName(string name, List stringHash, bool logNewNameGenerated = false, UnityEngine.Object context = null) + { + string uniqueName = string.Copy(SanitizeName(name)); + int index = 1; + while (true) + { + int hash = uniqueName.GetHashCode(); + var p = stringHash.Where(x => x == hash); + if (!p.Any()) + { + stringHash.Add(hash); + if (logNewNameGenerated && name != uniqueName) + Debug.Log(string.Format("Asset name {0} is changed to {1} to ensure uniqueness", name, uniqueName), context); + return uniqueName; + } + uniqueName = string.Format("{0}_{1}", name, index); + ++index; + } + } + + // ISpriteEditorDataProvider interface + internal SpriteImportMode spriteImportMode + { + get + { + return m_TextureImporterSettings.textureType != TextureImporterType.Sprite ? + SpriteImportMode.None : + (SpriteImportMode)m_TextureImporterSettings.spriteMode; + } + } + + SpriteImportMode ISpriteEditorDataProvider.spriteImportMode => spriteImportMode; + + internal int spriteDataCount + { + get + { + var spriteImportData = GetSpriteImportData(); + if (mosaicMode) + return spriteImportData.Count; + if (spriteImportMode != SpriteImportMode.Multiple) + return 1; + return spriteImportData.Count - 1; + } + } + + internal UnityEngine.Object targetObject + { + get { return this; } + } + UnityEngine.Object ISpriteEditorDataProvider.targetObject => targetObject; + + internal float pixelsPerUnit + { + get { return m_TextureImporterSettings.spritePixelsPerUnit; } + } + + float ISpriteEditorDataProvider.pixelsPerUnit =>pixelsPerUnit; + + internal T GetDataProvider() where T : class + { + if (typeof(T) == typeof(ISpriteBoneDataProvider)) + { + return new SpriteBoneDataProvider { dataProvider = this } as T; + } + if (typeof(T) == typeof(ISpriteMeshDataProvider)) + { + return new SpriteMeshDataProvider { dataProvider = this } as T; + } + if (typeof(T) == typeof(ISpriteOutlineDataProvider)) + { + return new SpriteOutlineDataProvider { dataProvider = this } as T; + } + if (typeof(T) == typeof(ISpritePhysicsOutlineDataProvider)) + { + return new SpritePhysicsOutlineProvider { dataProvider = this } as T; + } + if (typeof(T) == typeof(ITextureDataProvider)) + { + return new TextureDataProvider { dataProvider = this } as T; + } + if (typeof(T) == typeof(ICharacterDataProvider)) + { + return characterMode ? new CharacterDataProvider { dataProvider = this } as T : null; + } + if (typeof(T) == typeof(ISpriteLibDataProvider)) + { + return new SpriteLibraryDataProvider() { dataProvider = this } as T; + } + if (typeof(T) == typeof(ISecondaryTextureDataProvider)) + { + return new SecondaryTextureDataProvider() { dataProvider = this } as T; + } + else + return this as T; + } + + T ISpriteEditorDataProvider.GetDataProvider() + { + return GetDataProvider(); + } + + internal bool HasDataProvider(Type type) + { + if (characterMode && type == typeof(ICharacterDataProvider)) + return true; + if (type == typeof(ISpriteBoneDataProvider) || + type == typeof(ISpriteMeshDataProvider) || + type == typeof(ISpriteOutlineDataProvider) || + type == typeof(ISpritePhysicsOutlineDataProvider) || + type == typeof(ITextureDataProvider) || + type == typeof(ISpriteLibDataProvider) || + type == typeof(ISecondaryTextureDataProvider)) + { + return true; + } + else + return type.IsAssignableFrom(GetType()); + } + + bool ISpriteEditorDataProvider.HasDataProvider(Type type) + { + return HasDataProvider(type); + } + + internal void AddSpriteData(SpriteRect spriteRect) + { + if (spriteImportMode != SpriteImportMode.Multiple) + Debug.LogWarning("Can only add sprite data when import mode is multiple"); + else + { + GetSpriteImportData().Add(new SpriteMetaData(spriteRect)); + } + } + + internal void DeleteSpriteData(SpriteRect spriteRect) + { + if (spriteImportMode != SpriteImportMode.Multiple) + Debug.LogWarning("Can only add sprite data when import mode is multiple"); + else + { + var spriteImportData = GetSpriteImportData(); + int index = spriteImportData.FindIndex(x => x.spriteID == spriteRect.spriteID); + Assert.AreEqual(0, index, "Cannot delete Sprite from single sprite mode"); + spriteImportData.RemoveAt(index); + } + } + + internal int GetSpriteDataIndex(GUID guid) + { + switch (spriteImportMode) + { + case SpriteImportMode.Single: + case SpriteImportMode.Polygon: + return 0; + case SpriteImportMode.Multiple: + { + var spriteImportData = GetSpriteImportData(); + return spriteImportData.FindIndex(x => x.spriteID == guid); + } + default: + throw new InvalidOperationException("GUID not found"); + } + } + + internal void Apply() + { + // Do this so that asset change save dialog will not show + var originalValue = EditorPrefs.GetBool("VerifySavingAssets", false); + EditorPrefs.SetBool("VerifySavingAssets", false); + AssetDatabase.ForceReserializeAssets(new string[] { assetPath }, ForceReserializeAssetsOptions.ReserializeMetadata); + EditorPrefs.SetBool("VerifySavingAssets", originalValue); + } + + void ISpriteEditorDataProvider.Apply() + { + Apply(); + } + + internal void InitSpriteEditorDataProvider() {} + void ISpriteEditorDataProvider.InitSpriteEditorDataProvider() + { + InitSpriteEditorDataProvider(); + } + + internal SpriteRect[] GetSpriteRects() + { + var spriteImportData = GetSpriteImportData(); + var skip = mosaicMode ? 0 : 1; + return spriteImportMode == SpriteImportMode.Multiple ? spriteImportData.Skip(skip).Select(x => new SpriteMetaData(x) as SpriteRect).ToArray() : new[] {new SpriteMetaData(spriteImportData[0]) }; + } + + SpriteRect[] ISpriteEditorDataProvider.GetSpriteRects() + { + return GetSpriteRects(); + } + + List GetSpriteImportData() + { + return mosaicMode ? (characterMode ? m_RigSpriteImportData : m_MosaicSpriteImportData) : m_SpriteImportData; + } + + internal List GetPSDLayers() + { + return mosaicMode ? (characterMode ? m_RigPSDLayers : m_MosaicPSDLayers) : null; + } + + internal SpriteMetaData[] GetSpriteMetaData() + { + var spriteImportData = GetSpriteImportData(); + var skip = mosaicMode ? 0 : 1; + return spriteImportMode == SpriteImportMode.Multiple ? spriteImportData.Skip(skip).ToArray() : new[] { new SpriteMetaData(spriteImportData[0]) }; + } + + internal SpriteRect GetSpriteDataFromAllMode(GUID guid) + { + var spriteMetaData = m_RigSpriteImportData.FirstOrDefault(x => x.spriteID == guid); + if(spriteMetaData == null) + spriteMetaData = m_MosaicSpriteImportData.FirstOrDefault(x => x.spriteID == guid); + if(spriteMetaData == null) + spriteMetaData = m_SpriteImportData.FirstOrDefault(x => x.spriteID == guid); + return spriteMetaData; + } + + internal SpriteRect GetSpriteData(GUID guid) + { + var spriteImportData = GetSpriteImportData(); + var skip = mosaicMode ? 0 : 1; + return spriteImportMode == SpriteImportMode.Multiple ? spriteImportData.Skip(skip).FirstOrDefault(x => x.spriteID == guid) : spriteImportData[0]; + } + + internal void SetSpriteRects(SpriteRect[] spriteRects) + { + var spriteImportData = GetSpriteImportData(); + if (spriteImportMode == SpriteImportMode.Multiple) + { + var singleSpriteID = mosaicMode ? new GUID() : spriteImportData[0].spriteID; + spriteImportData.RemoveAll(data => data.spriteID != singleSpriteID && spriteRects.FirstOrDefault(x => x.spriteID == data.spriteID) == null); + foreach (var sr in spriteRects) + { + var importData = spriteImportData.FirstOrDefault(x => x.spriteID == sr.spriteID); + if (importData == null) + spriteImportData.Add(new SpriteMetaData(sr)); + else + { + importData.name = sr.name; + importData.alignment = sr.alignment; + importData.border = sr.border; + importData.pivot = sr.pivot; + importData.rect = sr.rect; + } + } + } + else if (spriteRects.Length == 1 && (spriteImportMode == SpriteImportMode.Single || spriteImportMode == SpriteImportMode.Polygon)) + { + if (spriteImportData[0].spriteID == spriteRects[0].spriteID) + { + spriteImportData[0].name = spriteRects[0].name; + spriteImportData[0].alignment = spriteRects[0].alignment; + m_TextureImporterSettings.spriteAlignment = (int)spriteRects[0].alignment; + m_TextureImporterSettings.spriteBorder = spriteImportData[0].border = spriteRects[0].border; + m_TextureImporterSettings.spritePivot = spriteImportData[0].pivot = spriteRects[0].pivot; + spriteImportData[0].rect = spriteRects[0].rect; + } + else + { + spriteImportData[0] = new SpriteMetaData(spriteRects[0]); + } + } + } + + void ISpriteEditorDataProvider.SetSpriteRects(SpriteRect[] spriteRects) + { + SetSpriteRects(spriteRects); + } + + bool mosaicMode + { + get { return spriteImportMode == SpriteImportMode.Multiple && m_MosaicLayers; } + } + + internal CharacterData characterData + { + get { return m_CharacterData; } + set { m_CharacterData = value; } + } + + internal Vector2Int documentSize + { + get { return m_DocumentSize; } + } + + SpriteLibraryAsset ProduceSpriteLibAsset(Sprite[] sprites) + { + if (!characterMode || m_SpriteCategoryList.categories == null) + return null; + var sla = ScriptableObject.CreateInstance(); + sla.name = "Sprite Lib"; + sla.categories = m_SpriteCategoryList.categories.Select(x => + new SpriteLibCategory() + { + name = x.name, + categoryList = x.labels.Select(y => + { + var sprite = sprites.FirstOrDefault(z => z.GetSpriteID().ToString() == y.spriteId); + return new Categorylabel() + { + name = y.name, + sprite = sprite + }; + }).ToList() + }).ToList(); + sla.categories.RemoveAll(x => x.categoryList.Count == 0); + if (sla.categories.Count > 0) + { + sla.UpdateHashes(); + return sla; + } + return null; + } + + internal SecondarySpriteTexture[] secondaryTextures + { + get { return m_SecondarySpriteTextures; } + set { m_SecondarySpriteTextures = value; } + } + + internal void ReadTextureSettings(TextureImporterSettings dest) + { + m_TextureImporterSettings.CopyTo(dest); + } + } +} diff --git a/Editor/PSDImporter.cs.meta b/Editor/PSDImporter.cs.meta index d44cb68..c4c99ed 100644 --- a/Editor/PSDImporter.cs.meta +++ b/Editor/PSDImporter.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: b2a9591990af98743ba3ff7cf1000886 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: b2a9591990af98743ba3ff7cf1000886 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDImporterDataProvider.cs b/Editor/PSDImporterDataProvider.cs index 5fe0515..7792287 100644 --- a/Editor/PSDImporterDataProvider.cs +++ b/Editor/PSDImporterDataProvider.cs @@ -1,299 +1,299 @@ -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.Assertions; -using UnityEditor.U2D.Common; -using UnityEditor.U2D.Animation; -using System; -using UnityEditor.U2D.Sprites; -using UnityEngine.U2D; - -namespace UnityEditor.U2D.PSD -{ - internal abstract class PSDDataProvider - { - public PSDImporter dataProvider; - } - - internal class SpriteBoneDataProvider : PSDDataProvider, ISpriteBoneDataProvider - { - public List GetBones(GUID guid) - { - var sprite = ((SpriteMetaData)dataProvider.GetSpriteData(guid)); - Assert.IsNotNull(sprite, string.Format("Sprite not found for GUID:{0}", guid.ToString())); - return sprite.spriteBone != null ? sprite.spriteBone.ToList() : new List(); - } - - public void SetBones(GUID guid, List bones) - { - var sprite = dataProvider.GetSpriteData(guid); - if (sprite != null) - ((SpriteMetaData)sprite).spriteBone = bones; - } - } - - internal class TextureDataProvider : PSDDataProvider, ITextureDataProvider - { - Texture2D m_ReadableTexture; - Texture2D m_OriginalTexture; - - PSDImporter textureImporter { get { return (PSDImporter)dataProvider.targetObject; } } - - public Texture2D texture - { - get - { - if (m_OriginalTexture == null) - m_OriginalTexture = AssetDatabase.LoadAssetAtPath(textureImporter.assetPath); - return m_OriginalTexture; - } - } - - public Texture2D previewTexture - { - get { return texture; } - } - - public Texture2D GetReadableTexture2D() - { - if (m_ReadableTexture == null) - { - m_ReadableTexture = InternalEditorBridge.CreateTemporaryDuplicate(texture, texture.width, texture.height); - if (m_ReadableTexture != null) - m_ReadableTexture.filterMode = texture.filterMode; - } - return m_ReadableTexture; - } - - public void GetTextureActualWidthAndHeight(out int width, out int height) - { - width = dataProvider.textureActualWidth; - height = dataProvider.textureActualHeight; - } - } - - internal class SecondaryTextureDataProvider : PSDDataProvider, ISecondaryTextureDataProvider - { - public SecondarySpriteTexture[] textures - { - get { return dataProvider.secondaryTextures; } - set { dataProvider.secondaryTextures = value; } - } - } - - internal class SpriteOutlineDataProvider : PSDDataProvider, ISpriteOutlineDataProvider - { - public List GetOutlines(GUID guid) - { - var sprite = ((SpriteMetaData)dataProvider.GetSpriteData(guid)); - Assert.IsNotNull(sprite, string.Format("Sprite not found for GUID:{0}", guid.ToString())); - - var outline = sprite.spriteOutline; - if (outline != null) - return outline.Select(x => x.outline).ToList(); - return new List(); - } - - public void SetOutlines(GUID guid, List data) - { - var sprite = dataProvider.GetSpriteData(guid); - if (sprite != null) - ((SpriteMetaData)sprite).spriteOutline = data.Select(x => new SpriteOutline() {outline = x}).ToList(); - } - - public float GetTessellationDetail(GUID guid) - { - return ((SpriteMetaData)dataProvider.GetSpriteData(guid)).tessellationDetail; - } - - public void SetTessellationDetail(GUID guid, float value) - { - var sprite = dataProvider.GetSpriteData(guid); - if (sprite != null) - ((SpriteMetaData)sprite).tessellationDetail = value; - } - } - - internal class SpritePhysicsOutlineProvider : PSDDataProvider, ISpritePhysicsOutlineDataProvider - { - public List GetOutlines(GUID guid) - { - var sprite = ((SpriteMetaData)dataProvider.GetSpriteData(guid)); - Assert.IsNotNull(sprite, string.Format("Sprite not found for GUID:{0}", guid.ToString())); - var outline = sprite.spritePhysicsOutline; - if (outline != null) - return outline.Select(x => x.outline).ToList(); - - return new List(); - } - - public void SetOutlines(GUID guid, List data) - { - var sprite = dataProvider.GetSpriteData(guid); - if (sprite != null) - ((SpriteMetaData)sprite).spritePhysicsOutline = data.Select(x => new SpriteOutline() { outline = x }).ToList(); - } - - public float GetTessellationDetail(GUID guid) - { - return ((SpriteMetaData)dataProvider.GetSpriteData(guid)).tessellationDetail; - } - - public void SetTessellationDetail(GUID guid, float value) - { - var sprite = dataProvider.GetSpriteData(guid); - if (sprite != null) - ((SpriteMetaData)sprite).tessellationDetail = value; - } - } - - internal class SpriteMeshDataProvider : PSDDataProvider, ISpriteMeshDataProvider - { - public Vertex2DMetaData[] GetVertices(GUID guid) - { - var sprite = ((SpriteMetaData)dataProvider.GetSpriteData(guid)); - Assert.IsNotNull(sprite, string.Format("Sprite not found for GUID:{0}", guid.ToString())); - var v = sprite.vertices; - if (v != null) - return v.ToArray(); - - return new Vertex2DMetaData[0]; - } - - public void SetVertices(GUID guid, Vertex2DMetaData[] vertices) - { - var sprite = dataProvider.GetSpriteData(guid); - if (sprite != null) - ((SpriteMetaData)sprite).vertices = vertices.ToList(); - } - - public int[] GetIndices(GUID guid) - { - var sprite = ((SpriteMetaData)dataProvider.GetSpriteData(guid)); - Assert.IsNotNull(sprite, string.Format("Sprite not found for GUID:{0}", guid.ToString())); - var v = sprite.indices; - if (v != null) - return v; - - return new int[0]; - } - - public void SetIndices(GUID guid, int[] indices) - { - var sprite = dataProvider.GetSpriteData(guid); - if (sprite != null) - ((SpriteMetaData)sprite).indices = indices; - } - - public Vector2Int[] GetEdges(GUID guid) - { - var sprite = ((SpriteMetaData)dataProvider.GetSpriteData(guid)); - Assert.IsNotNull(sprite, string.Format("Sprite not found for GUID:{0}", guid.ToString())); - var v = sprite.edges; - if (v != null) - return v; - - return new Vector2Int[0]; - } - - public void SetEdges(GUID guid, Vector2Int[] edges) - { - var sprite = dataProvider.GetSpriteData(guid); - if (sprite != null) - ((SpriteMetaData)sprite).edges = edges; - } - } - - - internal class CharacterDataProvider : PSDDataProvider, ICharacterDataProvider - { - int ParentGroupInFlatten(int parentIndex, List psdLayers) - { - int group = -1; - for (int i = 0; i <= parentIndex; ++i) - if (psdLayers[i].isGroup) - ++group; - - return group; - } - - public CharacterData GetCharacterData() - { - var psdLayers = dataProvider.GetPSDLayers(); - var groups = new List(); - for (int i = 0; i < psdLayers.Count; ++i) - { - if (psdLayers[i].isGroup) - { - groups.Add(new CharacterGroup() - { - name = psdLayers[i].name, - parentGroup = ParentGroupInFlatten(psdLayers[i].parentIndex, psdLayers), - order = i - }); - } - } - - var cd = dataProvider.characterData; - var parts = cd.parts == null ? new List() : cd.parts.ToList(); - var spriteRects = dataProvider.GetSpriteMetaData(); - parts.RemoveAll(x => Array.FindIndex(spriteRects, y => y.spriteID == new GUID(x.spriteId)) == -1); - foreach (var spriteMetaData in spriteRects) - { - var srIndex = parts.FindIndex(x => new GUID(x.spriteId) == spriteMetaData.spriteID); - CharacterPart cp = srIndex == -1 ? new CharacterPart() : parts[srIndex]; - cp.spriteId = spriteMetaData.spriteID.ToString(); - cp.order = psdLayers.FindIndex(l => l.spriteID == spriteMetaData.spriteID); - cp.spritePosition = new RectInt(); - var uvTransform = spriteMetaData.uvTransform; - var outlineOffset = new Vector2(spriteMetaData.rect.x - uvTransform.x, spriteMetaData.rect.y - uvTransform.y); - cp.spritePosition.position = new Vector2Int((int)outlineOffset.x, (int)outlineOffset.y); - cp.spritePosition.size = new Vector2Int((int)spriteMetaData.rect.width, (int)spriteMetaData.rect.height); - cp.parentGroup = -1; - //Find group - var spritePSDLayer = psdLayers.FirstOrDefault(x => x.spriteID == spriteMetaData.spriteID); - if (spritePSDLayer != null) - { - cp.parentGroup = ParentGroupInFlatten(spritePSDLayer.parentIndex, psdLayers); - } - - - if (srIndex == -1) - parts.Add(cp); - else - parts[srIndex] = cp; - } - - var layers = dataProvider.GetPSDLayers(); - parts.Sort((x, y) => - { - return x.order.CompareTo(y.order); - }); - - parts.Reverse(); - cd.parts = parts.ToArray(); - cd.dimension = dataProvider.documentSize; - cd.characterGroups = groups.ToArray(); - return cd; - } - - public void SetCharacterData(CharacterData characterData) - { - characterData.parts = characterData.parts.Reverse().ToArray(); - dataProvider.characterData = characterData; - } - } - - internal class SpriteLibraryDataProvider : PSDDataProvider, ISpriteLibDataProvider - { - public SpriteCategoryList GetSpriteCategoryList() - { - return dataProvider.spriteCategoryList; - } - - public void SetSpriteCategoryList(SpriteCategoryList spriteCategoryList) - { - dataProvider.spriteCategoryList = spriteCategoryList; - } - } -} +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.Assertions; +using UnityEditor.U2D.Common; +using UnityEditor.U2D.Animation; +using System; +using UnityEditor.U2D.Sprites; +using UnityEngine.U2D; + +namespace UnityEditor.U2D.PSD +{ + internal abstract class PSDDataProvider + { + public PSDImporter dataProvider; + } + + internal class SpriteBoneDataProvider : PSDDataProvider, ISpriteBoneDataProvider + { + public List GetBones(GUID guid) + { + var sprite = ((SpriteMetaData)dataProvider.GetSpriteData(guid)); + Assert.IsNotNull(sprite, string.Format("Sprite not found for GUID:{0}", guid.ToString())); + return sprite.spriteBone != null ? sprite.spriteBone.ToList() : new List(); + } + + public void SetBones(GUID guid, List bones) + { + var sprite = dataProvider.GetSpriteDataFromAllMode(guid); + if (sprite != null) + ((SpriteMetaData)sprite).spriteBone = bones; + } + } + + internal class TextureDataProvider : PSDDataProvider, ITextureDataProvider + { + Texture2D m_ReadableTexture; + Texture2D m_OriginalTexture; + + PSDImporter textureImporter { get { return (PSDImporter)dataProvider.targetObject; } } + + public Texture2D texture + { + get + { + if (m_OriginalTexture == null) + m_OriginalTexture = AssetDatabase.LoadAssetAtPath(textureImporter.assetPath); + return m_OriginalTexture; + } + } + + public Texture2D previewTexture + { + get { return texture; } + } + + public Texture2D GetReadableTexture2D() + { + if (m_ReadableTexture == null) + { + m_ReadableTexture = InternalEditorBridge.CreateTemporaryDuplicate(texture, texture.width, texture.height); + if (m_ReadableTexture != null) + m_ReadableTexture.filterMode = texture.filterMode; + } + return m_ReadableTexture; + } + + public void GetTextureActualWidthAndHeight(out int width, out int height) + { + width = dataProvider.textureActualWidth; + height = dataProvider.textureActualHeight; + } + } + + internal class SecondaryTextureDataProvider : PSDDataProvider, ISecondaryTextureDataProvider + { + public SecondarySpriteTexture[] textures + { + get { return dataProvider.secondaryTextures; } + set { dataProvider.secondaryTextures = value; } + } + } + + internal class SpriteOutlineDataProvider : PSDDataProvider, ISpriteOutlineDataProvider + { + public List GetOutlines(GUID guid) + { + var sprite = ((SpriteMetaData)dataProvider.GetSpriteData(guid)); + Assert.IsNotNull(sprite, string.Format("Sprite not found for GUID:{0}", guid.ToString())); + + var outline = sprite.spriteOutline; + if (outline != null) + return outline.Select(x => x.outline).ToList(); + return new List(); + } + + public void SetOutlines(GUID guid, List data) + { + var sprite = dataProvider.GetSpriteDataFromAllMode(guid); + if (sprite != null) + ((SpriteMetaData)sprite).spriteOutline = data.Select(x => new SpriteOutline() {outline = x}).ToList(); + } + + public float GetTessellationDetail(GUID guid) + { + return ((SpriteMetaData)dataProvider.GetSpriteData(guid)).tessellationDetail; + } + + public void SetTessellationDetail(GUID guid, float value) + { + var sprite = dataProvider.GetSpriteDataFromAllMode(guid); + if (sprite != null) + ((SpriteMetaData)sprite).tessellationDetail = value; + } + } + + internal class SpritePhysicsOutlineProvider : PSDDataProvider, ISpritePhysicsOutlineDataProvider + { + public List GetOutlines(GUID guid) + { + var sprite = ((SpriteMetaData)dataProvider.GetSpriteData(guid)); + Assert.IsNotNull(sprite, string.Format("Sprite not found for GUID:{0}", guid.ToString())); + var outline = sprite.spritePhysicsOutline; + if (outline != null) + return outline.Select(x => x.outline).ToList(); + + return new List(); + } + + public void SetOutlines(GUID guid, List data) + { + var sprite = dataProvider.GetSpriteDataFromAllMode(guid); + if (sprite != null) + ((SpriteMetaData)sprite).spritePhysicsOutline = data.Select(x => new SpriteOutline() { outline = x }).ToList(); + } + + public float GetTessellationDetail(GUID guid) + { + return ((SpriteMetaData)dataProvider.GetSpriteData(guid)).tessellationDetail; + } + + public void SetTessellationDetail(GUID guid, float value) + { + var sprite = dataProvider.GetSpriteDataFromAllMode(guid); + if (sprite != null) + ((SpriteMetaData)sprite).tessellationDetail = value; + } + } + + internal class SpriteMeshDataProvider : PSDDataProvider, ISpriteMeshDataProvider + { + public Vertex2DMetaData[] GetVertices(GUID guid) + { + var sprite = ((SpriteMetaData)dataProvider.GetSpriteData(guid)); + Assert.IsNotNull(sprite, string.Format("Sprite not found for GUID:{0}", guid.ToString())); + var v = sprite.vertices; + if (v != null) + return v.ToArray(); + + return new Vertex2DMetaData[0]; + } + + public void SetVertices(GUID guid, Vertex2DMetaData[] vertices) + { + var sprite = dataProvider.GetSpriteDataFromAllMode(guid); + if (sprite != null) + ((SpriteMetaData)sprite).vertices = vertices.ToList(); + } + + public int[] GetIndices(GUID guid) + { + var sprite = ((SpriteMetaData)dataProvider.GetSpriteData(guid)); + Assert.IsNotNull(sprite, string.Format("Sprite not found for GUID:{0}", guid.ToString())); + var v = sprite.indices; + if (v != null) + return v; + + return new int[0]; + } + + public void SetIndices(GUID guid, int[] indices) + { + var sprite = dataProvider.GetSpriteDataFromAllMode(guid); + if (sprite != null) + ((SpriteMetaData)sprite).indices = indices; + } + + public Vector2Int[] GetEdges(GUID guid) + { + var sprite = ((SpriteMetaData)dataProvider.GetSpriteData(guid)); + Assert.IsNotNull(sprite, string.Format("Sprite not found for GUID:{0}", guid.ToString())); + var v = sprite.edges; + if (v != null) + return v; + + return new Vector2Int[0]; + } + + public void SetEdges(GUID guid, Vector2Int[] edges) + { + var sprite = dataProvider.GetSpriteDataFromAllMode(guid); + if (sprite != null) + ((SpriteMetaData)sprite).edges = edges; + } + } + + + internal class CharacterDataProvider : PSDDataProvider, ICharacterDataProvider + { + int ParentGroupInFlatten(int parentIndex, List psdLayers) + { + int group = -1; + for (int i = 0; i <= parentIndex; ++i) + if (psdLayers[i].isGroup) + ++group; + + return group; + } + + public CharacterData GetCharacterData() + { + var psdLayers = dataProvider.GetPSDLayers(); + var groups = new List(); + for (int i = 0; i < psdLayers.Count; ++i) + { + if (psdLayers[i].isGroup) + { + groups.Add(new CharacterGroup() + { + name = psdLayers[i].name, + parentGroup = ParentGroupInFlatten(psdLayers[i].parentIndex, psdLayers), + order = i + }); + } + } + + var cd = dataProvider.characterData; + var parts = cd.parts == null ? new List() : cd.parts.ToList(); + var spriteRects = dataProvider.GetSpriteMetaData(); + parts.RemoveAll(x => Array.FindIndex(spriteRects, y => y.spriteID == new GUID(x.spriteId)) == -1); + foreach (var spriteMetaData in spriteRects) + { + var srIndex = parts.FindIndex(x => new GUID(x.spriteId) == spriteMetaData.spriteID); + CharacterPart cp = srIndex == -1 ? new CharacterPart() : parts[srIndex]; + cp.spriteId = spriteMetaData.spriteID.ToString(); + cp.order = psdLayers.FindIndex(l => l.spriteID == spriteMetaData.spriteID); + cp.spritePosition = new RectInt(); + var uvTransform = spriteMetaData.uvTransform; + var outlineOffset = new Vector2(spriteMetaData.rect.x - uvTransform.x, spriteMetaData.rect.y - uvTransform.y); + cp.spritePosition.position = new Vector2Int((int)outlineOffset.x, (int)outlineOffset.y); + cp.spritePosition.size = new Vector2Int((int)spriteMetaData.rect.width, (int)spriteMetaData.rect.height); + cp.parentGroup = -1; + //Find group + var spritePSDLayer = psdLayers.FirstOrDefault(x => x.spriteID == spriteMetaData.spriteID); + if (spritePSDLayer != null) + { + cp.parentGroup = ParentGroupInFlatten(spritePSDLayer.parentIndex, psdLayers); + } + + + if (srIndex == -1) + parts.Add(cp); + else + parts[srIndex] = cp; + } + + var layers = dataProvider.GetPSDLayers(); + parts.Sort((x, y) => + { + return x.order.CompareTo(y.order); + }); + + parts.Reverse(); + cd.parts = parts.ToArray(); + cd.dimension = dataProvider.documentSize; + cd.characterGroups = groups.ToArray(); + return cd; + } + + public void SetCharacterData(CharacterData characterData) + { + characterData.parts = characterData.parts.Reverse().ToArray(); + dataProvider.characterData = characterData; + } + } + + internal class SpriteLibraryDataProvider : PSDDataProvider, ISpriteLibDataProvider + { + public SpriteCategoryList GetSpriteCategoryList() + { + return dataProvider.spriteCategoryList; + } + + public void SetSpriteCategoryList(SpriteCategoryList spriteCategoryList) + { + dataProvider.spriteCategoryList = spriteCategoryList; + } + } +} diff --git a/Editor/PSDImporterDataProvider.cs.meta b/Editor/PSDImporterDataProvider.cs.meta index 6a6d8bd..2aa6f07 100644 --- a/Editor/PSDImporterDataProvider.cs.meta +++ b/Editor/PSDImporterDataProvider.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: d38b7c3f9a7064947a8e162797ea2fa8 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: d38b7c3f9a7064947a8e162797ea2fa8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDImporterEditor.cs b/Editor/PSDImporterEditor.cs index 61d9d71..a0d1151 100644 --- a/Editor/PSDImporterEditor.cs +++ b/Editor/PSDImporterEditor.cs @@ -1,991 +1,1124 @@ -using System; -using System.Collections.Generic; -using System.IO; -using PhotoshopFile; -using UnityEditor.Experimental.AssetImporters; -using UnityEditor.U2D.Animation; -using UnityEditor.U2D.Common; -using UnityEditor.U2D.Sprites; -using UnityEngine; - -namespace UnityEditor.U2D.PSD -{ - /// - /// Inspector for PSDImporter - /// - [CustomEditor(typeof(PSDImporter))] - public class PSDImporterEditor : ScriptedImporterEditor - { - SerializedProperty m_TextureType; - SerializedProperty m_TextureShape; - SerializedProperty m_SpriteMode; - SerializedProperty m_SpritePixelsToUnits; - SerializedProperty m_SpriteMeshType; - SerializedProperty m_SpriteExtrude; - SerializedProperty m_Alignment; - SerializedProperty m_SpritePivot; - SerializedProperty m_NPOTScale; - SerializedProperty m_IsReadable; - SerializedProperty m_sRGBTexture; - SerializedProperty m_AlphaSource; - SerializedProperty m_MipMapMode; - SerializedProperty m_EnableMipMap; - SerializedProperty m_FadeOut; - SerializedProperty m_BorderMipMap; - SerializedProperty m_MipMapsPreserveCoverage; - SerializedProperty m_AlphaTestReferenceValue; - SerializedProperty m_MipMapFadeDistanceStart; - SerializedProperty m_MipMapFadeDistanceEnd; - SerializedProperty m_AlphaIsTransparency; - SerializedProperty m_FilterMode; - SerializedProperty m_Aniso; - - SerializedProperty m_WrapU; - SerializedProperty m_WrapV; - SerializedProperty m_WrapW; - SerializedProperty m_ConvertToNormalMap; - SerializedProperty m_MosaicLayers; - SerializedProperty m_ImportHiddenLayers; - SerializedProperty m_ResliceFromLayer; - SerializedProperty m_CharacterMode; - SerializedProperty m_DocumentPivot; - SerializedProperty m_DocumentAlignment; - SerializedProperty m_GenerateGOHierarchy; - SerializedProperty m_PaperDollMode; - SerializedProperty m_KeepDupilcateSpriteName; - - readonly int[] m_FilterModeOptions = (int[])(Enum.GetValues(typeof(FilterMode))); - - bool m_IsPOT = false; - bool m_ShowAdvanced = false; - bool m_ShowExperimental = false; - Dictionary m_AdvanceInspectorGUI = new Dictionary(); - int m_PlatformSettingsIndex; - bool m_ShowPerAxisWrapModes = false; - - TexturePlatformSettingsView m_TexturePlatformSettingsView = new TexturePlatformSettingsView(); - TexturePlatformSettingsController m_TexturePlatformSettingsController = new TexturePlatformSettingsController(); - - /// - /// Implementation of AssetImporterEditor.OnEnable - /// - public override void OnEnable() - { - base.OnEnable(); - m_MosaicLayers = serializedObject.FindProperty("m_MosaicLayers"); - m_ImportHiddenLayers = serializedObject.FindProperty("m_ImportHiddenLayers"); - m_ResliceFromLayer = serializedObject.FindProperty("m_ResliceFromLayer"); - m_CharacterMode = serializedObject.FindProperty("m_CharacterMode"); - m_DocumentPivot = serializedObject.FindProperty("m_DocumentPivot"); - m_DocumentAlignment = serializedObject.FindProperty("m_DocumentAlignment"); - m_GenerateGOHierarchy = serializedObject.FindProperty("m_GenerateGOHierarchy"); - m_PaperDollMode = serializedObject.FindProperty("m_PaperDollMode"); - m_KeepDupilcateSpriteName = serializedObject.FindProperty("m_KeepDupilcateSpriteName"); - - var textureImporterSettingsSP = serializedObject.FindProperty("m_TextureImporterSettings"); - m_TextureType = textureImporterSettingsSP.FindPropertyRelative("m_TextureType"); - m_TextureShape = textureImporterSettingsSP.FindPropertyRelative("m_TextureShape"); - m_ConvertToNormalMap = textureImporterSettingsSP.FindPropertyRelative("m_ConvertToNormalMap"); - m_SpriteMode = textureImporterSettingsSP.FindPropertyRelative("m_SpriteMode"); - m_SpritePixelsToUnits = textureImporterSettingsSP.FindPropertyRelative("m_SpritePixelsToUnits"); - m_SpriteMeshType = textureImporterSettingsSP.FindPropertyRelative("m_SpriteMeshType"); - m_SpriteExtrude = textureImporterSettingsSP.FindPropertyRelative("m_SpriteExtrude"); - m_Alignment = textureImporterSettingsSP.FindPropertyRelative("m_Alignment"); - m_SpritePivot = textureImporterSettingsSP.FindPropertyRelative("m_SpritePivot"); - m_NPOTScale = textureImporterSettingsSP.FindPropertyRelative("m_NPOTScale"); - m_IsReadable = textureImporterSettingsSP.FindPropertyRelative("m_IsReadable"); - m_sRGBTexture = textureImporterSettingsSP.FindPropertyRelative("m_sRGBTexture"); - m_AlphaSource = textureImporterSettingsSP.FindPropertyRelative("m_AlphaSource"); - m_MipMapMode = textureImporterSettingsSP.FindPropertyRelative("m_MipMapMode"); - m_EnableMipMap = textureImporterSettingsSP.FindPropertyRelative("m_EnableMipMap"); - m_FadeOut = textureImporterSettingsSP.FindPropertyRelative("m_FadeOut"); - m_BorderMipMap = textureImporterSettingsSP.FindPropertyRelative("m_BorderMipMap"); - m_MipMapsPreserveCoverage = textureImporterSettingsSP.FindPropertyRelative("m_MipMapsPreserveCoverage"); - m_AlphaTestReferenceValue = textureImporterSettingsSP.FindPropertyRelative("m_AlphaTestReferenceValue"); - m_MipMapFadeDistanceStart = textureImporterSettingsSP.FindPropertyRelative("m_MipMapFadeDistanceStart"); - m_MipMapFadeDistanceEnd = textureImporterSettingsSP.FindPropertyRelative("m_MipMapFadeDistanceEnd"); - m_AlphaIsTransparency = textureImporterSettingsSP.FindPropertyRelative("m_AlphaIsTransparency"); - m_FilterMode = textureImporterSettingsSP.FindPropertyRelative("m_FilterMode"); - m_Aniso = textureImporterSettingsSP.FindPropertyRelative("m_Aniso"); - m_WrapU = textureImporterSettingsSP.FindPropertyRelative("m_WrapU"); - m_WrapV = textureImporterSettingsSP.FindPropertyRelative("m_WrapV"); - m_WrapW = textureImporterSettingsSP.FindPropertyRelative("m_WrapW"); - - var textureWidth = serializedObject.FindProperty("m_TextureActualWidth"); - var textureHeight = serializedObject.FindProperty("m_TextureActualHeight"); - m_IsPOT = Mathf.IsPowerOfTwo(textureWidth.intValue) && Mathf.IsPowerOfTwo(textureHeight.intValue); - - - var advanceGUIAction = new Action[] - { - ColorSpaceGUI, - AlphaHandlingGUI, - POTScaleGUI, - ReadableGUI, - MipMapGUI - }; - m_AdvanceInspectorGUI.Add(TextureImporterType.Sprite, advanceGUIAction); - - advanceGUIAction = new Action[] - { - POTScaleGUI, - ReadableGUI, - MipMapGUI - }; - m_AdvanceInspectorGUI.Add(TextureImporterType.Default, advanceGUIAction); - - LoadPlatformSettings(); - } - - /// - /// Implementation of AssetImporterEditor.OnInspectorGUI - /// - public override void OnInspectorGUI() - { - serializedObject.Update(); - if (s_Styles == null) - s_Styles = new Styles(); - - EditorGUI.showMixedValue = m_TextureType.hasMultipleDifferentValues; - m_TextureType.intValue = EditorGUILayout.IntPopup(s_Styles.textureTypeTitle, m_TextureType.intValue, s_Styles.textureTypeOptions, s_Styles.textureTypeValues); - EditorGUI.showMixedValue = false; - - switch ((TextureImporterType)m_TextureType.intValue) - { - case TextureImporterType.Sprite: - DoSpriteInspector(); - break; - case TextureImporterType.Default: - DoTextureDefaultInspector(); - break; - default: - Debug.LogWarning("We only support Default or Sprite texture type for now. Texture type is set to default."); - m_TextureType.intValue = (int)TextureImporterType.Default; - break; - } - - DoAdvanceInspector(); - CommonTextureSettingsGUI(); - GUILayout.Space(10); - DoPlatformSettings(); - serializedObject.ApplyModifiedProperties(); - ApplyRevertGUI(); - } - - /// - /// Implementation of AssetImporterEditor.Apply - /// - protected override void Apply() - { - FileStream fileStream = new FileStream(((AssetImporter)target).assetPath, FileMode.Open, FileAccess.Read); - var doc = PaintDotNet.Data.PhotoshopFileType.PsdLoad.Load(fileStream, ELoadFlag.Header | ELoadFlag.ColorMode); - - PSDApplyEvent evt = new PSDApplyEvent() - { - instance_id = target.GetInstanceID(), - texture_type = m_TextureType.intValue, - sprite_mode = m_SpriteMode.intValue, - mosaic_layer = m_MosaicLayers.boolValue, - import_hidden_layer = m_ImportHiddenLayers.boolValue, - character_mode = m_CharacterMode.boolValue, - generate_go_hierarchy = m_GenerateGOHierarchy.boolValue, - reslice_from_layer = m_ResliceFromLayer.boolValue, - is_character_rigged = IsCharacterRigged(), - is_psd = IsPSD(doc), - color_mode = FileColorMode(doc) - }; - doc.Cleanup(); - AnalyticFactory.analytics.SendApplyEvent(evt); - base.Apply(); - } - - static bool IsPSD(PsdFile doc) - { - return !doc.IsLargeDocument; - } - - static PsdColorMode FileColorMode(PsdFile doc) - { - return doc.ColorMode; - } - - bool IsCharacterRigged() - { - var importer = target as PSDImporter; - if (importer != null) - { - var characterProvider = importer.GetDataProvider(); - var meshDataProvider = importer.GetDataProvider(); - if (characterProvider != null && meshDataProvider != null) - { - var character = characterProvider.GetCharacterData(); - foreach (var parts in character.parts) - { - var vert = meshDataProvider.GetVertices(new GUID(parts.spriteId)); - var indices = meshDataProvider.GetIndices(new GUID(parts.spriteId)); - if (parts.bones != null && parts.bones.Length > 0 && - vert != null && vert.Length > 0 && - indices != null && indices.Length > 0) - return true; - } - } - } - return false; - } - - Dictionary> m_PlatfromSettings = new Dictionary>(); - void LoadPlatformSettings() - { - foreach (var t in targets) - { - var so = new SerializedObject(t); - var platformSettingsSP = so.FindProperty("m_PlatformSettings"); - for (int i = 0; i < platformSettingsSP.arraySize; ++i) - { - var tip = new TextureImporterPlatformSettings(); - var sp = platformSettingsSP.GetArrayElementAtIndex(i); - tip.name = sp.FindPropertyRelative("m_Name").stringValue; - tip.overridden = sp.FindPropertyRelative("m_Overridden").intValue == 1; - tip.maxTextureSize = sp.FindPropertyRelative("m_MaxTextureSize").intValue; - tip.resizeAlgorithm = (TextureResizeAlgorithm)sp.FindPropertyRelative("m_ResizeAlgorithm").intValue; - tip.format = (TextureImporterFormat)sp.FindPropertyRelative("m_TextureFormat").intValue; - tip.textureCompression = (TextureImporterCompression)sp.FindPropertyRelative("m_TextureCompression").intValue; - tip.compressionQuality = sp.FindPropertyRelative("m_CompressionQuality").intValue; - tip.crunchedCompression = sp.FindPropertyRelative("m_CrunchedCompression").intValue == 1; - tip.allowsAlphaSplitting = sp.FindPropertyRelative("m_AllowsAlphaSplitting").intValue == 1; - - List platformSettings = null; - m_PlatfromSettings.TryGetValue(tip.name, out platformSettings); - if (platformSettings == null) - { - platformSettings = new List(); - m_PlatfromSettings.Add(tip.name, platformSettings); - } - platformSettings.Add(tip); - } - } - } - - void StorePlatformSettings() - { - var platformSettingsSP = serializedObject.FindProperty("m_PlatformSettings"); - platformSettingsSP.ClearArray(); - foreach (var keyValue in m_PlatfromSettings) - { - if (!keyValue.Value[0].overridden) - continue; - - SerializedProperty platformSettingSP = null; - for (int i = 0; i < platformSettingsSP.arraySize; ++i) - { - var sp = platformSettingsSP.GetArrayElementAtIndex(i); - if (sp.FindPropertyRelative("m_Name").stringValue == keyValue.Key) - platformSettingSP = sp; - } - if (platformSettingSP == null) - { - platformSettingsSP.InsertArrayElementAtIndex(platformSettingsSP.arraySize); - platformSettingSP = platformSettingsSP.GetArrayElementAtIndex(platformSettingsSP.arraySize - 1); - } - - var tip = keyValue.Value[0]; - platformSettingSP.FindPropertyRelative("m_Name").stringValue = tip.name; - platformSettingSP.FindPropertyRelative("m_Overridden").intValue = tip.overridden ? 1 : 0; - platformSettingSP.FindPropertyRelative("m_MaxTextureSize").intValue = tip.maxTextureSize; - platformSettingSP.FindPropertyRelative("m_ResizeAlgorithm").intValue = (int)tip.resizeAlgorithm; - platformSettingSP.FindPropertyRelative("m_TextureFormat").intValue = (int)tip.format; - platformSettingSP.FindPropertyRelative("m_TextureCompression").intValue = (int)tip.textureCompression; - platformSettingSP.FindPropertyRelative("m_CompressionQuality").intValue = tip.compressionQuality; - platformSettingSP.FindPropertyRelative("m_CrunchedCompression").intValue = tip.crunchedCompression ? 1 : 0; - platformSettingSP.FindPropertyRelative("m_AllowsAlphaSplitting").intValue = tip.allowsAlphaSplitting ? 1 : 0; - } - } - - void DoPlatformSettings() - { - m_PlatformSettingsIndex = EditorGUILayout.Popup(s_Styles.platformSettingsLabel, m_PlatformSettingsIndex, s_Styles.platformSettingsSelection); - - List settings = null; - m_PlatfromSettings.TryGetValue(TexturePlatformSettingsModal.kValidBuildPlatform[m_PlatformSettingsIndex].buildTargetName, out settings); - if (settings == null) - { - settings = new List(targets.Length); - for (int i = 0; i < targets.Length; ++i) - { - var tip = new TextureImporterPlatformSettings(); - tip.name = TexturePlatformSettingsModal.kValidBuildPlatform[m_PlatformSettingsIndex].buildTargetName; - tip.format = TexturePlatformSettingsModal.kValidBuildPlatform[m_PlatformSettingsIndex].defaultTextureFormat; - if (TexturePlatformSettingsModal.kValidBuildPlatform[m_PlatformSettingsIndex].buildTarget[0] == BuildTarget.NoTarget) - { - tip.overridden = true; - } - settings.Add(tip); - } - m_PlatfromSettings.Add(TexturePlatformSettingsModal.kValidBuildPlatform[m_PlatformSettingsIndex].buildTargetName, settings); - } - - - if (m_TexturePlatformSettingsController.HandlePlatformSettings(TexturePlatformSettingsModal.kValidBuildPlatform[m_PlatformSettingsIndex].buildTarget[0], settings, m_TexturePlatformSettingsView)) - { - StorePlatformSettings(); - } - } - - void DoAdvanceInspector() - { - if (!m_TextureType.hasMultipleDifferentValues) - { - if (m_AdvanceInspectorGUI.ContainsKey((TextureImporterType)m_TextureType.intValue)) - { - EditorGUILayout.Space(); - - m_ShowAdvanced = EditorGUILayout.Foldout(m_ShowAdvanced, s_Styles.showAdvanced, true); - if (m_ShowAdvanced) - { - foreach (var action in m_AdvanceInspectorGUI[(TextureImporterType)m_TextureType.intValue]) - { - action(); - } - } - } - } - EditorGUILayout.Space(); - } - - void CommonTextureSettingsGUI() - { - EditorGUI.BeginChangeCheck(); - - // Wrap mode - bool isVolume = false; - WrapModePopup(m_WrapU, m_WrapV, m_WrapW, isVolume, ref m_ShowPerAxisWrapModes); - - - // Display warning about repeat wrap mode on restricted npot emulation - if (m_NPOTScale.intValue == (int)TextureImporterNPOTScale.None && - (m_WrapU.intValue == (int)TextureWrapMode.Repeat || m_WrapV.intValue == (int)TextureWrapMode.Repeat) && - !InternalEditorBridge.DoesHardwareSupportsFullNPOT()) - { - bool displayWarning = false; - foreach (var target in targets) - { - var imp = (PSDImporter)target; - int w = imp.textureActualWidth; - int h = imp.textureActualHeight; - if (!Mathf.IsPowerOfTwo(w) || !Mathf.IsPowerOfTwo(h)) - { - displayWarning = true; - break; - } - } - - if (displayWarning) - { - EditorGUILayout.HelpBox(s_Styles.warpNotSupportWarning.text, MessageType.Warning, true); - } - } - - // Filter mode - EditorGUI.showMixedValue = m_FilterMode.hasMultipleDifferentValues; - FilterMode filter = (FilterMode)m_FilterMode.intValue; - if ((int)filter == -1) - { - if (m_FadeOut.intValue > 0 || m_ConvertToNormalMap.intValue > 0) - filter = FilterMode.Trilinear; - else - filter = FilterMode.Bilinear; - } - filter = (FilterMode)EditorGUILayout.IntPopup(s_Styles.filterMode, (int)filter, s_Styles.filterModeOptions, m_FilterModeOptions); - EditorGUI.showMixedValue = false; - if (EditorGUI.EndChangeCheck()) - m_FilterMode.intValue = (int)filter; - - // Aniso - bool showAniso = (FilterMode)m_FilterMode.intValue != FilterMode.Point - && m_EnableMipMap.intValue > 0 - && (TextureImporterShape)m_TextureShape.intValue != TextureImporterShape.TextureCube; - using (new EditorGUI.DisabledScope(!showAniso)) - { - EditorGUI.BeginChangeCheck(); - EditorGUI.showMixedValue = m_Aniso.hasMultipleDifferentValues; - int aniso = m_Aniso.intValue; - if (aniso == -1) - aniso = 1; - aniso = EditorGUILayout.IntSlider(s_Styles.anisoLevelLabel, aniso, 0, 16); - EditorGUI.showMixedValue = false; - if (EditorGUI.EndChangeCheck()) - m_Aniso.intValue = aniso; - - if (aniso > 1) - { - if (QualitySettings.anisotropicFiltering == AnisotropicFiltering.Disable) - EditorGUILayout.HelpBox(s_Styles.anisotropicDisableInfo.text, MessageType.Info); - else if (QualitySettings.anisotropicFiltering == AnisotropicFiltering.ForceEnable) - EditorGUILayout.HelpBox(s_Styles.anisotropicForceEnableInfo.text, MessageType.Info); - } - } - } - - private static bool IsAnyTextureObjectUsingPerAxisWrapMode(UnityEngine.Object[] objects, bool isVolumeTexture) - { - foreach (var o in objects) - { - int u = 0, v = 0, w = 0; - // the objects can be Textures themselves, or texture-related importers - if (o is Texture) - { - var ti = (Texture)o; - u = (int)ti.wrapModeU; - v = (int)ti.wrapModeV; - w = (int)ti.wrapModeW; - } - if (o is TextureImporter) - { - var ti = (TextureImporter)o; - u = (int)ti.wrapModeU; - v = (int)ti.wrapModeV; - w = (int)ti.wrapModeW; - } - if (o is IHVImageFormatImporter) - { - var ti = (IHVImageFormatImporter)o; - u = (int)ti.wrapModeU; - v = (int)ti.wrapModeV; - w = (int)ti.wrapModeW; - } - u = Mathf.Max(0, u); - v = Mathf.Max(0, v); - w = Mathf.Max(0, w); - if (u != v) - { - return true; - } - if (isVolumeTexture) - { - if (u != w || v != w) - { - return true; - } - } - } - return false; - } - - // showPerAxisWrapModes is state of whether "Per-Axis" mode should be active in the main dropdown. - // It is set automatically if wrap modes in UVW are different, or if user explicitly picks "Per-Axis" option -- when that one is picked, - // then it should stay true even if UVW wrap modes will initially be the same. - // - // Note: W wrapping mode is only shown when isVolumeTexture is true. - internal static void WrapModePopup(SerializedProperty wrapU, SerializedProperty wrapV, SerializedProperty wrapW, bool isVolumeTexture, ref bool showPerAxisWrapModes) - { - if (s_Styles == null) - s_Styles = new Styles(); - - // In texture importer settings, serialized properties for things like wrap modes can contain -1; - // that seems to indicate "use defaults, user has not changed them to anything" but not totally sure. - // Show them as Repeat wrap modes in the popups. - var wu = (TextureWrapMode)Mathf.Max(wrapU.intValue, 0); - var wv = (TextureWrapMode)Mathf.Max(wrapV.intValue, 0); - var ww = (TextureWrapMode)Mathf.Max(wrapW.intValue, 0); - - // automatically go into per-axis mode if values are already different - if (wu != wv) - showPerAxisWrapModes = true; - if (isVolumeTexture) - { - if (wu != ww || wv != ww) - showPerAxisWrapModes = true; - } - - // It's not possible to determine whether any single texture in the whole selection is using per-axis wrap modes - // just from SerializedProperty values. They can only tell if "some values in whole selection are different" (e.g. - // wrap value on U axis is not the same among all textures), and can return value of "some" object in the selection - // (typically based on object loading order). So in order for more intuitive behavior with multi-selection, - // we go over the actual objects when there's >1 object selected and some wrap modes are different. - if (!showPerAxisWrapModes) - { - if (wrapU.hasMultipleDifferentValues || wrapV.hasMultipleDifferentValues || (isVolumeTexture && wrapW.hasMultipleDifferentValues)) - { - if (IsAnyTextureObjectUsingPerAxisWrapMode(wrapU.serializedObject.targetObjects, isVolumeTexture)) - { - showPerAxisWrapModes = true; - } - } - } - - int value = showPerAxisWrapModes ? -1 : (int)wu; - - // main wrap mode popup - EditorGUI.BeginChangeCheck(); - EditorGUI.showMixedValue = !showPerAxisWrapModes && (wrapU.hasMultipleDifferentValues || wrapV.hasMultipleDifferentValues || (isVolumeTexture && wrapW.hasMultipleDifferentValues)); - value = EditorGUILayout.IntPopup(s_Styles.wrapModeLabel, value, s_Styles.wrapModeContents, s_Styles.wrapModeValues); - if (EditorGUI.EndChangeCheck() && value != -1) - { - // assign the same wrap mode to all axes, and hide per-axis popups - wrapU.intValue = value; - wrapV.intValue = value; - wrapW.intValue = value; - showPerAxisWrapModes = false; - } - - // show per-axis popups if needed - if (value == -1) - { - showPerAxisWrapModes = true; - EditorGUI.indentLevel++; - WrapModeAxisPopup(s_Styles.wrapU, wrapU); - WrapModeAxisPopup(s_Styles.wrapV, wrapV); - if (isVolumeTexture) - { - WrapModeAxisPopup(s_Styles.wrapW, wrapW); - } - EditorGUI.indentLevel--; - } - EditorGUI.showMixedValue = false; - } - - static void WrapModeAxisPopup(GUIContent label, SerializedProperty wrapProperty) - { - // In texture importer settings, serialized properties for wrap modes can contain -1, which means "use default". - var wrap = (TextureWrapMode)Mathf.Max(wrapProperty.intValue, 0); - Rect rect = EditorGUILayout.GetControlRect(); - EditorGUI.BeginChangeCheck(); - EditorGUI.BeginProperty(rect, label, wrapProperty); - wrap = (TextureWrapMode)EditorGUI.EnumPopup(rect, label, wrap); - EditorGUI.EndProperty(); - if (EditorGUI.EndChangeCheck()) - { - wrapProperty.intValue = (int)wrap; - } - } - - void DoWrapModePopup() - { - WrapModePopup(m_WrapU, m_WrapV, m_WrapW, IsVolume(), ref m_ShowPerAxisWrapModes); - } - - bool IsVolume() - { - var t = target as Texture; - return t != null && t.dimension == UnityEngine.Rendering.TextureDimension.Tex3D; - } - - void DoSpriteInspector() - { - EditorGUI.BeginChangeCheck(); - EditorGUILayout.IntPopup(m_SpriteMode, s_Styles.spriteModeOptions, new[] { 1, 2, 3 }, s_Styles.spriteMode); - - // Ensure that PropertyField focus will be cleared when we change spriteMode. - if (EditorGUI.EndChangeCheck()) - { - GUIUtility.keyboardControl = 0; - } - - EditorGUI.indentLevel++; - - // Show generic attributes - if (m_SpriteMode.intValue != 0) - { - EditorGUILayout.PropertyField(m_SpritePixelsToUnits, s_Styles.spritePixelsPerUnit); - - if (m_SpriteMode.intValue != (int)SpriteImportMode.Polygon && !m_SpriteMode.hasMultipleDifferentValues) - { - EditorGUILayout.IntPopup(m_SpriteMeshType, s_Styles.spriteMeshTypeOptions, new[] { 0, 1 }, s_Styles.spriteMeshType); - } - - EditorGUILayout.IntSlider(m_SpriteExtrude, 0, 32, s_Styles.spriteExtrude); - - if (m_SpriteMode.intValue == 1) - { - EditorGUILayout.IntPopup(m_Alignment, s_Styles.spriteAlignmentOptions, new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, s_Styles.spriteAlignment); - - if (m_Alignment.intValue == (int)SpriteAlignment.Custom) - { - GUILayout.BeginHorizontal(); - EditorGUILayout.PropertyField(m_SpritePivot, new GUIContent()); - GUILayout.EndHorizontal(); - } - } - } - - EditorGUILayout.PropertyField(m_ImportHiddenLayers, s_Styles.importHiddenLayer); - if (m_SpriteMode.intValue == (int)SpriteImportMode.Multiple && !m_SpriteMode.hasMultipleDifferentValues) - { - EditorGUILayout.PropertyField(m_MosaicLayers, s_Styles.mosaicLayers); - using (new EditorGUI.DisabledScope(!m_MosaicLayers.boolValue)) - { - EditorGUILayout.PropertyField(m_CharacterMode, s_Styles.characterMode); - using (new EditorGUI.DisabledScope(!m_CharacterMode.boolValue)) - { - EditorGUILayout.PropertyField(m_GenerateGOHierarchy, s_Styles.generateGOHierarchy); - EditorGUILayout.IntPopup(m_DocumentAlignment, s_Styles.spriteAlignmentOptions, new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, s_Styles.characterAlignment); - if (m_DocumentAlignment.intValue == (int)SpriteAlignment.Custom) - { - GUILayout.BeginHorizontal(); - GUILayout.Space(EditorGUIUtility.labelWidth); - EditorGUILayout.PropertyField(m_DocumentPivot, new GUIContent()); - GUILayout.EndHorizontal(); - } - //EditorGUILayout.PropertyField(m_PaperDollMode, s_Styles.paperDollMode); - } - - - EditorGUILayout.PropertyField(m_ResliceFromLayer, s_Styles.resliceFromLayer); - if (m_ResliceFromLayer.boolValue) - { - EditorGUILayout.HelpBox(s_Styles.resliceFromLayerWarning.text, MessageType.Info, true); - } - } - m_ShowExperimental = EditorGUILayout.Foldout(m_ShowExperimental, s_Styles.experimental, true); - if (m_ShowExperimental) - { - EditorGUI.indentLevel++; - EditorGUILayout.PropertyField(m_KeepDupilcateSpriteName, s_Styles.keepDuplicateSpriteName); - EditorGUI.indentLevel--; - } - } - - using (new EditorGUI.DisabledScope(targets.Length != 1)) - { - GUILayout.BeginHorizontal(); - - GUILayout.FlexibleSpace(); - if (GUILayout.Button(s_Styles.spriteEditorButtonLabel)) - { - if (HasModified()) - { - // To ensure Sprite Editor Window to have the latest texture import setting, - // We must applied those modified values first. - string dialogText = string.Format(s_Styles.unappliedSettingsDialogContent.text, ((AssetImporter)target).assetPath); - if (EditorUtility.DisplayDialog(s_Styles.unappliedSettingsDialogTitle.text, - dialogText, s_Styles.applyButtonLabel.text, s_Styles.revertButtonLabel.text)) - { - ApplyAndImport(); - InternalEditorBridge.ShowSpriteEditorWindow(); - - // We reimported the asset which destroyed the editor, so we can't keep running the UI here. - GUIUtility.ExitGUI(); - } - } - else - { - InternalEditorBridge.ShowSpriteEditorWindow(); - } - } - GUILayout.EndHorizontal(); - } - EditorGUI.indentLevel--; - } - - void DoTextureDefaultInspector() - { - ColorSpaceGUI(); - AlphaHandlingGUI(); - } - - void ColorSpaceGUI() - { - ToggleFromInt(m_sRGBTexture, s_Styles.sRGBTexture); - } - - void POTScaleGUI() - { - using (new EditorGUI.DisabledScope(m_IsPOT || m_TextureType.intValue == (int)TextureImporterType.Sprite)) - { - EnumPopup(m_NPOTScale, typeof(TextureImporterNPOTScale), s_Styles.npot); - } - } - - void ReadableGUI() - { - ToggleFromInt(m_IsReadable, s_Styles.readWrite); - } - - void AlphaHandlingGUI() - { - EditorGUI.showMixedValue = m_AlphaSource.hasMultipleDifferentValues; - EditorGUI.BeginChangeCheck(); - int newAlphaUsage = EditorGUILayout.IntPopup(s_Styles.alphaSource, m_AlphaSource.intValue, s_Styles.alphaSourceOptions, s_Styles.alphaSourceValues); - - EditorGUI.showMixedValue = false; - if (EditorGUI.EndChangeCheck()) - { - m_AlphaSource.intValue = newAlphaUsage; - } - - bool showAlphaIsTransparency = (TextureImporterAlphaSource)m_AlphaSource.intValue != TextureImporterAlphaSource.None; - using (new EditorGUI.DisabledScope(!showAlphaIsTransparency)) - { - ToggleFromInt(m_AlphaIsTransparency, s_Styles.alphaIsTransparency); - } - } - - void MipMapGUI() - { - ToggleFromInt(m_EnableMipMap, s_Styles.generateMipMaps); - - if (m_EnableMipMap.boolValue && !m_EnableMipMap.hasMultipleDifferentValues) - { - EditorGUI.indentLevel++; - ToggleFromInt(m_BorderMipMap, s_Styles.borderMipMaps); - EditorGUILayout.Popup(s_Styles.mipMapFilter, m_MipMapMode.intValue, s_Styles.mipMapFilterOptions); - - ToggleFromInt(m_MipMapsPreserveCoverage, s_Styles.mipMapsPreserveCoverage); - if (m_MipMapsPreserveCoverage.intValue != 0 && !m_MipMapsPreserveCoverage.hasMultipleDifferentValues) - { - EditorGUI.indentLevel++; - EditorGUILayout.PropertyField(m_AlphaTestReferenceValue, s_Styles.alphaTestReferenceValue); - EditorGUI.indentLevel--; - } - - // Mipmap fadeout - ToggleFromInt(m_FadeOut, s_Styles.mipmapFadeOutToggle); - if (m_FadeOut.intValue > 0) - { - EditorGUI.indentLevel++; - EditorGUI.BeginChangeCheck(); - float min = m_MipMapFadeDistanceStart.intValue; - float max = m_MipMapFadeDistanceEnd.intValue; - EditorGUILayout.MinMaxSlider(s_Styles.mipmapFadeOut, ref min, ref max, 0, 10); - if (EditorGUI.EndChangeCheck()) - { - m_MipMapFadeDistanceStart.intValue = Mathf.RoundToInt(min); - m_MipMapFadeDistanceEnd.intValue = Mathf.RoundToInt(max); - } - EditorGUI.indentLevel--; - } - EditorGUI.indentLevel--; - } - } - - void ToggleFromInt(SerializedProperty property, GUIContent label) - { - EditorGUI.BeginChangeCheck(); - EditorGUI.showMixedValue = property.hasMultipleDifferentValues; - int value = EditorGUILayout.Toggle(label, property.intValue > 0) ? 1 : 0; - EditorGUI.showMixedValue = false; - if (EditorGUI.EndChangeCheck()) - property.intValue = value; - } - - void EnumPopup(SerializedProperty property, System.Type type, GUIContent label) - { - EditorGUILayout.IntPopup(label.text, property.intValue, - System.Enum.GetNames(type), - System.Enum.GetValues(type) as int[]); - } - - void ExportMosaicTexture() - { - var assetPath = ((AssetImporter)target).assetPath; - var texture2D = AssetDatabase.LoadAssetAtPath(assetPath); - if (texture2D == null) - return; - if (!texture2D.isReadable) - texture2D = InternalEditorBridge.CreateTemporaryDuplicate(texture2D, texture2D.width, texture2D.height); - var pixelData = texture2D.GetPixels(); - texture2D = new Texture2D(texture2D.width, texture2D.height); - texture2D.SetPixels(pixelData); - texture2D.Apply(); - byte[] bytes = texture2D.EncodeToPNG(); - var fileName = Path.GetFileNameWithoutExtension(assetPath); - var filePath = Path.GetDirectoryName(assetPath); - var savePath = Path.Combine(filePath, fileName + ".png"); - File.WriteAllBytes(savePath, bytes); - AssetDatabase.Refresh(); - } - - /// - /// Override of AssetImporterEditor.showImportedObject - /// The property always returns false so that imported objects does not show up in the Inspector. - /// - /// false - public override bool showImportedObject { get => false; } - - internal class Styles - { - public readonly GUIContent textureTypeTitle = new GUIContent("Texture Type", "What will this texture be used for?"); - public readonly GUIContent[] textureTypeOptions = - { - new GUIContent("Default", "Texture is a normal image such as a diffuse texture or other."), - new GUIContent("Sprite (2D and UI)", "Texture is used for a sprite."), - }; - public readonly int[] textureTypeValues = - { - (int)TextureImporterType.Default, - (int)TextureImporterType.Sprite, - }; - - public readonly GUIContent textureShape = new GUIContent("Texture Shape", "What shape is this texture?"); - private readonly GUIContent textureShape2D = new GUIContent("2D, Texture is 2D."); - private readonly GUIContent textureShapeCube = new GUIContent("Cube", "Texture is a Cubemap."); - public readonly Dictionary textureShapeOptionsDictionnary = new Dictionary(); - public readonly Dictionary textureShapeValuesDictionnary = new Dictionary(); - - - public readonly GUIContent filterMode = new GUIContent("Filter Mode"); - public readonly GUIContent[] filterModeOptions = - { - new GUIContent("Point (no filter)"), - new GUIContent("Bilinear"), - new GUIContent("Trilinear") - }; - - public readonly GUIContent textureFormat = new GUIContent("Format"); - - public readonly GUIContent defaultPlatform = new GUIContent("Default"); - public readonly GUIContent mipmapFadeOutToggle = new GUIContent("Fadeout Mip Maps"); - public readonly GUIContent mipmapFadeOut = new GUIContent("Fade Range"); - public readonly GUIContent readWrite = new GUIContent("Read/Write Enabled", "Enable to be able to access the raw pixel data from code."); - - public readonly GUIContent alphaSource = new GUIContent("Alpha Source", "How is the alpha generated for the imported texture."); - public readonly GUIContent[] alphaSourceOptions = - { - new GUIContent("None", "No Alpha will be used."), - new GUIContent("Input Texture Alpha", "Use Alpha from the input texture if one is provided."), - new GUIContent("From Gray Scale", "Generate Alpha from image gray scale."), - }; - public readonly int[] alphaSourceValues = - { - (int)TextureImporterAlphaSource.None, - (int)TextureImporterAlphaSource.FromInput, - (int)TextureImporterAlphaSource.FromGrayScale, - }; - - public readonly GUIContent generateMipMaps = new GUIContent("Generate Mip Maps"); - public readonly GUIContent sRGBTexture = new GUIContent("sRGB (Color Texture)", "Texture content is stored in gamma space. Non-HDR color textures should enable this flag (except if used for IMGUI)."); - public readonly GUIContent borderMipMaps = new GUIContent("Border Mip Maps"); - public readonly GUIContent mipMapsPreserveCoverage = new GUIContent("Mip Maps Preserve Coverage", "The alpha channel of generated Mip Maps will preserve coverage during the alpha test."); - public readonly GUIContent alphaTestReferenceValue = new GUIContent("Alpha Cutoff Value", "The reference value used during the alpha test. Controls Mip Map coverage."); - public readonly GUIContent mipMapFilter = new GUIContent("Mip Map Filtering"); - public readonly GUIContent[] mipMapFilterOptions = - { - new GUIContent("Box"), - new GUIContent("Kaiser"), - }; - public readonly GUIContent npot = new GUIContent("Non Power of 2", "How non-power-of-two textures are scaled on import."); - - public readonly GUIContent compressionQuality = new GUIContent("Compressor Quality"); - public readonly GUIContent compressionQualitySlider = new GUIContent("Compressor Quality", "Use the slider to adjust compression quality from 0 (Fastest) to 100 (Best)"); - public readonly GUIContent[] mobileCompressionQualityOptions = - { - new GUIContent("Fast"), - new GUIContent("Normal"), - new GUIContent("Best") - }; - - public readonly GUIContent spriteMode = new GUIContent("Sprite Mode"); - public readonly GUIContent[] spriteModeOptions = - { - new GUIContent("Single"), - new GUIContent("Multiple"), - new GUIContent("Polygon"), - }; - public readonly GUIContent[] spriteMeshTypeOptions = - { - new GUIContent("Full Rect"), - new GUIContent("Tight"), - }; - - public readonly GUIContent spritePackingTag = new GUIContent("Packing Tag", "Tag for the Sprite Packing system."); - public readonly GUIContent spritePixelsPerUnit = new GUIContent("Pixels Per Unit", "How many pixels in the sprite correspond to one unit in the world."); - public readonly GUIContent spriteExtrude = new GUIContent("Extrude Edges", "How much empty area to leave around the sprite in the generated mesh."); - public readonly GUIContent spriteMeshType = new GUIContent("Mesh Type", "Type of sprite mesh to generate."); - public readonly GUIContent spriteAlignment = new GUIContent("Pivot", "Sprite pivot point in its local space. May be used for syncing animation frames of different sizes."); - public readonly GUIContent characterAlignment = new GUIContent("Pivot", "Character pivot point in its local space using normalized value i.e. 0 - 1"); - - public readonly GUIContent[] spriteAlignmentOptions = - { - new GUIContent("Center"), - new GUIContent("Top Left"), - new GUIContent("Top"), - new GUIContent("Top Right"), - new GUIContent("Left"), - new GUIContent("Right"), - new GUIContent("Bottom Left"), - new GUIContent("Bottom"), - new GUIContent("Bottom Right"), - new GUIContent("Custom"), - }; - - public readonly GUIContent warpNotSupportWarning = new GUIContent("Graphics device doesn't support Repeat wrap mode on NPOT textures. Falling back to Clamp."); - public readonly GUIContent anisoLevelLabel = new GUIContent("Aniso Level"); - public readonly GUIContent anisotropicDisableInfo = new GUIContent("Anisotropic filtering is disabled for all textures in Quality Settings."); - public readonly GUIContent anisotropicForceEnableInfo = new GUIContent("Anisotropic filtering is enabled for all textures in Quality Settings."); - public readonly GUIContent unappliedSettingsDialogTitle = new GUIContent("Unapplied import settings"); - public readonly GUIContent unappliedSettingsDialogContent = new GUIContent("Unapplied import settings for \'{0}\'.\nApply and continue to sprite editor or cancel."); - public readonly GUIContent applyButtonLabel = new GUIContent("Apply"); - public readonly GUIContent revertButtonLabel = new GUIContent("Revert"); - public readonly GUIContent spriteEditorButtonLabel = new GUIContent("Sprite Editor"); - public readonly GUIContent resliceFromLayerWarning = new GUIContent("This will reinitialize and recreate all Sprites based on the file’s layer data. Existing Sprite metadata from previously generated Sprites are copied over."); - public readonly GUIContent alphaIsTransparency = new GUIContent("Alpha Is Transparency", "If the provided alpha channel is transparency, enable this to pre-filter the color to avoid texture filtering artifacts. This is not supported for HDR textures."); - public readonly GUIContent etc1Compression = new GUIContent("Compress using ETC1 (split alpha channel)|Alpha for this texture will be preserved by splitting the alpha channel to another texture, and both resulting textures will be compressed using ETC1."); - public readonly GUIContent crunchedCompression = new GUIContent("Use Crunch Compression", "Texture is crunch-compressed to save space on disk when applicable."); - - public readonly GUIContent showAdvanced = new GUIContent("Advanced", "Show advanced settings."); - - public readonly GUIContent platformSettingsLabel = new GUIContent("Platform Setttings"); - - public readonly GUIContent[] platformSettingsSelection; - - public readonly GUIContent wrapModeLabel = new GUIContent("Wrap Mode"); - public readonly GUIContent wrapU = new GUIContent("U axis"); - public readonly GUIContent wrapV = new GUIContent("V axis"); - public readonly GUIContent wrapW = new GUIContent("W axis"); - - - public readonly GUIContent[] wrapModeContents = - { - new GUIContent("Repeat"), - new GUIContent("Clamp"), - new GUIContent("Mirror"), - new GUIContent("Mirror Once"), - new GUIContent("Per-axis") - }; - public readonly int[] wrapModeValues = - { - (int)TextureWrapMode.Repeat, - (int)TextureWrapMode.Clamp, - (int)TextureWrapMode.Mirror, - (int)TextureWrapMode.MirrorOnce, - -1 - }; - - public readonly GUIContent importHiddenLayer = new GUIContent(L10n.Tr("Import Hidden"), L10n.Tr("Import hidden layers")); - public readonly GUIContent mosaicLayers = new GUIContent(L10n.Tr("Mosaic"), L10n.Tr("Layers will be imported as individual Sprites")); - public readonly GUIContent characterMode = new GUIContent(L10n.Tr("Character Rig"), L10n.Tr("Enable to support 2D Animation character rigging")); - public readonly GUIContent generateGOHierarchy = new GUIContent(L10n.Tr("Use Layer Grouping"), L10n.Tr("GameObjects are grouped according to source file layer grouping")); - public readonly GUIContent resliceFromLayer = new GUIContent(L10n.Tr("Reslice"), L10n.Tr("Recreate Sprite rects from file")); - public readonly GUIContent paperDollMode = new GUIContent(L10n.Tr("Paper Doll Mode"), L10n.Tr("Special mode to generate a Prefab for Paper Doll use case")); - public readonly GUIContent experimental = new GUIContent(L10n.Tr("Experimental")); - public readonly GUIContent keepDuplicateSpriteName = new GUIContent(L10n.Tr("Keep Duplicate Name"), L10n.Tr("Keep Sprite name same as Layer Name even if there are duplicated Layer Name")); - - public Styles() - { - // This is far from ideal, but it's better than having tons of logic in the GUI code itself. - // The combination should not grow too much anyway since only Texture3D will be added later. - GUIContent[] s2D_Options = { textureShape2D }; - GUIContent[] sCube_Options = { textureShapeCube }; - GUIContent[] s2D_Cube_Options = { textureShape2D, textureShapeCube }; - textureShapeOptionsDictionnary.Add(TextureImporterShape.Texture2D, s2D_Options); - textureShapeOptionsDictionnary.Add(TextureImporterShape.TextureCube, sCube_Options); - textureShapeOptionsDictionnary.Add(TextureImporterShape.Texture2D | TextureImporterShape.TextureCube, s2D_Cube_Options); - - int[] s2D_Values = { (int)TextureImporterShape.Texture2D }; - int[] sCube_Values = { (int)TextureImporterShape.TextureCube }; - int[] s2D_Cube_Values = { (int)TextureImporterShape.Texture2D, (int)TextureImporterShape.TextureCube }; - textureShapeValuesDictionnary.Add(TextureImporterShape.Texture2D, s2D_Values); - textureShapeValuesDictionnary.Add(TextureImporterShape.TextureCube, sCube_Values); - textureShapeValuesDictionnary.Add(TextureImporterShape.Texture2D | TextureImporterShape.TextureCube, s2D_Cube_Values); - - platformSettingsSelection = new GUIContent[TexturePlatformSettingsModal.kValidBuildPlatform.Length]; - for (int i = 0; i < TexturePlatformSettingsModal.kValidBuildPlatform.Length; ++i) - { - platformSettingsSelection[i] = new GUIContent(TexturePlatformSettingsModal.kValidBuildPlatform[i].buildTargetName); - } - } - } - - internal static Styles s_Styles; - } -} +using System; +using System.Collections.Generic; +using System.IO; +using PhotoshopFile; +using UnityEditor.Experimental.AssetImporters; +using UnityEditor.U2D.Animation; +using UnityEditor.U2D.Common; +using UnityEditor.U2D.Sprites; +using UnityEngine; + +namespace UnityEditor.U2D.PSD +{ + /// + /// Inspector for PSDImporter + /// + [CustomEditor(typeof(PSDImporter))] + public class PSDImporterEditor : ScriptedImporterEditor, ITexturePlatformSettingsDataProvider + { + SerializedProperty m_TextureType; + SerializedProperty m_TextureShape; + SerializedProperty m_SpriteMode; + SerializedProperty m_SpritePixelsToUnits; + SerializedProperty m_SpriteMeshType; + SerializedProperty m_SpriteExtrude; + SerializedProperty m_Alignment; + SerializedProperty m_SpritePivot; + SerializedProperty m_NPOTScale; + SerializedProperty m_IsReadable; + SerializedProperty m_sRGBTexture; + SerializedProperty m_AlphaSource; + SerializedProperty m_MipMapMode; + SerializedProperty m_EnableMipMap; + SerializedProperty m_FadeOut; + SerializedProperty m_BorderMipMap; + SerializedProperty m_MipMapsPreserveCoverage; + SerializedProperty m_AlphaTestReferenceValue; + SerializedProperty m_MipMapFadeDistanceStart; + SerializedProperty m_MipMapFadeDistanceEnd; + SerializedProperty m_AlphaIsTransparency; + SerializedProperty m_FilterMode; + SerializedProperty m_Aniso; + + SerializedProperty m_WrapU; + SerializedProperty m_WrapV; + SerializedProperty m_WrapW; + SerializedProperty m_ConvertToNormalMap; + SerializedProperty m_MosaicLayers; + SerializedProperty m_ImportHiddenLayers; + SerializedProperty m_ResliceFromLayer; + SerializedProperty m_CharacterMode; + SerializedProperty m_DocumentPivot; + SerializedProperty m_DocumentAlignment; + SerializedProperty m_GenerateGOHierarchy; + SerializedProperty m_PaperDollMode; + SerializedProperty m_KeepDupilcateSpriteName; + + readonly int[] m_FilterModeOptions = (int[])(Enum.GetValues(typeof(FilterMode))); + + bool m_IsPOT = false; + bool m_ShowAdvanced = false; + bool m_ShowExperimental = false; + Dictionary m_AdvanceInspectorGUI = new Dictionary(); + int m_PlatformSettingsIndex; + bool m_ShowPerAxisWrapModes = false; + + TexturePlatformSettingsHelper m_TexturePlatformSettingsHelper; + + TexturePlatformSettingsView m_TexturePlatformSettingsView = new TexturePlatformSettingsView(); + TexturePlatformSettingsController m_TexturePlatformSettingsController = new TexturePlatformSettingsController(); + + /// + /// Implementation of AssetImporterEditor.OnEnable + /// + public override void OnEnable() + { + base.OnEnable(); + m_MosaicLayers = serializedObject.FindProperty("m_MosaicLayers"); + m_ImportHiddenLayers = serializedObject.FindProperty("m_ImportHiddenLayers"); + m_ResliceFromLayer = serializedObject.FindProperty("m_ResliceFromLayer"); + m_CharacterMode = serializedObject.FindProperty("m_CharacterMode"); + m_DocumentPivot = serializedObject.FindProperty("m_DocumentPivot"); + m_DocumentAlignment = serializedObject.FindProperty("m_DocumentAlignment"); + m_GenerateGOHierarchy = serializedObject.FindProperty("m_GenerateGOHierarchy"); + m_PaperDollMode = serializedObject.FindProperty("m_PaperDollMode"); + m_KeepDupilcateSpriteName = serializedObject.FindProperty("m_KeepDupilcateSpriteName"); + + var textureImporterSettingsSP = serializedObject.FindProperty("m_TextureImporterSettings"); + m_TextureType = textureImporterSettingsSP.FindPropertyRelative("m_TextureType"); + m_TextureShape = textureImporterSettingsSP.FindPropertyRelative("m_TextureShape"); + m_ConvertToNormalMap = textureImporterSettingsSP.FindPropertyRelative("m_ConvertToNormalMap"); + m_SpriteMode = textureImporterSettingsSP.FindPropertyRelative("m_SpriteMode"); + m_SpritePixelsToUnits = textureImporterSettingsSP.FindPropertyRelative("m_SpritePixelsToUnits"); + m_SpriteMeshType = textureImporterSettingsSP.FindPropertyRelative("m_SpriteMeshType"); + m_SpriteExtrude = textureImporterSettingsSP.FindPropertyRelative("m_SpriteExtrude"); + m_Alignment = textureImporterSettingsSP.FindPropertyRelative("m_Alignment"); + m_SpritePivot = textureImporterSettingsSP.FindPropertyRelative("m_SpritePivot"); + m_NPOTScale = textureImporterSettingsSP.FindPropertyRelative("m_NPOTScale"); + m_IsReadable = textureImporterSettingsSP.FindPropertyRelative("m_IsReadable"); + m_sRGBTexture = textureImporterSettingsSP.FindPropertyRelative("m_sRGBTexture"); + m_AlphaSource = textureImporterSettingsSP.FindPropertyRelative("m_AlphaSource"); + m_MipMapMode = textureImporterSettingsSP.FindPropertyRelative("m_MipMapMode"); + m_EnableMipMap = textureImporterSettingsSP.FindPropertyRelative("m_EnableMipMap"); + m_FadeOut = textureImporterSettingsSP.FindPropertyRelative("m_FadeOut"); + m_BorderMipMap = textureImporterSettingsSP.FindPropertyRelative("m_BorderMipMap"); + m_MipMapsPreserveCoverage = textureImporterSettingsSP.FindPropertyRelative("m_MipMapsPreserveCoverage"); + m_AlphaTestReferenceValue = textureImporterSettingsSP.FindPropertyRelative("m_AlphaTestReferenceValue"); + m_MipMapFadeDistanceStart = textureImporterSettingsSP.FindPropertyRelative("m_MipMapFadeDistanceStart"); + m_MipMapFadeDistanceEnd = textureImporterSettingsSP.FindPropertyRelative("m_MipMapFadeDistanceEnd"); + m_AlphaIsTransparency = textureImporterSettingsSP.FindPropertyRelative("m_AlphaIsTransparency"); + m_FilterMode = textureImporterSettingsSP.FindPropertyRelative("m_FilterMode"); + m_Aniso = textureImporterSettingsSP.FindPropertyRelative("m_Aniso"); + m_WrapU = textureImporterSettingsSP.FindPropertyRelative("m_WrapU"); + m_WrapV = textureImporterSettingsSP.FindPropertyRelative("m_WrapV"); + m_WrapW = textureImporterSettingsSP.FindPropertyRelative("m_WrapW"); + + var textureWidth = serializedObject.FindProperty("m_TextureActualWidth"); + var textureHeight = serializedObject.FindProperty("m_TextureActualHeight"); + m_IsPOT = Mathf.IsPowerOfTwo(textureWidth.intValue) && Mathf.IsPowerOfTwo(textureHeight.intValue); + + + var advanceGUIAction = new Action[] + { + ColorSpaceGUI, + AlphaHandlingGUI, + POTScaleGUI, + ReadableGUI, + MipMapGUI + }; + m_AdvanceInspectorGUI.Add(TextureImporterType.Sprite, advanceGUIAction); + + advanceGUIAction = new Action[] + { + POTScaleGUI, + ReadableGUI, + MipMapGUI + }; + m_AdvanceInspectorGUI.Add(TextureImporterType.Default, advanceGUIAction); + LoadPlatformSettings(); + m_TexturePlatformSettingsHelper = new TexturePlatformSettingsHelper(this); + } + + /// + /// Implementation of AssetImporterEditor.OnInspectorGUI + /// + public override void OnInspectorGUI() + { + serializedObject.Update(); + if (s_Styles == null) + s_Styles = new Styles(); + + EditorGUI.showMixedValue = m_TextureType.hasMultipleDifferentValues; + m_TextureType.intValue = EditorGUILayout.IntPopup(s_Styles.textureTypeTitle, m_TextureType.intValue, s_Styles.textureTypeOptions, s_Styles.textureTypeValues); + EditorGUI.showMixedValue = false; + + switch ((TextureImporterType)m_TextureType.intValue) + { + case TextureImporterType.Sprite: + DoSpriteInspector(); + break; + case TextureImporterType.Default: + DoTextureDefaultInspector(); + break; + default: + Debug.LogWarning("We only support Default or Sprite texture type for now. Texture type is set to default."); + m_TextureType.intValue = (int)TextureImporterType.Default; + break; + } + + DoAdvanceInspector(); + CommonTextureSettingsGUI(); + GUILayout.Space(10); + DoPlatformSettings(); + serializedObject.ApplyModifiedProperties(); + ApplyRevertGUI(); + } + + /// + /// Implementation of AssetImporterEditor.Apply + /// + protected override void Apply() + { + FileStream fileStream = new FileStream(((AssetImporter)target).assetPath, FileMode.Open, FileAccess.Read); + var doc = PaintDotNet.Data.PhotoshopFileType.PsdLoad.Load(fileStream, ELoadFlag.Header | ELoadFlag.ColorMode); + + PSDApplyEvent evt = new PSDApplyEvent() + { + instance_id = target.GetInstanceID(), + texture_type = m_TextureType.intValue, + sprite_mode = m_SpriteMode.intValue, + mosaic_layer = m_MosaicLayers.boolValue, + import_hidden_layer = m_ImportHiddenLayers.boolValue, + character_mode = m_CharacterMode.boolValue, + generate_go_hierarchy = m_GenerateGOHierarchy.boolValue, + reslice_from_layer = m_ResliceFromLayer.boolValue, + is_character_rigged = IsCharacterRigged(), + is_psd = IsPSD(doc), + color_mode = FileColorMode(doc) + }; + doc.Cleanup(); + AnalyticFactory.analytics.SendApplyEvent(evt); + m_TexturePlatformSettingsHelper.Apply(); + base.Apply(); + Selection.activeObject = null; + Unsupported.SceneTrackerFlushDirty(); + PSDImportPostProcessor.currentApplyAssetPath = ((PSDImporter) target).assetPath; + } + + static bool IsPSD(PsdFile doc) + { + return !doc.IsLargeDocument; + } + + static PsdColorMode FileColorMode(PsdFile doc) + { + return doc.ColorMode; + } + + bool IsCharacterRigged() + { + var importer = target as PSDImporter; + if (importer != null) + { + var characterProvider = importer.GetDataProvider(); + var meshDataProvider = importer.GetDataProvider(); + if (characterProvider != null && meshDataProvider != null) + { + var character = characterProvider.GetCharacterData(); + foreach (var parts in character.parts) + { + var vert = meshDataProvider.GetVertices(new GUID(parts.spriteId)); + var indices = meshDataProvider.GetIndices(new GUID(parts.spriteId)); + if (parts.bones != null && parts.bones.Length > 0 && + vert != null && vert.Length > 0 && + indices != null && indices.Length > 0) + return true; + } + } + } + return false; + } + + Dictionary> m_PlatfromSettings = new Dictionary>(); + void LoadPlatformSettings() + { + foreach (var t in targets) + { + var importer = ((PSDImporter)t); + var importerPlatformSettings = importer.GetAllPlatformSettings(); + for (int i = 0; i < importerPlatformSettings.Length; ++i) + { + var tip = importerPlatformSettings[i]; + List platformSettings = null; + m_PlatfromSettings.TryGetValue(tip.name, out platformSettings); + if (platformSettings == null) + { + platformSettings = new List(); + m_PlatfromSettings.Add(tip.name, platformSettings); + } + platformSettings.Add(tip); + } + } + } + + void StorePlatformSettings() + { + var platformSettingsSP = serializedObject.FindProperty("m_PlatformSettings"); + platformSettingsSP.ClearArray(); + foreach (var keyValue in m_PlatfromSettings) + { + if (!keyValue.Value[0].overridden) + continue; + + SerializedProperty platformSettingSP = null; + for (int i = 0; i < platformSettingsSP.arraySize; ++i) + { + var sp = platformSettingsSP.GetArrayElementAtIndex(i); + if (sp.FindPropertyRelative("m_Name").stringValue == keyValue.Key) + platformSettingSP = sp; + } + if (platformSettingSP == null) + { + platformSettingsSP.InsertArrayElementAtIndex(platformSettingsSP.arraySize); + platformSettingSP = platformSettingsSP.GetArrayElementAtIndex(platformSettingsSP.arraySize - 1); + } + + var tip = keyValue.Value[0]; + platformSettingSP.FindPropertyRelative("m_Name").stringValue = tip.name; + platformSettingSP.FindPropertyRelative("m_Overridden").intValue = tip.overridden ? 1 : 0; + platformSettingSP.FindPropertyRelative("m_MaxTextureSize").intValue = tip.maxTextureSize; + platformSettingSP.FindPropertyRelative("m_ResizeAlgorithm").intValue = (int)tip.resizeAlgorithm; + platformSettingSP.FindPropertyRelative("m_TextureFormat").intValue = (int)tip.format; + platformSettingSP.FindPropertyRelative("m_TextureCompression").intValue = (int)tip.textureCompression; + platformSettingSP.FindPropertyRelative("m_CompressionQuality").intValue = tip.compressionQuality; + platformSettingSP.FindPropertyRelative("m_CrunchedCompression").intValue = tip.crunchedCompression ? 1 : 0; + platformSettingSP.FindPropertyRelative("m_AllowsAlphaSplitting").intValue = tip.allowsAlphaSplitting ? 1 : 0; + } + } + + void DoPlatformSettings() + { + m_TexturePlatformSettingsHelper.ShowPlatformSpecificSettings(); + } + + void DoAdvanceInspector() + { + if (!m_TextureType.hasMultipleDifferentValues) + { + if (m_AdvanceInspectorGUI.ContainsKey((TextureImporterType)m_TextureType.intValue)) + { + EditorGUILayout.Space(); + + m_ShowAdvanced = EditorGUILayout.Foldout(m_ShowAdvanced, s_Styles.showAdvanced, true); + if (m_ShowAdvanced) + { + foreach (var action in m_AdvanceInspectorGUI[(TextureImporterType)m_TextureType.intValue]) + { + action(); + } + } + } + } + EditorGUILayout.Space(); + } + + void CommonTextureSettingsGUI() + { + EditorGUI.BeginChangeCheck(); + + // Wrap mode + bool isVolume = false; + WrapModePopup(m_WrapU, m_WrapV, m_WrapW, isVolume, ref m_ShowPerAxisWrapModes); + + + // Display warning about repeat wrap mode on restricted npot emulation + if (m_NPOTScale.intValue == (int)TextureImporterNPOTScale.None && + (m_WrapU.intValue == (int)TextureWrapMode.Repeat || m_WrapV.intValue == (int)TextureWrapMode.Repeat) && + !InternalEditorBridge.DoesHardwareSupportsFullNPOT()) + { + bool displayWarning = false; + foreach (var target in targets) + { + var imp = (PSDImporter)target; + int w = imp.textureActualWidth; + int h = imp.textureActualHeight; + if (!Mathf.IsPowerOfTwo(w) || !Mathf.IsPowerOfTwo(h)) + { + displayWarning = true; + break; + } + } + + if (displayWarning) + { + EditorGUILayout.HelpBox(s_Styles.warpNotSupportWarning.text, MessageType.Warning, true); + } + } + + // Filter mode + EditorGUI.showMixedValue = m_FilterMode.hasMultipleDifferentValues; + FilterMode filter = (FilterMode)m_FilterMode.intValue; + if ((int)filter == -1) + { + if (m_FadeOut.intValue > 0 || m_ConvertToNormalMap.intValue > 0) + filter = FilterMode.Trilinear; + else + filter = FilterMode.Bilinear; + } + filter = (FilterMode)EditorGUILayout.IntPopup(s_Styles.filterMode, (int)filter, s_Styles.filterModeOptions, m_FilterModeOptions); + EditorGUI.showMixedValue = false; + if (EditorGUI.EndChangeCheck()) + m_FilterMode.intValue = (int)filter; + + // Aniso + bool showAniso = (FilterMode)m_FilterMode.intValue != FilterMode.Point + && m_EnableMipMap.intValue > 0 + && (TextureImporterShape)m_TextureShape.intValue != TextureImporterShape.TextureCube; + using (new EditorGUI.DisabledScope(!showAniso)) + { + EditorGUI.BeginChangeCheck(); + EditorGUI.showMixedValue = m_Aniso.hasMultipleDifferentValues; + int aniso = m_Aniso.intValue; + if (aniso == -1) + aniso = 1; + aniso = EditorGUILayout.IntSlider(s_Styles.anisoLevelLabel, aniso, 0, 16); + EditorGUI.showMixedValue = false; + if (EditorGUI.EndChangeCheck()) + m_Aniso.intValue = aniso; + + if (aniso > 1) + { + if (QualitySettings.anisotropicFiltering == AnisotropicFiltering.Disable) + EditorGUILayout.HelpBox(s_Styles.anisotropicDisableInfo.text, MessageType.Info); + else if (QualitySettings.anisotropicFiltering == AnisotropicFiltering.ForceEnable) + EditorGUILayout.HelpBox(s_Styles.anisotropicForceEnableInfo.text, MessageType.Info); + } + } + } + + private static bool IsAnyTextureObjectUsingPerAxisWrapMode(UnityEngine.Object[] objects, bool isVolumeTexture) + { + foreach (var o in objects) + { + int u = 0, v = 0, w = 0; + // the objects can be Textures themselves, or texture-related importers + if (o is Texture) + { + var ti = (Texture)o; + u = (int)ti.wrapModeU; + v = (int)ti.wrapModeV; + w = (int)ti.wrapModeW; + } + if (o is TextureImporter) + { + var ti = (TextureImporter)o; + u = (int)ti.wrapModeU; + v = (int)ti.wrapModeV; + w = (int)ti.wrapModeW; + } + if (o is IHVImageFormatImporter) + { + var ti = (IHVImageFormatImporter)o; + u = (int)ti.wrapModeU; + v = (int)ti.wrapModeV; + w = (int)ti.wrapModeW; + } + u = Mathf.Max(0, u); + v = Mathf.Max(0, v); + w = Mathf.Max(0, w); + if (u != v) + { + return true; + } + if (isVolumeTexture) + { + if (u != w || v != w) + { + return true; + } + } + } + return false; + } + + // showPerAxisWrapModes is state of whether "Per-Axis" mode should be active in the main dropdown. + // It is set automatically if wrap modes in UVW are different, or if user explicitly picks "Per-Axis" option -- when that one is picked, + // then it should stay true even if UVW wrap modes will initially be the same. + // + // Note: W wrapping mode is only shown when isVolumeTexture is true. + internal static void WrapModePopup(SerializedProperty wrapU, SerializedProperty wrapV, SerializedProperty wrapW, bool isVolumeTexture, ref bool showPerAxisWrapModes) + { + if (s_Styles == null) + s_Styles = new Styles(); + + // In texture importer settings, serialized properties for things like wrap modes can contain -1; + // that seems to indicate "use defaults, user has not changed them to anything" but not totally sure. + // Show them as Repeat wrap modes in the popups. + var wu = (TextureWrapMode)Mathf.Max(wrapU.intValue, 0); + var wv = (TextureWrapMode)Mathf.Max(wrapV.intValue, 0); + var ww = (TextureWrapMode)Mathf.Max(wrapW.intValue, 0); + + // automatically go into per-axis mode if values are already different + if (wu != wv) + showPerAxisWrapModes = true; + if (isVolumeTexture) + { + if (wu != ww || wv != ww) + showPerAxisWrapModes = true; + } + + // It's not possible to determine whether any single texture in the whole selection is using per-axis wrap modes + // just from SerializedProperty values. They can only tell if "some values in whole selection are different" (e.g. + // wrap value on U axis is not the same among all textures), and can return value of "some" object in the selection + // (typically based on object loading order). So in order for more intuitive behavior with multi-selection, + // we go over the actual objects when there's >1 object selected and some wrap modes are different. + if (!showPerAxisWrapModes) + { + if (wrapU.hasMultipleDifferentValues || wrapV.hasMultipleDifferentValues || (isVolumeTexture && wrapW.hasMultipleDifferentValues)) + { + if (IsAnyTextureObjectUsingPerAxisWrapMode(wrapU.serializedObject.targetObjects, isVolumeTexture)) + { + showPerAxisWrapModes = true; + } + } + } + + int value = showPerAxisWrapModes ? -1 : (int)wu; + + // main wrap mode popup + EditorGUI.BeginChangeCheck(); + EditorGUI.showMixedValue = !showPerAxisWrapModes && (wrapU.hasMultipleDifferentValues || wrapV.hasMultipleDifferentValues || (isVolumeTexture && wrapW.hasMultipleDifferentValues)); + value = EditorGUILayout.IntPopup(s_Styles.wrapModeLabel, value, s_Styles.wrapModeContents, s_Styles.wrapModeValues); + if (EditorGUI.EndChangeCheck() && value != -1) + { + // assign the same wrap mode to all axes, and hide per-axis popups + wrapU.intValue = value; + wrapV.intValue = value; + wrapW.intValue = value; + showPerAxisWrapModes = false; + } + + // show per-axis popups if needed + if (value == -1) + { + showPerAxisWrapModes = true; + EditorGUI.indentLevel++; + WrapModeAxisPopup(s_Styles.wrapU, wrapU); + WrapModeAxisPopup(s_Styles.wrapV, wrapV); + if (isVolumeTexture) + { + WrapModeAxisPopup(s_Styles.wrapW, wrapW); + } + EditorGUI.indentLevel--; + } + EditorGUI.showMixedValue = false; + } + + static void WrapModeAxisPopup(GUIContent label, SerializedProperty wrapProperty) + { + // In texture importer settings, serialized properties for wrap modes can contain -1, which means "use default". + var wrap = (TextureWrapMode)Mathf.Max(wrapProperty.intValue, 0); + Rect rect = EditorGUILayout.GetControlRect(); + EditorGUI.BeginChangeCheck(); + EditorGUI.BeginProperty(rect, label, wrapProperty); + wrap = (TextureWrapMode)EditorGUI.EnumPopup(rect, label, wrap); + EditorGUI.EndProperty(); + if (EditorGUI.EndChangeCheck()) + { + wrapProperty.intValue = (int)wrap; + } + } + + void DoWrapModePopup() + { + WrapModePopup(m_WrapU, m_WrapV, m_WrapW, IsVolume(), ref m_ShowPerAxisWrapModes); + } + + bool IsVolume() + { + var t = target as Texture; + return t != null && t.dimension == UnityEngine.Rendering.TextureDimension.Tex3D; + } + + void DoSpriteInspector() + { + EditorGUI.BeginChangeCheck(); + EditorGUILayout.IntPopup(m_SpriteMode, s_Styles.spriteModeOptions, new[] { 1, 2, 3 }, s_Styles.spriteMode); + + // Ensure that PropertyField focus will be cleared when we change spriteMode. + if (EditorGUI.EndChangeCheck()) + { + GUIUtility.keyboardControl = 0; + } + + EditorGUI.indentLevel++; + + // Show generic attributes + if (m_SpriteMode.intValue != 0) + { + EditorGUILayout.PropertyField(m_SpritePixelsToUnits, s_Styles.spritePixelsPerUnit); + + if (m_SpriteMode.intValue != (int)SpriteImportMode.Polygon && !m_SpriteMode.hasMultipleDifferentValues) + { + EditorGUILayout.IntPopup(m_SpriteMeshType, s_Styles.spriteMeshTypeOptions, new[] { 0, 1 }, s_Styles.spriteMeshType); + } + + EditorGUILayout.IntSlider(m_SpriteExtrude, 0, 32, s_Styles.spriteExtrude); + + if (m_SpriteMode.intValue == 1) + { + EditorGUILayout.IntPopup(m_Alignment, s_Styles.spriteAlignmentOptions, new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, s_Styles.spriteAlignment); + + if (m_Alignment.intValue == (int)SpriteAlignment.Custom) + { + GUILayout.BeginHorizontal(); + EditorGUILayout.PropertyField(m_SpritePivot, new GUIContent()); + GUILayout.EndHorizontal(); + } + } + } + + EditorGUILayout.PropertyField(m_ImportHiddenLayers, s_Styles.importHiddenLayer); + if (m_SpriteMode.intValue == (int)SpriteImportMode.Multiple && !m_SpriteMode.hasMultipleDifferentValues) + { + EditorGUILayout.PropertyField(m_MosaicLayers, s_Styles.mosaicLayers); + using (new EditorGUI.DisabledScope(!m_MosaicLayers.boolValue)) + { + EditorGUILayout.PropertyField(m_CharacterMode, s_Styles.characterMode); + using (new EditorGUI.DisabledScope(!m_CharacterMode.boolValue)) + { + EditorGUILayout.PropertyField(m_GenerateGOHierarchy, s_Styles.generateGOHierarchy); + EditorGUILayout.IntPopup(m_DocumentAlignment, s_Styles.spriteAlignmentOptions, new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, s_Styles.characterAlignment); + if (m_DocumentAlignment.intValue == (int)SpriteAlignment.Custom) + { + GUILayout.BeginHorizontal(); + GUILayout.Space(EditorGUIUtility.labelWidth); + EditorGUILayout.PropertyField(m_DocumentPivot, new GUIContent()); + GUILayout.EndHorizontal(); + } + //EditorGUILayout.PropertyField(m_PaperDollMode, s_Styles.paperDollMode); + } + + + EditorGUILayout.PropertyField(m_ResliceFromLayer, s_Styles.resliceFromLayer); + if (m_ResliceFromLayer.boolValue) + { + EditorGUILayout.HelpBox(s_Styles.resliceFromLayerWarning.text, MessageType.Info, true); + } + } + m_ShowExperimental = EditorGUILayout.Foldout(m_ShowExperimental, s_Styles.experimental, true); + if (m_ShowExperimental) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(m_KeepDupilcateSpriteName, s_Styles.keepDuplicateSpriteName); + EditorGUI.indentLevel--; + } + } + + using (new EditorGUI.DisabledScope(targets.Length != 1)) + { + GUILayout.BeginHorizontal(); + + GUILayout.FlexibleSpace(); + if (GUILayout.Button(s_Styles.spriteEditorButtonLabel)) + { + if (HasModified()) + { + // To ensure Sprite Editor Window to have the latest texture import setting, + // We must applied those modified values first. + string dialogText = string.Format(s_Styles.unappliedSettingsDialogContent.text, ((AssetImporter)target).assetPath); + if (EditorUtility.DisplayDialog(s_Styles.unappliedSettingsDialogTitle.text, + dialogText, s_Styles.applyButtonLabel.text, s_Styles.revertButtonLabel.text)) + { + ApplyAndImport(); + InternalEditorBridge.ShowSpriteEditorWindow(); + + // We reimported the asset which destroyed the editor, so we can't keep running the UI here. + GUIUtility.ExitGUI(); + } + } + else + { + InternalEditorBridge.ShowSpriteEditorWindow(); + } + } + GUILayout.EndHorizontal(); + } + EditorGUI.indentLevel--; + } + + void DoTextureDefaultInspector() + { + ColorSpaceGUI(); + AlphaHandlingGUI(); + } + + void ColorSpaceGUI() + { + ToggleFromInt(m_sRGBTexture, s_Styles.sRGBTexture); + } + + void POTScaleGUI() + { + using (new EditorGUI.DisabledScope(m_IsPOT || m_TextureType.intValue == (int)TextureImporterType.Sprite)) + { + EnumPopup(m_NPOTScale, typeof(TextureImporterNPOTScale), s_Styles.npot); + } + } + + void ReadableGUI() + { + ToggleFromInt(m_IsReadable, s_Styles.readWrite); + } + + void AlphaHandlingGUI() + { + EditorGUI.showMixedValue = m_AlphaSource.hasMultipleDifferentValues; + EditorGUI.BeginChangeCheck(); + int newAlphaUsage = EditorGUILayout.IntPopup(s_Styles.alphaSource, m_AlphaSource.intValue, s_Styles.alphaSourceOptions, s_Styles.alphaSourceValues); + + EditorGUI.showMixedValue = false; + if (EditorGUI.EndChangeCheck()) + { + m_AlphaSource.intValue = newAlphaUsage; + } + + bool showAlphaIsTransparency = (TextureImporterAlphaSource)m_AlphaSource.intValue != TextureImporterAlphaSource.None; + using (new EditorGUI.DisabledScope(!showAlphaIsTransparency)) + { + ToggleFromInt(m_AlphaIsTransparency, s_Styles.alphaIsTransparency); + } + } + + void MipMapGUI() + { + ToggleFromInt(m_EnableMipMap, s_Styles.generateMipMaps); + + if (m_EnableMipMap.boolValue && !m_EnableMipMap.hasMultipleDifferentValues) + { + EditorGUI.indentLevel++; + ToggleFromInt(m_BorderMipMap, s_Styles.borderMipMaps); + EditorGUILayout.Popup(s_Styles.mipMapFilter, m_MipMapMode.intValue, s_Styles.mipMapFilterOptions); + + ToggleFromInt(m_MipMapsPreserveCoverage, s_Styles.mipMapsPreserveCoverage); + if (m_MipMapsPreserveCoverage.intValue != 0 && !m_MipMapsPreserveCoverage.hasMultipleDifferentValues) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(m_AlphaTestReferenceValue, s_Styles.alphaTestReferenceValue); + EditorGUI.indentLevel--; + } + + // Mipmap fadeout + ToggleFromInt(m_FadeOut, s_Styles.mipmapFadeOutToggle); + if (m_FadeOut.intValue > 0) + { + EditorGUI.indentLevel++; + EditorGUI.BeginChangeCheck(); + float min = m_MipMapFadeDistanceStart.intValue; + float max = m_MipMapFadeDistanceEnd.intValue; + EditorGUILayout.MinMaxSlider(s_Styles.mipmapFadeOut, ref min, ref max, 0, 10); + if (EditorGUI.EndChangeCheck()) + { + m_MipMapFadeDistanceStart.intValue = Mathf.RoundToInt(min); + m_MipMapFadeDistanceEnd.intValue = Mathf.RoundToInt(max); + } + EditorGUI.indentLevel--; + } + EditorGUI.indentLevel--; + } + } + + void ToggleFromInt(SerializedProperty property, GUIContent label) + { + EditorGUI.BeginChangeCheck(); + EditorGUI.showMixedValue = property.hasMultipleDifferentValues; + int value = EditorGUILayout.Toggle(label, property.intValue > 0) ? 1 : 0; + EditorGUI.showMixedValue = false; + if (EditorGUI.EndChangeCheck()) + property.intValue = value; + } + + void EnumPopup(SerializedProperty property, System.Type type, GUIContent label) + { + EditorGUILayout.IntPopup(label.text, property.intValue, + System.Enum.GetNames(type), + System.Enum.GetValues(type) as int[]); + } + + void ExportMosaicTexture() + { + var assetPath = ((AssetImporter)target).assetPath; + var texture2D = AssetDatabase.LoadAssetAtPath(assetPath); + if (texture2D == null) + return; + if (!texture2D.isReadable) + texture2D = InternalEditorBridge.CreateTemporaryDuplicate(texture2D, texture2D.width, texture2D.height); + var pixelData = texture2D.GetPixels(); + texture2D = new Texture2D(texture2D.width, texture2D.height); + texture2D.SetPixels(pixelData); + texture2D.Apply(); + byte[] bytes = texture2D.EncodeToPNG(); + var fileName = Path.GetFileNameWithoutExtension(assetPath); + var filePath = Path.GetDirectoryName(assetPath); + var savePath = Path.Combine(filePath, fileName + ".png"); + File.WriteAllBytes(savePath, bytes); + AssetDatabase.Refresh(); + } + + protected override void ResetValues() + { + base.ResetValues(); + LoadPlatformSettings(); + m_TexturePlatformSettingsHelper = new TexturePlatformSettingsHelper(this); + } + + public int GetTargetCount() + { + return targets.Length; + } + + public TextureImporterPlatformSettings GetPlatformTextureSettings(int i, string name) + { + if(m_PlatfromSettings.ContainsKey(name)) + if(m_PlatfromSettings[name].Count > i) + return m_PlatfromSettings[name][i]; + return new TextureImporterPlatformSettings() + { + name = name, + overridden = false + }; + } + + public bool ShowPresetSettings() + { + return assetTarget == null; + } + + public bool DoesSourceTextureHaveAlpha(int v) + { + return true; + } + + public bool IsSourceTextureHDR(int v) + { + return false; + } + + public void SetPlatformTextureSettings(int i, TextureImporterPlatformSettings platformSettings) + { + var psdImporter = ((PSDImporter)targets[i]); + psdImporter.SetPlatformTextureSettings(platformSettings); + psdImporter.Apply(); + } + + public void GetImporterSettings(int i, TextureImporterSettings settings) + { + ((PSDImporter)targets[i]).ReadTextureSettings(settings); + // Get settings that have been changed in the inspector + GetSerializedPropertySettings(settings); + } + + internal TextureImporterSettings GetSerializedPropertySettings(TextureImporterSettings settings) + { + if (!m_AlphaSource.hasMultipleDifferentValues) + settings.alphaSource = (TextureImporterAlphaSource)m_AlphaSource.intValue; + + if (!m_ConvertToNormalMap.hasMultipleDifferentValues) + settings.convertToNormalMap = m_ConvertToNormalMap.intValue > 0; + + if (!m_BorderMipMap.hasMultipleDifferentValues) + settings.borderMipmap = m_BorderMipMap.intValue > 0; + + if (!m_MipMapsPreserveCoverage.hasMultipleDifferentValues) + settings.mipMapsPreserveCoverage = m_MipMapsPreserveCoverage.intValue > 0; + + if (!m_AlphaTestReferenceValue.hasMultipleDifferentValues) + settings.alphaTestReferenceValue = m_AlphaTestReferenceValue.floatValue; + + if (!m_NPOTScale.hasMultipleDifferentValues) + settings.npotScale = (TextureImporterNPOTScale)m_NPOTScale.intValue; + + if (!m_IsReadable.hasMultipleDifferentValues) + settings.readable = m_IsReadable.intValue > 0; + + if (!m_sRGBTexture.hasMultipleDifferentValues) + settings.sRGBTexture = m_sRGBTexture.intValue > 0; + + if (!m_EnableMipMap.hasMultipleDifferentValues) + settings.mipmapEnabled = m_EnableMipMap.intValue > 0; + + if (!m_MipMapMode.hasMultipleDifferentValues) + settings.mipmapFilter = (TextureImporterMipFilter)m_MipMapMode.intValue; + + if (!m_FadeOut.hasMultipleDifferentValues) + settings.fadeOut = m_FadeOut.intValue > 0; + + if (!m_MipMapFadeDistanceStart.hasMultipleDifferentValues) + settings.mipmapFadeDistanceStart = m_MipMapFadeDistanceStart.intValue; + + if (!m_MipMapFadeDistanceEnd.hasMultipleDifferentValues) + settings.mipmapFadeDistanceEnd = m_MipMapFadeDistanceEnd.intValue; + + if (!m_SpriteMode.hasMultipleDifferentValues) + settings.spriteMode = m_SpriteMode.intValue; + + if (!m_SpritePixelsToUnits.hasMultipleDifferentValues) + settings.spritePixelsPerUnit = m_SpritePixelsToUnits.floatValue; + + if (!m_SpriteExtrude.hasMultipleDifferentValues) + settings.spriteExtrude = (uint)m_SpriteExtrude.intValue; + + if (!m_SpriteMeshType.hasMultipleDifferentValues) + settings.spriteMeshType = (SpriteMeshType)m_SpriteMeshType.intValue; + + if (!m_Alignment.hasMultipleDifferentValues) + settings.spriteAlignment = m_Alignment.intValue; + + if (!m_SpritePivot.hasMultipleDifferentValues) + settings.spritePivot = m_SpritePivot.vector2Value; + + if (!m_WrapU.hasMultipleDifferentValues) + settings.wrapModeU = (TextureWrapMode)m_WrapU.intValue; + if (!m_WrapV.hasMultipleDifferentValues) + settings.wrapModeU = (TextureWrapMode)m_WrapV.intValue; + if (!m_WrapW.hasMultipleDifferentValues) + settings.wrapModeU = (TextureWrapMode)m_WrapW.intValue; + + if (!m_FilterMode.hasMultipleDifferentValues) + settings.filterMode = (FilterMode)m_FilterMode.intValue; + + if (!m_Aniso.hasMultipleDifferentValues) + settings.aniso = m_Aniso.intValue; + + + if (!m_AlphaIsTransparency.hasMultipleDifferentValues) + settings.alphaIsTransparency = m_AlphaIsTransparency.intValue > 0; + + if (!m_TextureType.hasMultipleDifferentValues) + settings.textureType = (TextureImporterType)m_TextureType.intValue; + + if (!m_TextureShape.hasMultipleDifferentValues) + settings.textureShape = (TextureImporterShape)m_TextureShape.intValue; + + return settings; + } + /// + /// Override of AssetImporterEditor.showImportedObject + /// The property always returns false so that imported objects does not show up in the Inspector. + /// + /// false + public override bool showImportedObject + { + get { return false; } + } + + public bool textureTypeHasMultipleDifferentValues + { + get { return m_TextureType.hasMultipleDifferentValues; } + } + + public TextureImporterType textureType + { + get { return (TextureImporterType)m_TextureType.intValue; } + } + + public SpriteImportMode spriteImportMode + { + get { return (SpriteImportMode)m_SpriteMode.intValue; } + } + + public override bool HasModified() + { + if (base.HasModified()) + return true; + + return m_TexturePlatformSettingsHelper.HasModified(); + } + + internal class Styles + { + public readonly GUIContent textureTypeTitle = new GUIContent("Texture Type", "What will this texture be used for?"); + public readonly GUIContent[] textureTypeOptions = + { + new GUIContent("Default", "Texture is a normal image such as a diffuse texture or other."), + new GUIContent("Sprite (2D and UI)", "Texture is used for a sprite."), + }; + public readonly int[] textureTypeValues = + { + (int)TextureImporterType.Default, + (int)TextureImporterType.Sprite, + }; + + public readonly GUIContent textureShape = new GUIContent("Texture Shape", "What shape is this texture?"); + private readonly GUIContent textureShape2D = new GUIContent("2D, Texture is 2D."); + private readonly GUIContent textureShapeCube = new GUIContent("Cube", "Texture is a Cubemap."); + public readonly Dictionary textureShapeOptionsDictionnary = new Dictionary(); + public readonly Dictionary textureShapeValuesDictionnary = new Dictionary(); + + + public readonly GUIContent filterMode = new GUIContent("Filter Mode"); + public readonly GUIContent[] filterModeOptions = + { + new GUIContent("Point (no filter)"), + new GUIContent("Bilinear"), + new GUIContent("Trilinear") + }; + + public readonly GUIContent textureFormat = new GUIContent("Format"); + + public readonly GUIContent defaultPlatform = new GUIContent("Default"); + public readonly GUIContent mipmapFadeOutToggle = new GUIContent("Fadeout Mip Maps"); + public readonly GUIContent mipmapFadeOut = new GUIContent("Fade Range"); + public readonly GUIContent readWrite = new GUIContent("Read/Write Enabled", "Enable to be able to access the raw pixel data from code."); + + public readonly GUIContent alphaSource = new GUIContent("Alpha Source", "How is the alpha generated for the imported texture."); + public readonly GUIContent[] alphaSourceOptions = + { + new GUIContent("None", "No Alpha will be used."), + new GUIContent("Input Texture Alpha", "Use Alpha from the input texture if one is provided."), + new GUIContent("From Gray Scale", "Generate Alpha from image gray scale."), + }; + public readonly int[] alphaSourceValues = + { + (int)TextureImporterAlphaSource.None, + (int)TextureImporterAlphaSource.FromInput, + (int)TextureImporterAlphaSource.FromGrayScale, + }; + + public readonly GUIContent generateMipMaps = new GUIContent("Generate Mip Maps"); + public readonly GUIContent sRGBTexture = new GUIContent("sRGB (Color Texture)", "Texture content is stored in gamma space. Non-HDR color textures should enable this flag (except if used for IMGUI)."); + public readonly GUIContent borderMipMaps = new GUIContent("Border Mip Maps"); + public readonly GUIContent mipMapsPreserveCoverage = new GUIContent("Mip Maps Preserve Coverage", "The alpha channel of generated Mip Maps will preserve coverage during the alpha test."); + public readonly GUIContent alphaTestReferenceValue = new GUIContent("Alpha Cutoff Value", "The reference value used during the alpha test. Controls Mip Map coverage."); + public readonly GUIContent mipMapFilter = new GUIContent("Mip Map Filtering"); + public readonly GUIContent[] mipMapFilterOptions = + { + new GUIContent("Box"), + new GUIContent("Kaiser"), + }; + public readonly GUIContent npot = new GUIContent("Non Power of 2", "How non-power-of-two textures are scaled on import."); + + public readonly GUIContent compressionQuality = new GUIContent("Compressor Quality"); + public readonly GUIContent compressionQualitySlider = new GUIContent("Compressor Quality", "Use the slider to adjust compression quality from 0 (Fastest) to 100 (Best)"); + public readonly GUIContent[] mobileCompressionQualityOptions = + { + new GUIContent("Fast"), + new GUIContent("Normal"), + new GUIContent("Best") + }; + + public readonly GUIContent spriteMode = new GUIContent("Sprite Mode"); + public readonly GUIContent[] spriteModeOptions = + { + new GUIContent("Single"), + new GUIContent("Multiple"), + new GUIContent("Polygon"), + }; + public readonly GUIContent[] spriteMeshTypeOptions = + { + new GUIContent("Full Rect"), + new GUIContent("Tight"), + }; + + public readonly GUIContent spritePackingTag = new GUIContent("Packing Tag", "Tag for the Sprite Packing system."); + public readonly GUIContent spritePixelsPerUnit = new GUIContent("Pixels Per Unit", "How many pixels in the sprite correspond to one unit in the world."); + public readonly GUIContent spriteExtrude = new GUIContent("Extrude Edges", "How much empty area to leave around the sprite in the generated mesh."); + public readonly GUIContent spriteMeshType = new GUIContent("Mesh Type", "Type of sprite mesh to generate."); + public readonly GUIContent spriteAlignment = new GUIContent("Pivot", "Sprite pivot point in its local space. May be used for syncing animation frames of different sizes."); + public readonly GUIContent characterAlignment = new GUIContent("Pivot", "Character pivot point in its local space using normalized value i.e. 0 - 1"); + + public readonly GUIContent[] spriteAlignmentOptions = + { + new GUIContent("Center"), + new GUIContent("Top Left"), + new GUIContent("Top"), + new GUIContent("Top Right"), + new GUIContent("Left"), + new GUIContent("Right"), + new GUIContent("Bottom Left"), + new GUIContent("Bottom"), + new GUIContent("Bottom Right"), + new GUIContent("Custom"), + }; + + public readonly GUIContent warpNotSupportWarning = new GUIContent("Graphics device doesn't support Repeat wrap mode on NPOT textures. Falling back to Clamp."); + public readonly GUIContent anisoLevelLabel = new GUIContent("Aniso Level"); + public readonly GUIContent anisotropicDisableInfo = new GUIContent("Anisotropic filtering is disabled for all textures in Quality Settings."); + public readonly GUIContent anisotropicForceEnableInfo = new GUIContent("Anisotropic filtering is enabled for all textures in Quality Settings."); + public readonly GUIContent unappliedSettingsDialogTitle = new GUIContent("Unapplied import settings"); + public readonly GUIContent unappliedSettingsDialogContent = new GUIContent("Unapplied import settings for \'{0}\'.\nApply and continue to sprite editor or cancel."); + public readonly GUIContent applyButtonLabel = new GUIContent("Apply"); + public readonly GUIContent revertButtonLabel = new GUIContent("Revert"); + public readonly GUIContent spriteEditorButtonLabel = new GUIContent("Sprite Editor"); + public readonly GUIContent resliceFromLayerWarning = new GUIContent("This will reinitialize and recreate all Sprites based on the file’s layer data. Existing Sprite metadata from previously generated Sprites are copied over."); + public readonly GUIContent alphaIsTransparency = new GUIContent("Alpha Is Transparency", "If the provided alpha channel is transparency, enable this to pre-filter the color to avoid texture filtering artifacts. This is not supported for HDR textures."); + public readonly GUIContent etc1Compression = new GUIContent("Compress using ETC1 (split alpha channel)|Alpha for this texture will be preserved by splitting the alpha channel to another texture, and both resulting textures will be compressed using ETC1."); + public readonly GUIContent crunchedCompression = new GUIContent("Use Crunch Compression", "Texture is crunch-compressed to save space on disk when applicable."); + + public readonly GUIContent showAdvanced = new GUIContent("Advanced", "Show advanced settings."); + + public readonly GUIContent platformSettingsLabel = new GUIContent("Platform Setttings"); + + public readonly GUIContent[] platformSettingsSelection; + + public readonly GUIContent wrapModeLabel = new GUIContent("Wrap Mode"); + public readonly GUIContent wrapU = new GUIContent("U axis"); + public readonly GUIContent wrapV = new GUIContent("V axis"); + public readonly GUIContent wrapW = new GUIContent("W axis"); + + + public readonly GUIContent[] wrapModeContents = + { + new GUIContent("Repeat"), + new GUIContent("Clamp"), + new GUIContent("Mirror"), + new GUIContent("Mirror Once"), + new GUIContent("Per-axis") + }; + public readonly int[] wrapModeValues = + { + (int)TextureWrapMode.Repeat, + (int)TextureWrapMode.Clamp, + (int)TextureWrapMode.Mirror, + (int)TextureWrapMode.MirrorOnce, + -1 + }; + + public readonly GUIContent importHiddenLayer = new GUIContent(L10n.Tr("Import Hidden"), L10n.Tr("Import hidden layers")); + public readonly GUIContent mosaicLayers = new GUIContent(L10n.Tr("Mosaic"), L10n.Tr("Layers will be imported as individual Sprites")); + public readonly GUIContent characterMode = new GUIContent(L10n.Tr("Character Rig"), L10n.Tr("Enable to support 2D Animation character rigging")); + public readonly GUIContent generateGOHierarchy = new GUIContent(L10n.Tr("Use Layer Grouping"), L10n.Tr("GameObjects are grouped according to source file layer grouping")); + public readonly GUIContent resliceFromLayer = new GUIContent(L10n.Tr("Reslice"), L10n.Tr("Recreate Sprite rects from file")); + public readonly GUIContent paperDollMode = new GUIContent(L10n.Tr("Paper Doll Mode"), L10n.Tr("Special mode to generate a Prefab for Paper Doll use case")); + public readonly GUIContent experimental = new GUIContent(L10n.Tr("Experimental")); + public readonly GUIContent keepDuplicateSpriteName = new GUIContent(L10n.Tr("Keep Duplicate Name"), L10n.Tr("Keep Sprite name same as Layer Name even if there are duplicated Layer Name")); + + public Styles() + { + // This is far from ideal, but it's better than having tons of logic in the GUI code itself. + // The combination should not grow too much anyway since only Texture3D will be added later. + GUIContent[] s2D_Options = { textureShape2D }; + GUIContent[] sCube_Options = { textureShapeCube }; + GUIContent[] s2D_Cube_Options = { textureShape2D, textureShapeCube }; + textureShapeOptionsDictionnary.Add(TextureImporterShape.Texture2D, s2D_Options); + textureShapeOptionsDictionnary.Add(TextureImporterShape.TextureCube, sCube_Options); + textureShapeOptionsDictionnary.Add(TextureImporterShape.Texture2D | TextureImporterShape.TextureCube, s2D_Cube_Options); + + int[] s2D_Values = { (int)TextureImporterShape.Texture2D }; + int[] sCube_Values = { (int)TextureImporterShape.TextureCube }; + int[] s2D_Cube_Values = { (int)TextureImporterShape.Texture2D, (int)TextureImporterShape.TextureCube }; + textureShapeValuesDictionnary.Add(TextureImporterShape.Texture2D, s2D_Values); + textureShapeValuesDictionnary.Add(TextureImporterShape.TextureCube, sCube_Values); + textureShapeValuesDictionnary.Add(TextureImporterShape.Texture2D | TextureImporterShape.TextureCube, s2D_Cube_Values); + + platformSettingsSelection = new GUIContent[TexturePlatformSettingsModal.kValidBuildPlatform.Length]; + for (int i = 0; i < TexturePlatformSettingsModal.kValidBuildPlatform.Length; ++i) + { + platformSettingsSelection[i] = new GUIContent(TexturePlatformSettingsModal.kValidBuildPlatform[i].buildTargetName); + } + } + } + + internal static Styles s_Styles; + } +} diff --git a/Editor/PSDImporterEditor.cs.meta b/Editor/PSDImporterEditor.cs.meta index b9895fe..eb174d7 100644 --- a/Editor/PSDImporterEditor.cs.meta +++ b/Editor/PSDImporterEditor.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 18bf2b24e4cf52b4db1d73f71d4bd76b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 18bf2b24e4cf52b4db1d73f71d4bd76b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDLayer.cs b/Editor/PSDLayer.cs index 185a75c..57f6cc5 100644 --- a/Editor/PSDLayer.cs +++ b/Editor/PSDLayer.cs @@ -1,59 +1,59 @@ -using System; -using Unity.Collections; -using UnityEngine; - -namespace UnityEditor.U2D.PSD -{ - [Serializable] - class PSDLayer - { - [SerializeField] - string m_Name; - [SerializeField] - string m_SpriteName; - [SerializeField] - bool m_IsGroup; - [SerializeField] - int m_ParentIndex; - [SerializeField] - string m_SpriteID; - [SerializeField] - int m_LayerID; - [SerializeField] - Vector2Int m_MosaicPosition; - - [NonSerialized] - GameObject m_GameObject; - - public PSDLayer(NativeArray tex, int parent, bool group, string layerName, int width, int height, int id) - { - isGroup = group; - parentIndex = parent; - texture = tex; - name = layerName; - this.width = width; - this.height = height; - layerID = id; - } - - public int layerID { get { return m_LayerID; } private set { m_LayerID = value; } } - - public string name { get { return m_Name; } private set { m_Name = value; } } - public string spriteName { get { return m_SpriteName; } set { m_SpriteName = value; } } - public bool isGroup { get { return m_IsGroup; } private set { m_IsGroup = value; } } - public int parentIndex { get { return m_ParentIndex; } private set { m_ParentIndex = value; } } - public Vector2Int mosaicPosition { get { return m_MosaicPosition; } set { m_MosaicPosition = value; } } - public GUID spriteID { get { return new GUID(m_SpriteID); } set { m_SpriteID = value.ToString(); } } - public GameObject gameObject { get { return m_GameObject; } set { m_GameObject = value; } } - - public NativeArray texture { get; set; } - public int width { get; private set; } - public int height { get; private set; } - - public void Dispose() - { - if (texture.IsCreated) - texture.Dispose(); - } - } -} +using System; +using Unity.Collections; +using UnityEngine; + +namespace UnityEditor.U2D.PSD +{ + [Serializable] + class PSDLayer + { + [SerializeField] + string m_Name; + [SerializeField] + string m_SpriteName; + [SerializeField] + bool m_IsGroup; + [SerializeField] + int m_ParentIndex; + [SerializeField] + string m_SpriteID; + [SerializeField] + int m_LayerID; + [SerializeField] + Vector2Int m_MosaicPosition; + + [NonSerialized] + GameObject m_GameObject; + + public PSDLayer(NativeArray tex, int parent, bool group, string layerName, int width, int height, int id) + { + isGroup = group; + parentIndex = parent; + texture = tex; + name = layerName; + this.width = width; + this.height = height; + layerID = id; + } + + public int layerID { get { return m_LayerID; } private set { m_LayerID = value; } } + + public string name { get { return m_Name; } private set { m_Name = value; } } + public string spriteName { get { return m_SpriteName; } set { m_SpriteName = value; } } + public bool isGroup { get { return m_IsGroup; } private set { m_IsGroup = value; } } + public int parentIndex { get { return m_ParentIndex; } private set { m_ParentIndex = value; } } + public Vector2Int mosaicPosition { get { return m_MosaicPosition; } set { m_MosaicPosition = value; } } + public GUID spriteID { get { return new GUID(m_SpriteID); } set { m_SpriteID = value.ToString(); } } + public GameObject gameObject { get { return m_GameObject; } set { m_GameObject = value; } } + + public NativeArray texture { get; set; } + public int width { get; private set; } + public int height { get; private set; } + + public void Dispose() + { + if (texture.IsCreated) + texture.Dispose(); + } + } +} diff --git a/Editor/PSDLayer.cs.meta b/Editor/PSDLayer.cs.meta index b602270..4d8cf68 100644 --- a/Editor/PSDLayer.cs.meta +++ b/Editor/PSDLayer.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: a775ce65fe4b55c46a628fa416f319d3 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: a775ce65fe4b55c46a628fa416f319d3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin.meta b/Editor/PSDPlugin.meta index b78ae1c..ad5c91f 100644 --- a/Editor/PSDPlugin.meta +++ b/Editor/PSDPlugin.meta @@ -1,10 +1,10 @@ -fileFormatVersion: 2 -guid: c21e2663cf9e69a40b8ac0838a3f9ae1 -folderAsset: yes -timeCreated: 1502356798 -licenseType: Pro -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: c21e2663cf9e69a40b8ac0838a3f9ae1 +folderAsset: yes +timeCreated: 1502356798 +licenseType: Pro +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/AssemblyInfo.cs b/Editor/PSDPlugin/AssemblyInfo.cs index 8ebf792..320536a 100644 --- a/Editor/PSDPlugin/AssemblyInfo.cs +++ b/Editor/PSDPlugin/AssemblyInfo.cs @@ -1,3 +1,3 @@ -using System.Runtime.CompilerServices; - +using System.Runtime.CompilerServices; + [assembly: InternalsVisibleTo("Unity.2D.PsdImporter.Editor")] \ No newline at end of file diff --git a/Editor/PSDPlugin/AssemblyInfo.cs.meta b/Editor/PSDPlugin/AssemblyInfo.cs.meta index ce1ab1d..48fc37f 100644 --- a/Editor/PSDPlugin/AssemblyInfo.cs.meta +++ b/Editor/PSDPlugin/AssemblyInfo.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 86edfd93afbfbfd4a9dd8afefbb6ba14 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 86edfd93afbfbfd4a9dd8afefbb6ba14 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PDNWrapper.meta b/Editor/PSDPlugin/PDNWrapper.meta index 62a7895..9bac7a1 100644 --- a/Editor/PSDPlugin/PDNWrapper.meta +++ b/Editor/PSDPlugin/PDNWrapper.meta @@ -1,9 +1,9 @@ -fileFormatVersion: 2 -guid: 9fcfe7284d9f34b4eae286b83227271d -folderAsset: yes -timeCreated: 1495006553 -licenseType: Pro -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 9fcfe7284d9f34b4eae286b83227271d +folderAsset: yes +timeCreated: 1495006553 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PDNWrapper/BitmapLayer.cs b/Editor/PSDPlugin/PDNWrapper/BitmapLayer.cs index a6f2521..c824dc0 100644 --- a/Editor/PSDPlugin/PDNWrapper/BitmapLayer.cs +++ b/Editor/PSDPlugin/PDNWrapper/BitmapLayer.cs @@ -1,50 +1,50 @@ -using System.Collections; -using System.Collections.Generic; - -namespace PDNWrapper -{ - internal static class Layer - { - public static BitmapLayer CreateBackgroundLayer(int w, int h) - { - return new BitmapLayer(w, h); - } - } - - internal class BitmapLayer - { - int width, height; - - public Rectangle Bounds - { - get {return new Rectangle(0, 0, width, height); } - } - - public void Dispose() - { - Surface.Dispose(); - foreach (var layer in ChildLayer) - layer.Dispose(); - } - - public BitmapLayer(int w, int h) - { - Surface = new Surface(w, h); - width = w; - height = h; - ChildLayer = new List(); - IsGroup = false; - } - public int LayerID { get; set; } - - public bool IsGroup {get; set; } - public BitmapLayer ParentLayer {get; set; } - public List ChildLayer { get; set; } - public string Name { get; set; } - public byte Opacity { get; set; } - public bool Visible { get; set; } - public LayerBlendMode BlendMode { get; set; } - - public Surface Surface { get; set; } - } -} +using System.Collections; +using System.Collections.Generic; + +namespace PDNWrapper +{ + internal static class Layer + { + public static BitmapLayer CreateBackgroundLayer(int w, int h) + { + return new BitmapLayer(w, h); + } + } + + internal class BitmapLayer + { + int width, height; + + public Rectangle Bounds + { + get {return new Rectangle(0, 0, width, height); } + } + + public void Dispose() + { + Surface.Dispose(); + foreach (var layer in ChildLayer) + layer.Dispose(); + } + + public BitmapLayer(int w, int h) + { + Surface = new Surface(w, h); + width = w; + height = h; + ChildLayer = new List(); + IsGroup = false; + } + public int LayerID { get; set; } + + public bool IsGroup {get; set; } + public BitmapLayer ParentLayer {get; set; } + public List ChildLayer { get; set; } + public string Name { get; set; } + public byte Opacity { get; set; } + public bool Visible { get; set; } + public LayerBlendMode BlendMode { get; set; } + + public Surface Surface { get; set; } + } +} diff --git a/Editor/PSDPlugin/PDNWrapper/BitmapLayer.cs.meta b/Editor/PSDPlugin/PDNWrapper/BitmapLayer.cs.meta index 395afd5..c427cbf 100644 --- a/Editor/PSDPlugin/PDNWrapper/BitmapLayer.cs.meta +++ b/Editor/PSDPlugin/PDNWrapper/BitmapLayer.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 43a7a92da0ad89c40b5a39ed87329536 -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 43a7a92da0ad89c40b5a39ed87329536 +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PDNWrapper/Document.cs b/Editor/PSDPlugin/PDNWrapper/Document.cs index f0fd977..8cd1304 100644 --- a/Editor/PSDPlugin/PDNWrapper/Document.cs +++ b/Editor/PSDPlugin/PDNWrapper/Document.cs @@ -1,30 +1,30 @@ -using System.Collections; -using System.Collections.Generic; - -namespace PDNWrapper -{ - internal class Document - { - public int width, height; - - public Document(int w, int h) - { - width = w; - height = h; - Layers = new List(); - } - - public void Dispose() - { - foreach (var layer in Layers) - layer.Dispose(); - } - - public List Layers { get; set; } - - public MeasurementUnit DpuUnit { get; set; } - - public double DpuX { get; set; } - public double DpuY { get; set; } - } -} +using System.Collections; +using System.Collections.Generic; + +namespace PDNWrapper +{ + internal class Document + { + public int width, height; + + public Document(int w, int h) + { + width = w; + height = h; + Layers = new List(); + } + + public void Dispose() + { + foreach (var layer in Layers) + layer.Dispose(); + } + + public List Layers { get; set; } + + public MeasurementUnit DpuUnit { get; set; } + + public double DpuX { get; set; } + public double DpuY { get; set; } + } +} diff --git a/Editor/PSDPlugin/PDNWrapper/Document.cs.meta b/Editor/PSDPlugin/PDNWrapper/Document.cs.meta index c26664a..b727bea 100644 --- a/Editor/PSDPlugin/PDNWrapper/Document.cs.meta +++ b/Editor/PSDPlugin/PDNWrapper/Document.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 5d036cb10363b5f4b94b39c7afb3e2d0 -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 5d036cb10363b5f4b94b39c7afb3e2d0 +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PDNWrapper/Enums.cs b/Editor/PSDPlugin/PDNWrapper/Enums.cs index c7c18d9..100e09c 100644 --- a/Editor/PSDPlugin/PDNWrapper/Enums.cs +++ b/Editor/PSDPlugin/PDNWrapper/Enums.cs @@ -1,27 +1,27 @@ -namespace PDNWrapper -{ - internal enum MeasurementUnit - { - Pixel = 1, - Inch = 2, - Centimeter = 3 - } - - internal enum LayerBlendMode - { - Normal = 0, - Multiply = 1, - Additive = 2, - ColorBurn = 3, - ColorDodge = 4, - Reflect = 5, - Glow = 6, - Overlay = 7, - Difference = 8, - Negation = 9, - Lighten = 10, - Darken = 11, - Screen = 12, - Xor = 13 - } -} +namespace PDNWrapper +{ + internal enum MeasurementUnit + { + Pixel = 1, + Inch = 2, + Centimeter = 3 + } + + internal enum LayerBlendMode + { + Normal = 0, + Multiply = 1, + Additive = 2, + ColorBurn = 3, + ColorDodge = 4, + Reflect = 5, + Glow = 6, + Overlay = 7, + Difference = 8, + Negation = 9, + Lighten = 10, + Darken = 11, + Screen = 12, + Xor = 13 + } +} diff --git a/Editor/PSDPlugin/PDNWrapper/Enums.cs.meta b/Editor/PSDPlugin/PDNWrapper/Enums.cs.meta index b1cb66e..3a307e6 100644 --- a/Editor/PSDPlugin/PDNWrapper/Enums.cs.meta +++ b/Editor/PSDPlugin/PDNWrapper/Enums.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: f396654a3007906488e747d54ae80913 -timeCreated: 1495006554 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: f396654a3007906488e747d54ae80913 +timeCreated: 1495006554 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PDNWrapper/PDNDecodeJob.cs b/Editor/PSDPlugin/PDNWrapper/PDNDecodeJob.cs index c50d074..71819ae 100644 --- a/Editor/PSDPlugin/PDNWrapper/PDNDecodeJob.cs +++ b/Editor/PSDPlugin/PDNWrapper/PDNDecodeJob.cs @@ -1,623 +1,623 @@ -using System.Collections; -using System.Collections.Generic; -using Unity.Jobs; -using UnityEngine; -using Unity.Collections; -using System; -using Unity.Collections.LowLevel.Unsafe; - -namespace PaintDotNet.Data.PhotoshopFileType -{ - - #region PDNDecodeJob - - internal struct PDNDecoderData - { - // Inputs. - public PDNWrapper.Rectangle Rect; - public PDNWrapper.Rectangle LayerRect; - public PDNWrapper.Rectangle ClippedRect; - public int SurfaceWidth; - public int SurfaceHeight; - public int SurfaceByteDepth; - public DecodeType DecoderType; - - [NativeDisableParallelForRestriction] - [ReadOnly] - public NativeArray ColorChannel0; - - [NativeDisableParallelForRestriction] - [ReadOnly] - public NativeArray ColorChannel1; - - [NativeDisableParallelForRestriction] - [ReadOnly] - public NativeArray ColorChannel2; - - [NativeDisableParallelForRestriction] - [ReadOnly] - public NativeArray ColorChannel3; - - [NativeDisableParallelForRestriction] - [ReadOnly] - [DeallocateOnJobCompletion] - public NativeArray ColorModeData; - - // Outputs - [NativeDisableParallelForRestriction] - public NativeArray DecodedImage; - - } - - internal struct PDNDecoderJob : IJobParallelFor - { - - public PDNDecoderData Data; - - public void Execute(int index) - { - - int idx = Data.Rect.Top + index; - { - // Calculate index into ImageData source from row and column. - int idxSrcPixel = (idx - Data.LayerRect.Top) * Data.LayerRect.Width + (Data.Rect.Left - Data.LayerRect.Left); - int idxSrcBytes = idxSrcPixel * Data.SurfaceByteDepth; - - // Calculate pointers to destination Surface. - var idxDstStart = idx * Data.SurfaceWidth + Data.ClippedRect.Left; - var idxDstStops = idx * Data.SurfaceWidth + Data.ClippedRect.Right; - - // For 16-bit images, take the higher-order byte from the image data, which is now in little-endian order. - if (Data.SurfaceByteDepth == 2) - { - idxSrcBytes++; - } - - switch (Data.DecoderType) - { - case DecodeType.RGB32: - { - SetPDNRowRgb32(idxDstStart, idxDstStops, idxSrcBytes); - } - break; - case DecodeType.Grayscale32: - { - SetPDNRowGrayscale32(idxDstStart, idxDstStops, idxSrcBytes); - } - break; - case DecodeType.RGB: - { - SetPDNRowRgb(idxDstStart, idxDstStops, idxSrcBytes); - } - break; - case DecodeType.CMYK: - { - SetPDNRowCmyk(idxDstStart, idxDstStops, idxSrcBytes); - } - break; - case DecodeType.Bitmap: - { - SetPDNRowBitmap(idxDstStart, idxDstStops, idxSrcBytes); - } - break; - case DecodeType.Grayscale: - { - SetPDNRowGrayscale(idxDstStart, idxDstStops, idxSrcBytes); - } - break; - case DecodeType.Indexed: - { - SetPDNRowIndexed(idxDstStart, idxDstStops, idxSrcBytes); - } - break; - case DecodeType.Lab: - { - SetPDNRowLab(idxDstStart, idxDstStops, idxSrcBytes); - } - break; - } - - } - - } - - // Case 0: - private void SetPDNRowRgb32(int dstStart, int dstStops, int idxSrc) - { - NativeArray cR = Data.ColorChannel0.Reinterpret(1); - NativeArray cG = Data.ColorChannel1.Reinterpret(1); - NativeArray cB = Data.ColorChannel2.Reinterpret(1); - var c = Data.DecodedImage[dstStart]; - while (dstStart < dstStops) - { - c.r = ImageDecoderPdn.RGBByteFromHDRFloat(cR[idxSrc / 4]); - c.g = ImageDecoderPdn.RGBByteFromHDRFloat(cG[idxSrc / 4]); - c.b = ImageDecoderPdn.RGBByteFromHDRFloat(cB[idxSrc / 4]); - Data.DecodedImage[dstStart] = c; - - dstStart++; - idxSrc += 4; - } - } - - // Case 1: - private void SetPDNRowGrayscale32(int dstStart, int dstStops, int idxSrc) - { - NativeArray channel = Data.ColorChannel0.Reinterpret(1); - var c = Data.DecodedImage[dstStart]; - while (dstStart < dstStops) - { - byte rgbValue = ImageDecoderPdn.RGBByteFromHDRFloat(channel[idxSrc / 4]); - c.r = rgbValue; - c.g = rgbValue; - c.b = rgbValue; - Data.DecodedImage[dstStart] = c; - - dstStart++; - idxSrc += 4; - } - } - - // Case 2: - private void SetPDNRowRgb(int dstStart, int dstStops, int idxSrc) - { - var c = Data.DecodedImage[dstStart]; - while (dstStart < dstStops) - { - c.r = Data.ColorChannel0[idxSrc]; - c.g = Data.ColorChannel1[idxSrc]; - c.b = Data.ColorChannel2[idxSrc]; - Data.DecodedImage[dstStart] = c; - - dstStart++; - idxSrc += Data.SurfaceByteDepth; - } - } - - // Case 3: - /////////////////////////////////////////////////////////////////////////////// - // - // The color-conversion formulas come from the Colour Space Conversions FAQ: - // http://www.poynton.com/PDFs/coloureq.pdf - // - // RGB --> CMYK CMYK --> RGB - // --------------------------------------- -------------------------------------------- - // Black = minimum(1-Red,1-Green,1-Blue) Red = 1-minimum(1,Cyan*(1-Black)+Black) - // Cyan = (1-Red-Black)/(1-Black) Green = 1-minimum(1,Magenta*(1-Black)+Black) - // Magenta = (1-Green-Black)/(1-Black) Blue = 1-minimum(1,Yellow*(1-Black)+Black) - // Yellow = (1-Blue-Black)/(1-Black) - // - /////////////////////////////////////////////////////////////////////////////// - private void SetPDNRowCmyk(int dstStart, int dstStops, int idxSrc) - { - var c = Data.DecodedImage[dstStart]; - while (dstStart < dstStops) - { - // CMYK values are stored as complements, presumably to allow for some - // measure of compatibility with RGB-only applications. - var C = 255 - Data.ColorChannel0[idxSrc]; - var M = 255 - Data.ColorChannel1[idxSrc]; - var Y = 255 - Data.ColorChannel2[idxSrc]; - var K = 255 - Data.ColorChannel3[idxSrc]; - - int R = 255 - Math.Min(255, C * (255 - K) / 255 + K); - int G = 255 - Math.Min(255, M * (255 - K) / 255 + K); - int B = 255 - Math.Min(255, Y * (255 - K) / 255 + K); - - c.r = (byte)R; - c.g = (byte)G; - c.b = (byte)B; - Data.DecodedImage[dstStart] = c; - - dstStart++; - idxSrc += Data.SurfaceByteDepth; - } - } - - // Case 4: - private void SetPDNRowBitmap(int dstStart, int dstStops, int idxSrc) - { - var c = Data.DecodedImage[dstStart]; - while (dstStart < dstStops) - { - byte mask = (byte)(0x80 >> (idxSrc % 8)); - byte bwValue = (byte)(Data.ColorChannel0[idxSrc / 8] & mask); - bwValue = (bwValue == 0) ? (byte)255 : (byte)0; - - c.r = bwValue; - c.g = bwValue; - c.b = bwValue; - Data.DecodedImage[dstStart] = c; - - dstStart++; - idxSrc += Data.SurfaceByteDepth; - } - } - - // Case 5: - private void SetPDNRowGrayscale(int dstStart, int dstStops, int idxSrc) - { - var c = Data.DecodedImage[dstStart]; - while (dstStart < dstStops) - { - - c.r = Data.ColorChannel0[idxSrc]; - c.g = Data.ColorChannel0[idxSrc]; - c.b = Data.ColorChannel0[idxSrc]; - Data.DecodedImage[dstStart] = c; - - dstStart++; - idxSrc += Data.SurfaceByteDepth; - } - } - - // Case 6: - private void SetPDNRowIndexed(int dstStart, int dstStops, int idxSrc) - { - var c = Data.DecodedImage[dstStart]; - int index = (int)Data.ColorChannel0[idxSrc]; - while (dstStart < dstStops) - { - c.r = Data.ColorModeData[index]; - c.g = Data.ColorModeData[index + 256]; - c.b = Data.ColorModeData[index + 2 * 256]; - Data.DecodedImage[dstStart] = c; - - dstStart++; - idxSrc += Data.SurfaceByteDepth; - } - } - - // Case 7: - private void SetPDNRowLab(int dstStart, int dstStops, int idxSrc) - { - var c = Data.DecodedImage[dstStart]; - while (dstStart < dstStops) - { - double exL, exA, exB; - exL = (double)Data.ColorChannel0[idxSrc]; - exA = (double)Data.ColorChannel1[idxSrc]; - exB = (double)Data.ColorChannel2[idxSrc]; - - int L = (int)(exL / 2.55); - int a = (int)(exA - 127.5); - int b = (int)(exB - 127.5); - - // First, convert from Lab to XYZ. - // Standards used Observer = 2, Illuminant = D65 - - const double ref_X = 95.047; - const double ref_Y = 100.000; - const double ref_Z = 108.883; - - double var_Y = ((double)L + 16.0) / 116.0; - double var_X = (double)a / 500.0 + var_Y; - double var_Z = var_Y - (double)b / 200.0; - - double var_X3 = var_X * var_X * var_X; - double var_Y3 = var_Y * var_Y * var_Y; - double var_Z3 = var_Z * var_Z * var_Z; - - if (var_Y3 > 0.008856) - var_Y = var_Y3; - else - var_Y = (var_Y - 16 / 116) / 7.787; - - if (var_X3 > 0.008856) - var_X = var_X3; - else - var_X = (var_X - 16 / 116) / 7.787; - - if (var_Z3 > 0.008856) - var_Z = var_Z3; - else - var_Z = (var_Z - 16 / 116) / 7.787; - - double X = ref_X * var_X; - double Y = ref_Y * var_Y; - double Z = ref_Z * var_Z; - - // Then, convert from XYZ to RGB. - // Standards used Observer = 2, Illuminant = D65 - // ref_X = 95.047, ref_Y = 100.000, ref_Z = 108.883 - - double var_R = X * 0.032406 + Y * (-0.015372) + Z * (-0.004986); - double var_G = X * (-0.009689) + Y * 0.018758 + Z * 0.000415; - double var_B = X * 0.000557 + Y * (-0.002040) + Z * 0.010570; - - if (var_R > 0.0031308) - var_R = 1.055 * (Math.Pow(var_R, 1 / 2.4)) - 0.055; - else - var_R = 12.92 * var_R; - - if (var_G > 0.0031308) - var_G = 1.055 * (Math.Pow(var_G, 1 / 2.4)) - 0.055; - else - var_G = 12.92 * var_G; - - if (var_B > 0.0031308) - var_B = 1.055 * (Math.Pow(var_B, 1 / 2.4)) - 0.055; - else - var_B = 12.92 * var_B; - - int nRed = (int)(var_R * 256.0); - int nGreen = (int)(var_G * 256.0); - int nBlue = (int)(var_B * 256.0); - - if (nRed < 0) - nRed = 0; - else if (nRed > 255) - nRed = 255; - if (nGreen < 0) - nGreen = 0; - else if (nGreen > 255) - nGreen = 255; - if (nBlue < 0) - nBlue = 0; - else if (nBlue > 255) - nBlue = 255; - - c.r = (byte)nRed; - c.g = (byte)nGreen; - c.b = (byte)nBlue; - Data.DecodedImage[dstStart] = c; - - dstStart++; - idxSrc += Data.SurfaceByteDepth; - } - } - } - - #endregion - - #region AlphaDecodeJob - - internal struct PDNAlphaMaskData - { - // Inputs. - public PDNWrapper.Rectangle Rect; - public PDNWrapper.Rectangle LayerRect; - public PDNWrapper.Rectangle ClippedRect; - public int SurfaceWidth; - public int SurfaceHeight; - public int SurfaceByteDepth; - - public int HasAlphaChannel; - public int HasUserAlphaMask; - public int UserMaskInvertOnBlend; - public PDNWrapper.Rectangle UserMaskRect; - public PDNWrapper.Rectangle UserMaskContextRect; - public int HasLayerAlphaMask; - public int LayerMaskInvertOnBlend; - public PDNWrapper.Rectangle LayerMaskRect; - public PDNWrapper.Rectangle LayerMaskContextRect; - - [NativeDisableParallelForRestriction] - [ReadOnly] - [DeallocateOnJobCompletion] - public NativeArray AlphaChannel0; - - [NativeDisableParallelForRestriction] - [ReadOnly] - public NativeArray UserMask; - - [DeallocateOnJobCompletion] - [NativeDisableParallelForRestriction] - public NativeArray UserAlphaMask; - - [DeallocateOnJobCompletion] - [NativeDisableParallelForRestriction] - public NativeArray UserAlphaMaskEmpty; - - [NativeDisableParallelForRestriction] - [ReadOnly] - public NativeArray LayerMask; - - [DeallocateOnJobCompletion] - [NativeDisableParallelForRestriction] - public NativeArray LayerAlphaMask; - - [DeallocateOnJobCompletion] - [NativeDisableParallelForRestriction] - public NativeArray LayerAlphaMaskEmpty; - - // Outputs - [NativeDisableParallelForRestriction] - public NativeArray DecodedImage; - - // Colors. - public byte UserMaskBackgroundColor; - public byte LayerMaskBackgroundColor; - } - - internal struct PDNAlphaMaskJob : IJob - { - - public PDNAlphaMaskData Data; - - public void Execute() - { - - for (int idx = Data.Rect.Top; idx < Data.Rect.Bottom; idx++) - { - // Calculate index into ImageData source from row and column. - int idxSrcPixel = (idx - Data.LayerRect.Top) * Data.LayerRect.Width + (Data.Rect.Left - Data.LayerRect.Left); - int idxSrcBytes = idxSrcPixel * Data.SurfaceByteDepth; - - // Calculate pointers to destination Surface. - var idxDstStart = idx * Data.SurfaceWidth + Data.ClippedRect.Left; - var idxDstStops = idx * Data.SurfaceWidth + Data.ClippedRect.Right; - - // For 16-bit images, take the higher-order byte from the image data, which is now in little-endian order. - if (Data.SurfaceByteDepth == 2) - { - idxSrcBytes++; - } - - SetPDNAlphaRow(idxDstStart, idxDstStops, idxSrcBytes); - if (0 != Data.HasLayerAlphaMask) - { - GetMaskAlphaRow(idx, Data.LayerAlphaMask, Data.LayerAlphaMaskEmpty, Data.LayerMask, Data.LayerMaskInvertOnBlend, Data.LayerMaskBackgroundColor, Data.LayerMaskContextRect, Data.LayerMaskRect); - } - if (0 != Data.HasUserAlphaMask) - { - GetMaskAlphaRow(idx, Data.UserAlphaMask, Data.UserAlphaMaskEmpty, Data.UserMask, Data.UserMaskInvertOnBlend, Data.UserMaskBackgroundColor, Data.UserMaskContextRect, Data.UserMaskRect); - } - ApplyPDNMask(idxDstStart, idxDstStops); - - } - } - - private void SetPDNAlphaRow(int dstStart, int dstStops, int idxSrc) - { - // Set alpha to fully-opaque if there is no alpha channel - if (0 == Data.HasAlphaChannel) - { - while (dstStart < dstStops) - { - var c = Data.DecodedImage[dstStart]; - c.a = 255; - Data.DecodedImage[dstStart] = c; - dstStart++; - } - } - // Set the alpha channel data - else - { - NativeArray srcAlphaChannel = Data.AlphaChannel0.Reinterpret(1); - { - while (dstStart < dstStops) - { - var c = Data.DecodedImage[dstStart]; - c.a = (Data.SurfaceByteDepth < 4) ? Data.AlphaChannel0[idxSrc] : ImageDecoderPdn.RGBByteFromHDRFloat(srcAlphaChannel[idxSrc / 4]); - - Data.DecodedImage[dstStart] = c; - dstStart++; - idxSrc += Data.SurfaceByteDepth; - } - } - } - } - - private void ApplyPDNMask(int dstStart, int dstStops) - { - // Do nothing if there are no masks - if (0 == Data.HasLayerAlphaMask && 0 == Data.HasUserAlphaMask) - { - return; - } - - // Apply one mask - else if (0 == Data.HasLayerAlphaMask || 0 == Data.HasUserAlphaMask) - { - var maskAlpha = (0 == Data.HasLayerAlphaMask) ? Data.UserAlphaMask : Data.LayerAlphaMask; - var maskStart = 0; - { - var c = Data.DecodedImage[dstStart]; - while (dstStart < dstStops) - { - c.a = (byte)(Data.DecodedImage[dstStart].a * maskAlpha[maskStart] / 255); - Data.DecodedImage[dstStart] = c; - dstStart++; - maskStart++; - } - } - } - // Apply both masks in one pass, to minimize rounding error - else - { - var maskStart = 0; - var c = Data.DecodedImage[dstStart]; - { - while (dstStart < dstStops) - { - var alphaFactor = (Data.LayerAlphaMask[maskStart]) * (Data.UserAlphaMask[maskStart]); - c.a = (byte)(Data.DecodedImage[dstStart].a * alphaFactor / 65025); - Data.DecodedImage[dstStart] = c; - - dstStart++; - maskStart++; - } - } - } - } - - private void DecodeMaskAlphaRow32(NativeArray Alpha, int dstStart, int dstStops, NativeArray Mask, int maskStart) - { - NativeArray floatArray = Mask.Reinterpret(1); - - while (dstStart < dstStops) - { - Alpha[dstStart] = ImageDecoderPdn.RGBByteFromHDRFloat(floatArray[maskStart / 4]); - - dstStart++; - maskStart += 4; - } - } - - private void DecodeMaskAlphaRow(NativeArray Alpha, int dstStart, int dstStops, NativeArray Mask, int maskStart, int byteDepth) - { - while (dstStart < dstStops) - { - Alpha[dstStart] = Mask[maskStart]; - - dstStart++; - maskStart += byteDepth; - } - } - - private unsafe void GetMaskAlphaRow(int idxSrc, NativeArray alphaBuffer, NativeArray alphaBufferEmpty, NativeArray maskChannel, int MaskInvertOnBlend, byte MaskBackgroundColor, PDNWrapper.Rectangle MaskContextRect, PDNWrapper.Rectangle MaskRect) - { - ////////////////////////////////////// - // Transfer mask into the alpha array - // Background color for areas not covered by the mask - byte backgroundColor = (0 != MaskInvertOnBlend) ? (byte)(255 - MaskBackgroundColor) : MaskBackgroundColor; - { - var alphaBufferPtr = NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(alphaBuffer); - UnsafeUtility.MemSet(alphaBufferPtr, backgroundColor, alphaBuffer.Length); - } - // Only process if not Empty. - if (alphaBufferEmpty[idxSrc] == 0) - { - // Get pointers to starting positions - int alphaColumn = MaskContextRect.X; - // It's possible that the layer's rect is larger than the clip and it's offset. - // Since we only copy out the alpha based on the MaskContext size - // The copy will start from where the MaskContextRect is - if(Data.LayerRect.X > 0) - alphaColumn = MaskContextRect.X - Data.LayerRect.X; - var pAlpha = alphaColumn; - var pAlphaEnd = pAlpha + MaskContextRect.Width; - - int maskRow = idxSrc - MaskRect.Y; - int maskColumn = MaskContextRect.X - MaskRect.X; - int idxMaskPixel = (maskRow * MaskRect.Width) + maskColumn; - var pMask = idxMaskPixel * Data.SurfaceByteDepth; - - // Take the high-order byte if values are 16-bit (little-endian) - if (Data.SurfaceByteDepth == 2) - { - pMask++; - } - - // Decode mask into the alpha array. - if (Data.SurfaceByteDepth == 4) - { - DecodeMaskAlphaRow32(alphaBuffer, pAlpha, pAlphaEnd, maskChannel, pMask); - } - else - { - DecodeMaskAlphaRow(alphaBuffer, pAlpha, pAlphaEnd, maskChannel, pMask, Data.SurfaceByteDepth); - } - - // Obsolete since Photoshop CS6, but retained for compatibility with older versions. Note that the background has already been inverted. - if (0 != MaskInvertOnBlend) - { - PhotoshopFile.Util.Invert(alphaBuffer, pAlpha, pAlphaEnd); - } - } - } - } - - #endregion +using System.Collections; +using System.Collections.Generic; +using Unity.Jobs; +using UnityEngine; +using Unity.Collections; +using System; +using Unity.Collections.LowLevel.Unsafe; + +namespace PaintDotNet.Data.PhotoshopFileType +{ + + #region PDNDecodeJob + + internal struct PDNDecoderData + { + // Inputs. + public PDNWrapper.Rectangle Rect; + public PDNWrapper.Rectangle LayerRect; + public PDNWrapper.Rectangle ClippedRect; + public int SurfaceWidth; + public int SurfaceHeight; + public int SurfaceByteDepth; + public DecodeType DecoderType; + + [NativeDisableParallelForRestriction] + [ReadOnly] + public NativeArray ColorChannel0; + + [NativeDisableParallelForRestriction] + [ReadOnly] + public NativeArray ColorChannel1; + + [NativeDisableParallelForRestriction] + [ReadOnly] + public NativeArray ColorChannel2; + + [NativeDisableParallelForRestriction] + [ReadOnly] + public NativeArray ColorChannel3; + + [NativeDisableParallelForRestriction] + [ReadOnly] + [DeallocateOnJobCompletion] + public NativeArray ColorModeData; + + // Outputs + [NativeDisableParallelForRestriction] + public NativeArray DecodedImage; + + } + + internal struct PDNDecoderJob : IJobParallelFor + { + + public PDNDecoderData Data; + + public void Execute(int index) + { + + int idx = Data.Rect.Top + index; + { + // Calculate index into ImageData source from row and column. + int idxSrcPixel = (idx - Data.LayerRect.Top) * Data.LayerRect.Width + (Data.Rect.Left - Data.LayerRect.Left); + int idxSrcBytes = idxSrcPixel * Data.SurfaceByteDepth; + + // Calculate pointers to destination Surface. + var idxDstStart = idx * Data.SurfaceWidth + Data.ClippedRect.Left; + var idxDstStops = idx * Data.SurfaceWidth + Data.ClippedRect.Right; + + // For 16-bit images, take the higher-order byte from the image data, which is now in little-endian order. + if (Data.SurfaceByteDepth == 2) + { + idxSrcBytes++; + } + + switch (Data.DecoderType) + { + case DecodeType.RGB32: + { + SetPDNRowRgb32(idxDstStart, idxDstStops, idxSrcBytes); + } + break; + case DecodeType.Grayscale32: + { + SetPDNRowGrayscale32(idxDstStart, idxDstStops, idxSrcBytes); + } + break; + case DecodeType.RGB: + { + SetPDNRowRgb(idxDstStart, idxDstStops, idxSrcBytes); + } + break; + case DecodeType.CMYK: + { + SetPDNRowCmyk(idxDstStart, idxDstStops, idxSrcBytes); + } + break; + case DecodeType.Bitmap: + { + SetPDNRowBitmap(idxDstStart, idxDstStops, idxSrcBytes); + } + break; + case DecodeType.Grayscale: + { + SetPDNRowGrayscale(idxDstStart, idxDstStops, idxSrcBytes); + } + break; + case DecodeType.Indexed: + { + SetPDNRowIndexed(idxDstStart, idxDstStops, idxSrcBytes); + } + break; + case DecodeType.Lab: + { + SetPDNRowLab(idxDstStart, idxDstStops, idxSrcBytes); + } + break; + } + + } + + } + + // Case 0: + private void SetPDNRowRgb32(int dstStart, int dstStops, int idxSrc) + { + NativeArray cR = Data.ColorChannel0.Reinterpret(1); + NativeArray cG = Data.ColorChannel1.Reinterpret(1); + NativeArray cB = Data.ColorChannel2.Reinterpret(1); + var c = Data.DecodedImage[dstStart]; + while (dstStart < dstStops) + { + c.r = ImageDecoderPdn.RGBByteFromHDRFloat(cR[idxSrc / 4]); + c.g = ImageDecoderPdn.RGBByteFromHDRFloat(cG[idxSrc / 4]); + c.b = ImageDecoderPdn.RGBByteFromHDRFloat(cB[idxSrc / 4]); + Data.DecodedImage[dstStart] = c; + + dstStart++; + idxSrc += 4; + } + } + + // Case 1: + private void SetPDNRowGrayscale32(int dstStart, int dstStops, int idxSrc) + { + NativeArray channel = Data.ColorChannel0.Reinterpret(1); + var c = Data.DecodedImage[dstStart]; + while (dstStart < dstStops) + { + byte rgbValue = ImageDecoderPdn.RGBByteFromHDRFloat(channel[idxSrc / 4]); + c.r = rgbValue; + c.g = rgbValue; + c.b = rgbValue; + Data.DecodedImage[dstStart] = c; + + dstStart++; + idxSrc += 4; + } + } + + // Case 2: + private void SetPDNRowRgb(int dstStart, int dstStops, int idxSrc) + { + var c = Data.DecodedImage[dstStart]; + while (dstStart < dstStops) + { + c.r = Data.ColorChannel0[idxSrc]; + c.g = Data.ColorChannel1[idxSrc]; + c.b = Data.ColorChannel2[idxSrc]; + Data.DecodedImage[dstStart] = c; + + dstStart++; + idxSrc += Data.SurfaceByteDepth; + } + } + + // Case 3: + /////////////////////////////////////////////////////////////////////////////// + // + // The color-conversion formulas come from the Colour Space Conversions FAQ: + // http://www.poynton.com/PDFs/coloureq.pdf + // + // RGB --> CMYK CMYK --> RGB + // --------------------------------------- -------------------------------------------- + // Black = minimum(1-Red,1-Green,1-Blue) Red = 1-minimum(1,Cyan*(1-Black)+Black) + // Cyan = (1-Red-Black)/(1-Black) Green = 1-minimum(1,Magenta*(1-Black)+Black) + // Magenta = (1-Green-Black)/(1-Black) Blue = 1-minimum(1,Yellow*(1-Black)+Black) + // Yellow = (1-Blue-Black)/(1-Black) + // + /////////////////////////////////////////////////////////////////////////////// + private void SetPDNRowCmyk(int dstStart, int dstStops, int idxSrc) + { + var c = Data.DecodedImage[dstStart]; + while (dstStart < dstStops) + { + // CMYK values are stored as complements, presumably to allow for some + // measure of compatibility with RGB-only applications. + var C = 255 - Data.ColorChannel0[idxSrc]; + var M = 255 - Data.ColorChannel1[idxSrc]; + var Y = 255 - Data.ColorChannel2[idxSrc]; + var K = 255 - Data.ColorChannel3[idxSrc]; + + int R = 255 - Math.Min(255, C * (255 - K) / 255 + K); + int G = 255 - Math.Min(255, M * (255 - K) / 255 + K); + int B = 255 - Math.Min(255, Y * (255 - K) / 255 + K); + + c.r = (byte)R; + c.g = (byte)G; + c.b = (byte)B; + Data.DecodedImage[dstStart] = c; + + dstStart++; + idxSrc += Data.SurfaceByteDepth; + } + } + + // Case 4: + private void SetPDNRowBitmap(int dstStart, int dstStops, int idxSrc) + { + var c = Data.DecodedImage[dstStart]; + while (dstStart < dstStops) + { + byte mask = (byte)(0x80 >> (idxSrc % 8)); + byte bwValue = (byte)(Data.ColorChannel0[idxSrc / 8] & mask); + bwValue = (bwValue == 0) ? (byte)255 : (byte)0; + + c.r = bwValue; + c.g = bwValue; + c.b = bwValue; + Data.DecodedImage[dstStart] = c; + + dstStart++; + idxSrc += Data.SurfaceByteDepth; + } + } + + // Case 5: + private void SetPDNRowGrayscale(int dstStart, int dstStops, int idxSrc) + { + var c = Data.DecodedImage[dstStart]; + while (dstStart < dstStops) + { + + c.r = Data.ColorChannel0[idxSrc]; + c.g = Data.ColorChannel0[idxSrc]; + c.b = Data.ColorChannel0[idxSrc]; + Data.DecodedImage[dstStart] = c; + + dstStart++; + idxSrc += Data.SurfaceByteDepth; + } + } + + // Case 6: + private void SetPDNRowIndexed(int dstStart, int dstStops, int idxSrc) + { + var c = Data.DecodedImage[dstStart]; + int index = (int)Data.ColorChannel0[idxSrc]; + while (dstStart < dstStops) + { + c.r = Data.ColorModeData[index]; + c.g = Data.ColorModeData[index + 256]; + c.b = Data.ColorModeData[index + 2 * 256]; + Data.DecodedImage[dstStart] = c; + + dstStart++; + idxSrc += Data.SurfaceByteDepth; + } + } + + // Case 7: + private void SetPDNRowLab(int dstStart, int dstStops, int idxSrc) + { + var c = Data.DecodedImage[dstStart]; + while (dstStart < dstStops) + { + double exL, exA, exB; + exL = (double)Data.ColorChannel0[idxSrc]; + exA = (double)Data.ColorChannel1[idxSrc]; + exB = (double)Data.ColorChannel2[idxSrc]; + + int L = (int)(exL / 2.55); + int a = (int)(exA - 127.5); + int b = (int)(exB - 127.5); + + // First, convert from Lab to XYZ. + // Standards used Observer = 2, Illuminant = D65 + + const double ref_X = 95.047; + const double ref_Y = 100.000; + const double ref_Z = 108.883; + + double var_Y = ((double)L + 16.0) / 116.0; + double var_X = (double)a / 500.0 + var_Y; + double var_Z = var_Y - (double)b / 200.0; + + double var_X3 = var_X * var_X * var_X; + double var_Y3 = var_Y * var_Y * var_Y; + double var_Z3 = var_Z * var_Z * var_Z; + + if (var_Y3 > 0.008856) + var_Y = var_Y3; + else + var_Y = (var_Y - 16 / 116) / 7.787; + + if (var_X3 > 0.008856) + var_X = var_X3; + else + var_X = (var_X - 16 / 116) / 7.787; + + if (var_Z3 > 0.008856) + var_Z = var_Z3; + else + var_Z = (var_Z - 16 / 116) / 7.787; + + double X = ref_X * var_X; + double Y = ref_Y * var_Y; + double Z = ref_Z * var_Z; + + // Then, convert from XYZ to RGB. + // Standards used Observer = 2, Illuminant = D65 + // ref_X = 95.047, ref_Y = 100.000, ref_Z = 108.883 + + double var_R = X * 0.032406 + Y * (-0.015372) + Z * (-0.004986); + double var_G = X * (-0.009689) + Y * 0.018758 + Z * 0.000415; + double var_B = X * 0.000557 + Y * (-0.002040) + Z * 0.010570; + + if (var_R > 0.0031308) + var_R = 1.055 * (Math.Pow(var_R, 1 / 2.4)) - 0.055; + else + var_R = 12.92 * var_R; + + if (var_G > 0.0031308) + var_G = 1.055 * (Math.Pow(var_G, 1 / 2.4)) - 0.055; + else + var_G = 12.92 * var_G; + + if (var_B > 0.0031308) + var_B = 1.055 * (Math.Pow(var_B, 1 / 2.4)) - 0.055; + else + var_B = 12.92 * var_B; + + int nRed = (int)(var_R * 256.0); + int nGreen = (int)(var_G * 256.0); + int nBlue = (int)(var_B * 256.0); + + if (nRed < 0) + nRed = 0; + else if (nRed > 255) + nRed = 255; + if (nGreen < 0) + nGreen = 0; + else if (nGreen > 255) + nGreen = 255; + if (nBlue < 0) + nBlue = 0; + else if (nBlue > 255) + nBlue = 255; + + c.r = (byte)nRed; + c.g = (byte)nGreen; + c.b = (byte)nBlue; + Data.DecodedImage[dstStart] = c; + + dstStart++; + idxSrc += Data.SurfaceByteDepth; + } + } + } + + #endregion + + #region AlphaDecodeJob + + internal struct PDNAlphaMaskData + { + // Inputs. + public PDNWrapper.Rectangle Rect; + public PDNWrapper.Rectangle LayerRect; + public PDNWrapper.Rectangle ClippedRect; + public int SurfaceWidth; + public int SurfaceHeight; + public int SurfaceByteDepth; + + public int HasAlphaChannel; + public int HasUserAlphaMask; + public int UserMaskInvertOnBlend; + public PDNWrapper.Rectangle UserMaskRect; + public PDNWrapper.Rectangle UserMaskContextRect; + public int HasLayerAlphaMask; + public int LayerMaskInvertOnBlend; + public PDNWrapper.Rectangle LayerMaskRect; + public PDNWrapper.Rectangle LayerMaskContextRect; + + [NativeDisableParallelForRestriction] + [ReadOnly] + [DeallocateOnJobCompletion] + public NativeArray AlphaChannel0; + + [NativeDisableParallelForRestriction] + [ReadOnly] + public NativeArray UserMask; + + [DeallocateOnJobCompletion] + [NativeDisableParallelForRestriction] + public NativeArray UserAlphaMask; + + [DeallocateOnJobCompletion] + [NativeDisableParallelForRestriction] + public NativeArray UserAlphaMaskEmpty; + + [NativeDisableParallelForRestriction] + [ReadOnly] + public NativeArray LayerMask; + + [DeallocateOnJobCompletion] + [NativeDisableParallelForRestriction] + public NativeArray LayerAlphaMask; + + [DeallocateOnJobCompletion] + [NativeDisableParallelForRestriction] + public NativeArray LayerAlphaMaskEmpty; + + // Outputs + [NativeDisableParallelForRestriction] + public NativeArray DecodedImage; + + // Colors. + public byte UserMaskBackgroundColor; + public byte LayerMaskBackgroundColor; + } + + internal struct PDNAlphaMaskJob : IJob + { + + public PDNAlphaMaskData Data; + + public void Execute() + { + + for (int idx = Data.Rect.Top; idx < Data.Rect.Bottom; idx++) + { + // Calculate index into ImageData source from row and column. + int idxSrcPixel = (idx - Data.LayerRect.Top) * Data.LayerRect.Width + (Data.Rect.Left - Data.LayerRect.Left); + int idxSrcBytes = idxSrcPixel * Data.SurfaceByteDepth; + + // Calculate pointers to destination Surface. + var idxDstStart = idx * Data.SurfaceWidth + Data.ClippedRect.Left; + var idxDstStops = idx * Data.SurfaceWidth + Data.ClippedRect.Right; + + // For 16-bit images, take the higher-order byte from the image data, which is now in little-endian order. + if (Data.SurfaceByteDepth == 2) + { + idxSrcBytes++; + } + + SetPDNAlphaRow(idxDstStart, idxDstStops, idxSrcBytes); + if (0 != Data.HasLayerAlphaMask) + { + GetMaskAlphaRow(idx, Data.LayerAlphaMask, Data.LayerAlphaMaskEmpty, Data.LayerMask, Data.LayerMaskInvertOnBlend, Data.LayerMaskBackgroundColor, Data.LayerMaskContextRect, Data.LayerMaskRect); + } + if (0 != Data.HasUserAlphaMask) + { + GetMaskAlphaRow(idx, Data.UserAlphaMask, Data.UserAlphaMaskEmpty, Data.UserMask, Data.UserMaskInvertOnBlend, Data.UserMaskBackgroundColor, Data.UserMaskContextRect, Data.UserMaskRect); + } + ApplyPDNMask(idxDstStart, idxDstStops); + + } + } + + private void SetPDNAlphaRow(int dstStart, int dstStops, int idxSrc) + { + // Set alpha to fully-opaque if there is no alpha channel + if (0 == Data.HasAlphaChannel) + { + while (dstStart < dstStops) + { + var c = Data.DecodedImage[dstStart]; + c.a = 255; + Data.DecodedImage[dstStart] = c; + dstStart++; + } + } + // Set the alpha channel data + else + { + NativeArray srcAlphaChannel = Data.AlphaChannel0.Reinterpret(1); + { + while (dstStart < dstStops) + { + var c = Data.DecodedImage[dstStart]; + c.a = (Data.SurfaceByteDepth < 4) ? Data.AlphaChannel0[idxSrc] : ImageDecoderPdn.RGBByteFromHDRFloat(srcAlphaChannel[idxSrc / 4]); + + Data.DecodedImage[dstStart] = c; + dstStart++; + idxSrc += Data.SurfaceByteDepth; + } + } + } + } + + private void ApplyPDNMask(int dstStart, int dstStops) + { + // Do nothing if there are no masks + if (0 == Data.HasLayerAlphaMask && 0 == Data.HasUserAlphaMask) + { + return; + } + + // Apply one mask + else if (0 == Data.HasLayerAlphaMask || 0 == Data.HasUserAlphaMask) + { + var maskAlpha = (0 == Data.HasLayerAlphaMask) ? Data.UserAlphaMask : Data.LayerAlphaMask; + var maskStart = 0; + { + var c = Data.DecodedImage[dstStart]; + while (dstStart < dstStops) + { + c.a = (byte)(Data.DecodedImage[dstStart].a * maskAlpha[maskStart] / 255); + Data.DecodedImage[dstStart] = c; + dstStart++; + maskStart++; + } + } + } + // Apply both masks in one pass, to minimize rounding error + else + { + var maskStart = 0; + var c = Data.DecodedImage[dstStart]; + { + while (dstStart < dstStops) + { + var alphaFactor = (Data.LayerAlphaMask[maskStart]) * (Data.UserAlphaMask[maskStart]); + c.a = (byte)(Data.DecodedImage[dstStart].a * alphaFactor / 65025); + Data.DecodedImage[dstStart] = c; + + dstStart++; + maskStart++; + } + } + } + } + + private void DecodeMaskAlphaRow32(NativeArray Alpha, int dstStart, int dstStops, NativeArray Mask, int maskStart) + { + NativeArray floatArray = Mask.Reinterpret(1); + + while (dstStart < dstStops) + { + Alpha[dstStart] = ImageDecoderPdn.RGBByteFromHDRFloat(floatArray[maskStart / 4]); + + dstStart++; + maskStart += 4; + } + } + + private void DecodeMaskAlphaRow(NativeArray Alpha, int dstStart, int dstStops, NativeArray Mask, int maskStart, int byteDepth) + { + while (dstStart < dstStops) + { + Alpha[dstStart] = Mask[maskStart]; + + dstStart++; + maskStart += byteDepth; + } + } + + private unsafe void GetMaskAlphaRow(int idxSrc, NativeArray alphaBuffer, NativeArray alphaBufferEmpty, NativeArray maskChannel, int MaskInvertOnBlend, byte MaskBackgroundColor, PDNWrapper.Rectangle MaskContextRect, PDNWrapper.Rectangle MaskRect) + { + ////////////////////////////////////// + // Transfer mask into the alpha array + // Background color for areas not covered by the mask + byte backgroundColor = (0 != MaskInvertOnBlend) ? (byte)(255 - MaskBackgroundColor) : MaskBackgroundColor; + { + var alphaBufferPtr = NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(alphaBuffer); + UnsafeUtility.MemSet(alphaBufferPtr, backgroundColor, alphaBuffer.Length); + } + // Only process if not Empty. + if (alphaBufferEmpty[idxSrc] == 0) + { + // Get pointers to starting positions + int alphaColumn = MaskContextRect.X; + // It's possible that the layer's rect is larger than the clip and it's offset. + // Since we only copy out the alpha based on the MaskContext size + // The copy will start from where the MaskContextRect is + if(Data.LayerRect.X > 0) + alphaColumn = MaskContextRect.X - Data.LayerRect.X; + var pAlpha = alphaColumn; + var pAlphaEnd = pAlpha + MaskContextRect.Width; + + int maskRow = idxSrc - MaskRect.Y; + int maskColumn = MaskContextRect.X - MaskRect.X; + int idxMaskPixel = (maskRow * MaskRect.Width) + maskColumn; + var pMask = idxMaskPixel * Data.SurfaceByteDepth; + + // Take the high-order byte if values are 16-bit (little-endian) + if (Data.SurfaceByteDepth == 2) + { + pMask++; + } + + // Decode mask into the alpha array. + if (Data.SurfaceByteDepth == 4) + { + DecodeMaskAlphaRow32(alphaBuffer, pAlpha, pAlphaEnd, maskChannel, pMask); + } + else + { + DecodeMaskAlphaRow(alphaBuffer, pAlpha, pAlphaEnd, maskChannel, pMask, Data.SurfaceByteDepth); + } + + // Obsolete since Photoshop CS6, but retained for compatibility with older versions. Note that the background has already been inverted. + if (0 != MaskInvertOnBlend) + { + PhotoshopFile.Util.Invert(alphaBuffer, pAlpha, pAlphaEnd); + } + } + } + } + + #endregion } \ No newline at end of file diff --git a/Editor/PSDPlugin/PDNWrapper/PDNDecodeJob.cs.meta b/Editor/PSDPlugin/PDNWrapper/PDNDecodeJob.cs.meta index 5769e3e..5d1015d 100644 --- a/Editor/PSDPlugin/PDNWrapper/PDNDecodeJob.cs.meta +++ b/Editor/PSDPlugin/PDNWrapper/PDNDecodeJob.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 806458e67991c7449a38f7d942188a0e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 806458e67991c7449a38f7d942188a0e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PDNWrapper/Rectangle.cs b/Editor/PSDPlugin/PDNWrapper/Rectangle.cs index 967d783..ce4b4f3 100644 --- a/Editor/PSDPlugin/PDNWrapper/Rectangle.cs +++ b/Editor/PSDPlugin/PDNWrapper/Rectangle.cs @@ -1,258 +1,258 @@ -using System; - -namespace PDNWrapper -{ - // Mimics System.Drawing.Rectangle - internal struct Rectangle - { - public static readonly Rectangle Empty = new Rectangle(); - - private int x; - private int y; - private int width; - private int height; - - public Rectangle(int x, int y, int width, int height) - { - this.x = x; - this.y = y; - this.width = width; - this.height = height; - } - - public static Rectangle FromLTRB(int left, int top, int right, int bottom) - { - return new Rectangle(left, - top, - right - left, - bottom - top); - } - - public Size Size - { - get - { - return new Size(Width, Height); - } - set - { - this.Width = value.Width; - this.Height = value.Height; - } - } - - public int X - { - get - { - return x; - } - set - { - x = value; - } - } - - public int Y - { - get - { - return y; - } - set - { - y = value; - } - } - - public int Width - { - get - { - return width; - } - set - { - width = value; - } - } - - public int Height - { - get - { - return height; - } - set - { - height = value; - } - } - - public int Left - { - get - { - return X; - } - } - - public int Top - { - get - { - return Y; - } - } - - public int Right - { - get - { - return X + Width; - } - } - - public int Bottom - { - get - { - return Y + Height; - } - } - - public bool IsEmpty - { - get - { - return height == 0 && width == 0 && x == 0 && y == 0; - } - } - - public override bool Equals(object obj) - { - if (!(obj is Rectangle)) - return false; - - Rectangle comp = (Rectangle)obj; - - return (comp.X == this.X) && - (comp.Y == this.Y) && - (comp.Width == this.Width) && - (comp.Height == this.Height); - } - - public static bool operator==(Rectangle left, Rectangle right) - { - return (left.X == right.X - && left.Y == right.Y - && left.Width == right.Width - && left.Height == right.Height); - } - - public static bool operator!=(Rectangle left, Rectangle right) - { - return !(left == right); - } - - public bool Contains(int x, int y) - { - return this.X <= x && - x < this.X + this.Width && - this.Y <= y && - y < this.Y + this.Height; - } - - public bool Contains(Rectangle rect) - { - return (this.X <= rect.X) && - ((rect.X + rect.Width) <= (this.X + this.Width)) && - (this.Y <= rect.Y) && - ((rect.Y + rect.Height) <= (this.Y + this.Height)); - } - - public override int GetHashCode() - { - return (int)((UInt32)X ^ - (((UInt32)Y << 13) | ((UInt32)Y >> 19)) ^ - (((UInt32)Width << 26) | ((UInt32)Width >> 6)) ^ - (((UInt32)Height << 7) | ((UInt32)Height >> 25))); - } - - public void Inflate(int width, int height) - { - this.X -= width; - this.Y -= height; - this.Width += 2 * width; - this.Height += 2 * height; - } - - public void Inflate(Size size) - { - Inflate(size.Width, size.Height); - } - - public static Rectangle Inflate(Rectangle rect, int x, int y) - { - Rectangle r = rect; - r.Inflate(x, y); - return r; - } - - public void Intersect(Rectangle rect) - { - Rectangle result = Rectangle.Intersect(rect, this); - - this.X = result.X; - this.Y = result.Y; - this.Width = result.Width; - this.Height = result.Height; - } - - public static Rectangle Intersect(Rectangle a, Rectangle b) - { - int x1 = Math.Max(a.X, b.X); - int x2 = Math.Min(a.X + a.Width, b.X + b.Width); - int y1 = Math.Max(a.Y, b.Y); - int y2 = Math.Min(a.Y + a.Height, b.Y + b.Height); - - if (x2 >= x1 - && y2 >= y1) - { - return new Rectangle(x1, y1, x2 - x1, y2 - y1); - } - return Rectangle.Empty; - } - - public bool IntersectsWith(Rectangle rect) - { - return (rect.X < this.X + this.Width) && - (this.X < (rect.X + rect.Width)) && - (rect.Y < this.Y + this.Height) && - (this.Y < rect.Y + rect.Height); - } - - public static Rectangle Union(Rectangle a, Rectangle b) - { - int x1 = Math.Min(a.X, b.X); - int x2 = Math.Max(a.X + a.Width, b.X + b.Width); - int y1 = Math.Min(a.Y, b.Y); - int y2 = Math.Max(a.Y + a.Height, b.Y + b.Height); - - return new Rectangle(x1, y1, x2 - x1, y2 - y1); - } - - public void Offset(int x, int y) - { - this.X += x; - this.Y += y; - } - - public override string ToString() - { - return "{X=" + X.ToString() + ",Y=" + Y.ToString() + - ",Width=" + Width.ToString() + - ",Height=" + Height.ToString() + "}"; - } - } -} +using System; + +namespace PDNWrapper +{ + // Mimics System.Drawing.Rectangle + internal struct Rectangle + { + public static readonly Rectangle Empty = new Rectangle(); + + private int x; + private int y; + private int width; + private int height; + + public Rectangle(int x, int y, int width, int height) + { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + public static Rectangle FromLTRB(int left, int top, int right, int bottom) + { + return new Rectangle(left, + top, + right - left, + bottom - top); + } + + public Size Size + { + get + { + return new Size(Width, Height); + } + set + { + this.Width = value.Width; + this.Height = value.Height; + } + } + + public int X + { + get + { + return x; + } + set + { + x = value; + } + } + + public int Y + { + get + { + return y; + } + set + { + y = value; + } + } + + public int Width + { + get + { + return width; + } + set + { + width = value; + } + } + + public int Height + { + get + { + return height; + } + set + { + height = value; + } + } + + public int Left + { + get + { + return X; + } + } + + public int Top + { + get + { + return Y; + } + } + + public int Right + { + get + { + return X + Width; + } + } + + public int Bottom + { + get + { + return Y + Height; + } + } + + public bool IsEmpty + { + get + { + return height == 0 && width == 0 && x == 0 && y == 0; + } + } + + public override bool Equals(object obj) + { + if (!(obj is Rectangle)) + return false; + + Rectangle comp = (Rectangle)obj; + + return (comp.X == this.X) && + (comp.Y == this.Y) && + (comp.Width == this.Width) && + (comp.Height == this.Height); + } + + public static bool operator==(Rectangle left, Rectangle right) + { + return (left.X == right.X + && left.Y == right.Y + && left.Width == right.Width + && left.Height == right.Height); + } + + public static bool operator!=(Rectangle left, Rectangle right) + { + return !(left == right); + } + + public bool Contains(int x, int y) + { + return this.X <= x && + x < this.X + this.Width && + this.Y <= y && + y < this.Y + this.Height; + } + + public bool Contains(Rectangle rect) + { + return (this.X <= rect.X) && + ((rect.X + rect.Width) <= (this.X + this.Width)) && + (this.Y <= rect.Y) && + ((rect.Y + rect.Height) <= (this.Y + this.Height)); + } + + public override int GetHashCode() + { + return (int)((UInt32)X ^ + (((UInt32)Y << 13) | ((UInt32)Y >> 19)) ^ + (((UInt32)Width << 26) | ((UInt32)Width >> 6)) ^ + (((UInt32)Height << 7) | ((UInt32)Height >> 25))); + } + + public void Inflate(int width, int height) + { + this.X -= width; + this.Y -= height; + this.Width += 2 * width; + this.Height += 2 * height; + } + + public void Inflate(Size size) + { + Inflate(size.Width, size.Height); + } + + public static Rectangle Inflate(Rectangle rect, int x, int y) + { + Rectangle r = rect; + r.Inflate(x, y); + return r; + } + + public void Intersect(Rectangle rect) + { + Rectangle result = Rectangle.Intersect(rect, this); + + this.X = result.X; + this.Y = result.Y; + this.Width = result.Width; + this.Height = result.Height; + } + + public static Rectangle Intersect(Rectangle a, Rectangle b) + { + int x1 = Math.Max(a.X, b.X); + int x2 = Math.Min(a.X + a.Width, b.X + b.Width); + int y1 = Math.Max(a.Y, b.Y); + int y2 = Math.Min(a.Y + a.Height, b.Y + b.Height); + + if (x2 >= x1 + && y2 >= y1) + { + return new Rectangle(x1, y1, x2 - x1, y2 - y1); + } + return Rectangle.Empty; + } + + public bool IntersectsWith(Rectangle rect) + { + return (rect.X < this.X + this.Width) && + (this.X < (rect.X + rect.Width)) && + (rect.Y < this.Y + this.Height) && + (this.Y < rect.Y + rect.Height); + } + + public static Rectangle Union(Rectangle a, Rectangle b) + { + int x1 = Math.Min(a.X, b.X); + int x2 = Math.Max(a.X + a.Width, b.X + b.Width); + int y1 = Math.Min(a.Y, b.Y); + int y2 = Math.Max(a.Y + a.Height, b.Y + b.Height); + + return new Rectangle(x1, y1, x2 - x1, y2 - y1); + } + + public void Offset(int x, int y) + { + this.X += x; + this.Y += y; + } + + public override string ToString() + { + return "{X=" + X.ToString() + ",Y=" + Y.ToString() + + ",Width=" + Width.ToString() + + ",Height=" + Height.ToString() + "}"; + } + } +} diff --git a/Editor/PSDPlugin/PDNWrapper/Rectangle.cs.meta b/Editor/PSDPlugin/PDNWrapper/Rectangle.cs.meta index 392d0b4..0e44c83 100644 --- a/Editor/PSDPlugin/PDNWrapper/Rectangle.cs.meta +++ b/Editor/PSDPlugin/PDNWrapper/Rectangle.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: e8fe32ddfd1506f47955dad6247df316 -timeCreated: 1495006554 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: e8fe32ddfd1506f47955dad6247df316 +timeCreated: 1495006554 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PDNWrapper/Size.cs b/Editor/PSDPlugin/PDNWrapper/Size.cs index b6a6bf2..d08414f 100644 --- a/Editor/PSDPlugin/PDNWrapper/Size.cs +++ b/Editor/PSDPlugin/PDNWrapper/Size.cs @@ -1,49 +1,49 @@ -namespace PDNWrapper -{ - // Mimics System.Drawing.Size - internal struct Size - { - public static readonly Size Empty = new Size(); - - private int width; - private int height; - - public Size(int width, int height) - { - this.width = width; - this.height = height; - } - - public bool IsEmpty - { - get - { - return width == 0 && height == 0; - } - } - - public int Width - { - get - { - return width; - } - set - { - width = value; - } - } - - public int Height - { - get - { - return height; - } - set - { - height = value; - } - } - } -} +namespace PDNWrapper +{ + // Mimics System.Drawing.Size + internal struct Size + { + public static readonly Size Empty = new Size(); + + private int width; + private int height; + + public Size(int width, int height) + { + this.width = width; + this.height = height; + } + + public bool IsEmpty + { + get + { + return width == 0 && height == 0; + } + } + + public int Width + { + get + { + return width; + } + set + { + width = value; + } + } + + public int Height + { + get + { + return height; + } + set + { + height = value; + } + } + } +} diff --git a/Editor/PSDPlugin/PDNWrapper/Size.cs.meta b/Editor/PSDPlugin/PDNWrapper/Size.cs.meta index 0821485..98d5ce3 100644 --- a/Editor/PSDPlugin/PDNWrapper/Size.cs.meta +++ b/Editor/PSDPlugin/PDNWrapper/Size.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: a81bd8318454c4f4f9e22a9e00bb9e3d -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: a81bd8318454c4f4f9e22a9e00bb9e3d +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PDNWrapper/Surface.cs b/Editor/PSDPlugin/PDNWrapper/Surface.cs index f8daa56..7bee37a 100644 --- a/Editor/PSDPlugin/PDNWrapper/Surface.cs +++ b/Editor/PSDPlugin/PDNWrapper/Surface.cs @@ -1,29 +1,29 @@ -using Unity.Collections; -using UnityEngine; - -namespace PDNWrapper -{ - internal class Surface - { - NativeArray m_Color; - public Surface(int w, int h) - { - width = w; - height = h; - m_Color = new NativeArray(width * height, Allocator.Persistent); - } - - public void Dispose() - { - m_Color.Dispose(); - } - - public NativeArray color - { - get { return m_Color; } - } - - public int width { get; private set; } - public int height { get; private set; } - } -} +using Unity.Collections; +using UnityEngine; + +namespace PDNWrapper +{ + internal class Surface + { + NativeArray m_Color; + public Surface(int w, int h) + { + width = w; + height = h; + m_Color = new NativeArray(width * height, Allocator.Persistent); + } + + public void Dispose() + { + m_Color.Dispose(); + } + + public NativeArray color + { + get { return m_Color; } + } + + public int width { get; private set; } + public int height { get; private set; } + } +} diff --git a/Editor/PSDPlugin/PDNWrapper/Surface.cs.meta b/Editor/PSDPlugin/PDNWrapper/Surface.cs.meta index f398ebb..f837d86 100644 --- a/Editor/PSDPlugin/PDNWrapper/Surface.cs.meta +++ b/Editor/PSDPlugin/PDNWrapper/Surface.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 1b467712e18b40c4f90510e9d0364faf -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 1b467712e18b40c4f90510e9d0364faf +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PhotoShopFileType.meta b/Editor/PSDPlugin/PhotoShopFileType.meta index 9ce96c6..b3f8a8b 100644 --- a/Editor/PSDPlugin/PhotoShopFileType.meta +++ b/Editor/PSDPlugin/PhotoShopFileType.meta @@ -1,9 +1,9 @@ -fileFormatVersion: 2 -guid: 36a1cbeb5badf2a4abdcb1dcefa0efb6 -folderAsset: yes -timeCreated: 1495006553 -licenseType: Pro -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 36a1cbeb5badf2a4abdcb1dcefa0efb6 +folderAsset: yes +timeCreated: 1495006553 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PhotoShopFileType/BlendModeMapping.cs b/Editor/PSDPlugin/PhotoShopFileType/BlendModeMapping.cs index 937b42e..b5a6f1d 100644 --- a/Editor/PSDPlugin/PhotoShopFileType/BlendModeMapping.cs +++ b/Editor/PSDPlugin/PhotoShopFileType/BlendModeMapping.cs @@ -1,107 +1,107 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2014 Tao Yue -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; - -using PaintDotNet; -using PhotoshopFile; -using PDNWrapper; - -namespace PaintDotNet.Data.PhotoshopFileType -{ - internal static class BlendModeMapping - { - /// - /// Convert between Paint.NET and Photoshop blend modes. - /// - public static string ToPsdBlendMode(this LayerBlendMode pdnBlendMode) - { - switch (pdnBlendMode) - { - case LayerBlendMode.Normal: - return PsdBlendMode.Normal; - - case LayerBlendMode.Multiply: - return PsdBlendMode.Multiply; - case LayerBlendMode.Additive: - return PsdBlendMode.LinearDodge; - case LayerBlendMode.ColorBurn: - return PsdBlendMode.ColorBurn; - case LayerBlendMode.ColorDodge: - return PsdBlendMode.ColorDodge; - case LayerBlendMode.Overlay: - return PsdBlendMode.Overlay; - case LayerBlendMode.Difference: - return PsdBlendMode.Difference; - case LayerBlendMode.Lighten: - return PsdBlendMode.Lighten; - case LayerBlendMode.Darken: - return PsdBlendMode.Darken; - case LayerBlendMode.Screen: - return PsdBlendMode.Screen; - - // Paint.NET blend modes without a Photoshop equivalent are saved - // as Normal. - case LayerBlendMode.Glow: - case LayerBlendMode.Negation: - case LayerBlendMode.Reflect: - case LayerBlendMode.Xor: - return PsdBlendMode.Normal; - - default: - Debug.Fail("Unknown Paint.NET blend mode."); - return PsdBlendMode.Normal; - } - } - - /// - /// Convert a Photoshop blend mode to a Paint.NET BlendOp. - /// - public static LayerBlendMode FromPsdBlendMode(string blendModeKey) - { - switch (blendModeKey) - { - case PsdBlendMode.Normal: - return LayerBlendMode.Normal; - - case PsdBlendMode.Multiply: - return LayerBlendMode.Multiply; - case PsdBlendMode.LinearDodge: - return LayerBlendMode.Additive; - case PsdBlendMode.ColorBurn: - return LayerBlendMode.ColorBurn; - case PsdBlendMode.ColorDodge: - return LayerBlendMode.ColorDodge; - case PsdBlendMode.Overlay: - return LayerBlendMode.Overlay; - case PsdBlendMode.Difference: - return LayerBlendMode.Difference; - case PsdBlendMode.Lighten: - return LayerBlendMode.Lighten; - case PsdBlendMode.Darken: - return LayerBlendMode.Darken; - case PsdBlendMode.Screen: - return LayerBlendMode.Screen; - - // Photoshop blend modes without a Paint.NET equivalent are loaded - // as Normal. - default: - return LayerBlendMode.Normal; - } - } - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2014 Tao Yue +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; + +using PaintDotNet; +using PhotoshopFile; +using PDNWrapper; + +namespace PaintDotNet.Data.PhotoshopFileType +{ + internal static class BlendModeMapping + { + /// + /// Convert between Paint.NET and Photoshop blend modes. + /// + public static string ToPsdBlendMode(this LayerBlendMode pdnBlendMode) + { + switch (pdnBlendMode) + { + case LayerBlendMode.Normal: + return PsdBlendMode.Normal; + + case LayerBlendMode.Multiply: + return PsdBlendMode.Multiply; + case LayerBlendMode.Additive: + return PsdBlendMode.LinearDodge; + case LayerBlendMode.ColorBurn: + return PsdBlendMode.ColorBurn; + case LayerBlendMode.ColorDodge: + return PsdBlendMode.ColorDodge; + case LayerBlendMode.Overlay: + return PsdBlendMode.Overlay; + case LayerBlendMode.Difference: + return PsdBlendMode.Difference; + case LayerBlendMode.Lighten: + return PsdBlendMode.Lighten; + case LayerBlendMode.Darken: + return PsdBlendMode.Darken; + case LayerBlendMode.Screen: + return PsdBlendMode.Screen; + + // Paint.NET blend modes without a Photoshop equivalent are saved + // as Normal. + case LayerBlendMode.Glow: + case LayerBlendMode.Negation: + case LayerBlendMode.Reflect: + case LayerBlendMode.Xor: + return PsdBlendMode.Normal; + + default: + Debug.Fail("Unknown Paint.NET blend mode."); + return PsdBlendMode.Normal; + } + } + + /// + /// Convert a Photoshop blend mode to a Paint.NET BlendOp. + /// + public static LayerBlendMode FromPsdBlendMode(string blendModeKey) + { + switch (blendModeKey) + { + case PsdBlendMode.Normal: + return LayerBlendMode.Normal; + + case PsdBlendMode.Multiply: + return LayerBlendMode.Multiply; + case PsdBlendMode.LinearDodge: + return LayerBlendMode.Additive; + case PsdBlendMode.ColorBurn: + return LayerBlendMode.ColorBurn; + case PsdBlendMode.ColorDodge: + return LayerBlendMode.ColorDodge; + case PsdBlendMode.Overlay: + return LayerBlendMode.Overlay; + case PsdBlendMode.Difference: + return LayerBlendMode.Difference; + case PsdBlendMode.Lighten: + return LayerBlendMode.Lighten; + case PsdBlendMode.Darken: + return LayerBlendMode.Darken; + case PsdBlendMode.Screen: + return LayerBlendMode.Screen; + + // Photoshop blend modes without a Paint.NET equivalent are loaded + // as Normal. + default: + return LayerBlendMode.Normal; + } + } + } +} diff --git a/Editor/PSDPlugin/PhotoShopFileType/BlendModeMapping.cs.meta b/Editor/PSDPlugin/PhotoShopFileType/BlendModeMapping.cs.meta index 9eac4c8..ebc52d8 100644 --- a/Editor/PSDPlugin/PhotoShopFileType/BlendModeMapping.cs.meta +++ b/Editor/PSDPlugin/PhotoShopFileType/BlendModeMapping.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 3045ca2469fb18a48a1b874587e1df9e -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 3045ca2469fb18a48a1b874587e1df9e +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PhotoShopFileType/DocumentLoadContext.cs b/Editor/PSDPlugin/PhotoShopFileType/DocumentLoadContext.cs index 292b402..502d173 100644 --- a/Editor/PSDPlugin/PhotoShopFileType/DocumentLoadContext.cs +++ b/Editor/PSDPlugin/PhotoShopFileType/DocumentLoadContext.cs @@ -1,46 +1,46 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2016 Tao Yue -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -using PhotoshopFile; - -namespace PaintDotNet.Data.PhotoshopFileType -{ - /// - /// Controls the loading of a PSD file into a Paint.NET Document. - /// - internal class DocumentLoadContext : LoadContext - { - public DocumentLoadContext() : base() - { - } - - public override void OnLoadLayersHeader(PsdFile psdFile) - { - PsdLoad.CheckSufficientMemory(psdFile); - } - - public override void OnLoadLayerHeader(PhotoshopFile.Layer layer) - { - var psdFile = layer.PsdFile; - if (psdFile.ColorMode == PsdColorMode.Multichannel) - { - PsdLoad.CheckSufficientMemory(psdFile); - } - } - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2016 Tao Yue +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using PhotoshopFile; + +namespace PaintDotNet.Data.PhotoshopFileType +{ + /// + /// Controls the loading of a PSD file into a Paint.NET Document. + /// + internal class DocumentLoadContext : LoadContext + { + public DocumentLoadContext() : base() + { + } + + public override void OnLoadLayersHeader(PsdFile psdFile) + { + PsdLoad.CheckSufficientMemory(psdFile); + } + + public override void OnLoadLayerHeader(PhotoshopFile.Layer layer) + { + var psdFile = layer.PsdFile; + if (psdFile.ColorMode == PsdColorMode.Multichannel) + { + PsdLoad.CheckSufficientMemory(psdFile); + } + } + } +} diff --git a/Editor/PSDPlugin/PhotoShopFileType/DocumentLoadContext.cs.meta b/Editor/PSDPlugin/PhotoShopFileType/DocumentLoadContext.cs.meta index c9a6de6..5c3873a 100644 --- a/Editor/PSDPlugin/PhotoShopFileType/DocumentLoadContext.cs.meta +++ b/Editor/PSDPlugin/PhotoShopFileType/DocumentLoadContext.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 138d3cdf8c274dd4c995e7ec72539d1b -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 138d3cdf8c274dd4c995e7ec72539d1b +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PhotoShopFileType/ImageDecoderPdn.cs b/Editor/PSDPlugin/PhotoShopFileType/ImageDecoderPdn.cs index 9c3a0e2..184949e 100644 --- a/Editor/PSDPlugin/PhotoShopFileType/ImageDecoderPdn.cs +++ b/Editor/PSDPlugin/PhotoShopFileType/ImageDecoderPdn.cs @@ -1,807 +1,807 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2014 Tao Yue -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using PaintDotNet; - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using PDNWrapper; -using System.Text; - -using PhotoshopFile; -using Unity.Collections; -using Unity.Collections.LowLevel.Unsafe; -using UnityEngine; -using Debug = UnityEngine.Debug; -using Unity.Jobs; - -namespace PaintDotNet.Data.PhotoshopFileType -{ - - internal enum DecodeType - { - RGB32 = 0, - Grayscale32 = 1, - RGB = 2, - CMYK = 3, - Bitmap = 4, - Grayscale = 5, - Indexed = 6, - Lab = 7 - }; - - internal static class ImageDecoderPdn - { - private static double rgbExponent = 1 / 2.19921875; - - private class DecodeContext - { - public PhotoshopFile.Layer Layer { get; private set; } - public int ByteDepth { get; private set; } - public int HasAlphaChannel { get; private set; } - public Channel[] Channels { get; private set; } - public NativeArray AlphaChannel { get; private set; } - public PsdColorMode ColorMode { get; private set; } - public NativeArray ColorModeData { get; private set; } - - public Rectangle Rectangle { get; private set; } - public MaskDecodeContext LayerMaskContext { get; private set; } - public MaskDecodeContext UserMaskContext { get; private set; } - - public DecodeContext(PhotoshopFile.Layer layer, Rectangle bounds) - { - Layer = layer; - ByteDepth = Util.BytesFromBitDepth(layer.PsdFile.BitDepth); - HasAlphaChannel = 0; - Channels = layer.Channels.ToIdArray(); - - var alphaSize = 4; - if (layer.AlphaChannel != null && layer.AlphaChannel.ImageData.Length > 0) - { - HasAlphaChannel = 1; - alphaSize = layer.AlphaChannel.ImageData.Length; - alphaSize = (alphaSize / 4) + (alphaSize % 4 > 0 ? 1 : 0); - alphaSize = alphaSize * 4; - } - AlphaChannel = new NativeArray(alphaSize, Allocator.TempJob); - if (HasAlphaChannel > 0) - NativeArray.Copy(layer.AlphaChannel.ImageData, AlphaChannel, layer.AlphaChannel.ImageData.Length); - ColorMode = layer.PsdFile.ColorMode; - ColorModeData = new NativeArray(layer.PsdFile.ColorModeData, Allocator.TempJob); - - // Clip the layer to the specified bounds - Rectangle = Layer.Rect.IntersectWith(bounds); - - if (layer.Masks != null) - { - LayerMaskContext = GetMaskContext(layer.Masks.LayerMask); - UserMaskContext = GetMaskContext(layer.Masks.UserMask); - } - } - - internal void Cleanup() - { - AlphaChannel.Dispose(); - ColorModeData.Dispose(); - } - - private MaskDecodeContext GetMaskContext(Mask mask) - { - if ((mask == null) || (mask.Disabled)) - { - return null; - } - - return new MaskDecodeContext(mask, this); - } - } - - private class MaskDecodeContext - { - public Mask Mask { get; private set; } - public Rectangle Rectangle { get; private set; } - public MaskDecodeContext(Mask mask, DecodeContext layerContext) - { - Mask = mask; - - // The PositionVsLayer flag is documented to indicate a position - // relative to the layer, but Photoshop treats the position as - // absolute. So that's what we do, too. - Rectangle = mask.Rect.IntersectWith(layerContext.Rectangle); - } - - public bool IsRowEmpty(int row) - { - return (Mask.ImageData == null) - || (Mask.ImageData.Length == 0) - || (Rectangle.Size.IsEmpty) - || (row < Rectangle.Top) - || (row >= Rectangle.Bottom); - } - } - - /////////////////////////////////////////////////////////////////////////////// - - internal static byte RGBByteFromHDRFloat(float ptr) - { - var result = (byte)(255 * Math.Pow(ptr, rgbExponent)); - return result; - } - - private static DecodeDelegate GetDecodeDelegate(PsdColorMode psdColorMode, ref DecodeType decoderType) - { - switch (psdColorMode) - { - case PsdColorMode.Bitmap: - decoderType = DecodeType.Bitmap; - return SetPDNRowBitmap; - case PsdColorMode.Grayscale: - case PsdColorMode.Duotone: - decoderType = DecodeType.Grayscale; - return SetPDNRowGrayscale; - case PsdColorMode.Indexed: - decoderType = DecodeType.Indexed; - return SetPDNRowIndexed; - case PsdColorMode.RGB: - decoderType = DecodeType.RGB; - return SetPDNRowRgb; - case PsdColorMode.CMYK: - decoderType = DecodeType.CMYK; - return SetPDNRowCmyk; - case PsdColorMode.Lab: - decoderType = DecodeType.Lab; - return SetPDNRowLab; - case PsdColorMode.Multichannel: - throw new Exception("Cannot decode multichannel."); - default: - throw new Exception("Unknown color mode."); - } - } - - private static DecodeDelegate GetDecodeDelegate32(PsdColorMode psdColorMode, ref DecodeType decoderType) - { - switch (psdColorMode) - { - case PsdColorMode.Grayscale: - decoderType = DecodeType.Grayscale32; - return SetPDNRowGrayscale32; - case PsdColorMode.RGB: - decoderType = DecodeType.RGB32; - return SetPDNRowRgb32; - default: - throw new PsdInvalidException( - "32-bit HDR images must be either RGB or grayscale."); - } - } - - /// - /// Decode image from Photoshop's channel-separated formats to BGRA. - /// - public static JobHandle DecodeImage(BitmapLayer pdnLayer, PhotoshopFile.Layer psdLayer, JobHandle inputDeps) - { - UnityEngine.Profiling.Profiler.BeginSample("DecodeImage"); - var decodeContext = new DecodeContext(psdLayer, pdnLayer.Bounds); - DecodeDelegate decoder = null; - DecodeType decoderType = 0; - - if (decodeContext.ByteDepth == 4) - decoder = GetDecodeDelegate32(decodeContext.ColorMode, ref decoderType); - else - decoder = GetDecodeDelegate(decodeContext.ColorMode, ref decoderType); - - JobHandle jobHandle = DecodeImage(pdnLayer, decodeContext, decoderType, inputDeps); - UnityEngine.Profiling.Profiler.EndSample(); - return jobHandle; - } - - /// - /// Decode image from Photoshop's channel-separated formats to BGRA, - /// using the specified decode delegate on each row. - /// - private static JobHandle DecodeImage(BitmapLayer pdnLayer, DecodeContext decodeContext, DecodeType decoderType, JobHandle inputDeps) - { - - var psdLayer = decodeContext.Layer; - var surface = pdnLayer.Surface; - var rect = decodeContext.Rectangle; - - // Convert rows from the Photoshop representation, writing the - // resulting ARGB values to to the Paint.NET Surface. - - int jobCount = Unity.Jobs.LowLevel.Unsafe.JobsUtility.JobWorkerMaximumCount; - int execCount = (rect.Bottom - rect.Top); - int sliceCount = execCount / jobCount; - PDNDecoderJob decoderJob = new PDNDecoderJob(); - - decoderJob.Data.Rect = rect; - decoderJob.Data.LayerRect = psdLayer.Rect; - decoderJob.Data.ClippedRect = rect; - decoderJob.Data.SurfaceWidth = surface.width; - decoderJob.Data.SurfaceHeight = surface.height; - decoderJob.Data.SurfaceByteDepth = decodeContext.ByteDepth; - decoderJob.Data.DecoderType = decoderType; - - decoderJob.Data.ColorChannel0 = decodeContext.Channels[0].ImageData; - decoderJob.Data.ColorChannel1 = decodeContext.Channels.Length > 1 ? decodeContext.Channels[1].ImageData : decodeContext.Channels[0].ImageData; - decoderJob.Data.ColorChannel2 = decodeContext.Channels.Length > 2 ? decodeContext.Channels[2].ImageData : decodeContext.Channels[0].ImageData; - decoderJob.Data.ColorChannel3 = decodeContext.Channels.Length > 3 ? decodeContext.Channels[3].ImageData : decodeContext.Channels[0].ImageData; - decoderJob.Data.ColorModeData = decodeContext.ColorModeData; - decoderJob.Data.DecodedImage = surface.color; - - // Schedule the job, returns the JobHandle which can be waited upon later on - JobHandle jobHandle = decoderJob.Schedule(execCount, sliceCount, inputDeps); - - // Mask and Alpha. - int userMaskContextSize = decodeContext.UserMaskContext != null ? decodeContext.Rectangle.Width : 1; - int layerMaskContextSize = decodeContext.LayerMaskContext != null ? decodeContext.Rectangle.Width : 1; - var userAlphaMask = new NativeArray(userMaskContextSize, Allocator.TempJob); - var layerAlphaMask = new NativeArray(layerMaskContextSize, Allocator.TempJob); - var userAlphaMaskEmpty = new NativeArray(rect.Bottom, Allocator.TempJob); - var layerAlphaMaskEmpty = new NativeArray(rect.Bottom, Allocator.TempJob); - - PDNAlphaMaskJob alphaMaskJob = new PDNAlphaMaskJob(); - - for (int y = rect.Top; y < rect.Bottom; ++y) - { - if (decodeContext.UserMaskContext != null) - userAlphaMaskEmpty[y] = decodeContext.UserMaskContext.IsRowEmpty(y) ? (byte)1 : (byte)0; - if (decodeContext.LayerMaskContext != null) - layerAlphaMaskEmpty[y] = decodeContext.LayerMaskContext.IsRowEmpty(y) ? (byte)1 : (byte)0; - } - - alphaMaskJob.Data.Rect = rect; - alphaMaskJob.Data.LayerRect = psdLayer.Rect; - alphaMaskJob.Data.ClippedRect = rect; - alphaMaskJob.Data.SurfaceWidth = surface.width; - alphaMaskJob.Data.SurfaceHeight = surface.height; - alphaMaskJob.Data.SurfaceByteDepth = decodeContext.ByteDepth; - alphaMaskJob.Data.HasAlphaChannel = decodeContext.HasAlphaChannel; - - alphaMaskJob.Data.HasUserAlphaMask = decodeContext.UserMaskContext != null ? 1 : 0; - alphaMaskJob.Data.UserMaskInvertOnBlend = decodeContext.UserMaskContext != null ? (decodeContext.UserMaskContext.Mask.InvertOnBlend ? 1 : 0) : 0; - alphaMaskJob.Data.UserMaskRect = decodeContext.UserMaskContext != null ? decodeContext.UserMaskContext.Mask.Rect : rect; - alphaMaskJob.Data.UserMaskContextRect = decodeContext.UserMaskContext != null ? decodeContext.UserMaskContext.Rectangle : rect; - alphaMaskJob.Data.HasLayerAlphaMask = decodeContext.LayerMaskContext != null ? 1 : 0; - alphaMaskJob.Data.LayerMaskInvertOnBlend = decodeContext.LayerMaskContext != null ? (decodeContext.LayerMaskContext.Mask.InvertOnBlend ? 1 : 0) : 0; - alphaMaskJob.Data.LayerMaskRect = decodeContext.LayerMaskContext != null ? decodeContext.LayerMaskContext.Mask.Rect : rect; - alphaMaskJob.Data.LayerMaskContextRect = decodeContext.LayerMaskContext != null ? decodeContext.LayerMaskContext.Rectangle : rect; - - alphaMaskJob.Data.AlphaChannel0 = decodeContext.AlphaChannel; - alphaMaskJob.Data.UserMask = decodeContext.UserMaskContext != null ? decodeContext.UserMaskContext.Mask.ImageData : decodeContext.AlphaChannel; - alphaMaskJob.Data.UserAlphaMask = userAlphaMask; - alphaMaskJob.Data.UserAlphaMaskEmpty = userAlphaMaskEmpty; - alphaMaskJob.Data.LayerMask = decodeContext.LayerMaskContext != null ? decodeContext.LayerMaskContext.Mask.ImageData : decodeContext.AlphaChannel; - alphaMaskJob.Data.LayerAlphaMask = layerAlphaMask; - alphaMaskJob.Data.LayerAlphaMaskEmpty = layerAlphaMaskEmpty; - alphaMaskJob.Data.DecodedImage = surface.color; - alphaMaskJob.Data.UserMaskBackgroundColor = decodeContext.UserMaskContext != null ? decodeContext.UserMaskContext.Mask.BackgroundColor : (byte)0; - alphaMaskJob.Data.LayerMaskBackgroundColor = decodeContext.LayerMaskContext != null ? decodeContext.LayerMaskContext.Mask.BackgroundColor : (byte)0; - - jobHandle = alphaMaskJob.Schedule(jobHandle); - return jobHandle; - - } - - /////////////////////////////////////////////////////////////////////////// - /// SINGLE THREADED - KEPT FOR REFERENCE - /////////////////////////////////////////////////////////////////////////// - - /// - /// Decode image from Photoshop's channel-separated formats to BGRA. - /// - public static void DecodeImage(BitmapLayer pdnLayer, PhotoshopFile.Layer psdLayer) - { - UnityEngine.Profiling.Profiler.BeginSample("DecodeImage"); - var decodeContext = new DecodeContext(psdLayer, pdnLayer.Bounds); - DecodeDelegate decoder = null; - DecodeType decoderType = 0; - - if (decodeContext.ByteDepth == 4) - decoder = GetDecodeDelegate32(decodeContext.ColorMode, ref decoderType); - else - decoder = GetDecodeDelegate(decodeContext.ColorMode, ref decoderType); - - DecodeImage(pdnLayer, decodeContext, decoder); - decodeContext.Cleanup(); - UnityEngine.Profiling.Profiler.EndSample(); - } - - private delegate void DecodeDelegate(int pDestStart, int pDestEnd, int width, NativeArray color, int idxSrc, DecodeContext context); - - /// - /// Decode image from Photoshop's channel-separated formats to BGRA, - /// using the specified decode delegate on each row. - /// - private static void DecodeImage(BitmapLayer pdnLayer, DecodeContext decodeContext, DecodeDelegate decoder) - { - - var psdLayer = decodeContext.Layer; - var surface = pdnLayer.Surface; - var rect = decodeContext.Rectangle; - - // Convert rows from the Photoshop representation, writing the - // resulting ARGB values to to the Paint.NET Surface. - for (int y = rect.Top; y < rect.Bottom; y++) - { - // Calculate index into ImageData source from row and column. - int idxSrcPixel = (y - psdLayer.Rect.Top) * psdLayer.Rect.Width - + (rect.Left - psdLayer.Rect.Left); - int idxSrcByte = idxSrcPixel * decodeContext.ByteDepth; - - // Calculate pointers to destination Surface. - //var pDestRow = surface.GetRowAddress(y); - //var pDestStart = pDestRow + decodeContext.Rectangle.Left; - //var pDestEnd = pDestRow + decodeContext.Rectangle.Right; - var pDestStart = y * surface.width + decodeContext.Rectangle.Left; - var pDestEnd = y * surface.width + decodeContext.Rectangle.Right; - - // For 16-bit images, take the higher-order byte from the image - // data, which is now in little-endian order. - if (decodeContext.ByteDepth == 2) - idxSrcByte++; - - // Decode the color and alpha channels - decoder(pDestStart, pDestEnd, surface.width, surface.color, idxSrcByte, decodeContext); - } - - // Mask and Alpha. - int userMaskContextSize = decodeContext.UserMaskContext != null ? decodeContext.Rectangle.Width : 1; - int layerMaskContextSize = decodeContext.LayerMaskContext != null ? decodeContext.Rectangle.Width : 1; - var userAlphaMask = new NativeArray(userMaskContextSize, Allocator.TempJob); - var layerAlphaMask = new NativeArray(layerMaskContextSize, Allocator.TempJob); - - for (int y = rect.Top; y < rect.Bottom; y++) - { - // Calculate index into ImageData source from row and column. - int idxSrcPixel = (y - psdLayer.Rect.Top) * psdLayer.Rect.Width + (rect.Left - psdLayer.Rect.Left); - int idxSrcByte = idxSrcPixel * decodeContext.ByteDepth; - - // Calculate pointers to destination Surface. - //var pDestRow = surface.GetRowAddress(y); - //var pDestStart = pDestRow + decodeContext.Rectangle.Left; - //var pDestEnd = pDestRow + decodeContext.Rectangle.Right; - var pDestStart = y * surface.width + decodeContext.Rectangle.Left; - var pDestEnd = y * surface.width + decodeContext.Rectangle.Right; - - // For 16-bit images, take the higher-order byte from the image - // data, which is now in little-endian order. - if (decodeContext.ByteDepth == 2) - idxSrcByte++; - - // Decode the color and alpha channels - SetPDNAlphaRow(pDestStart, pDestEnd, surface.width, surface.color, idxSrcByte, decodeContext.ByteDepth, decodeContext.HasAlphaChannel, decodeContext.AlphaChannel); - // Apply layer masks(s) to the alpha channel - GetMaskAlphaRow(y, decodeContext, decodeContext.LayerMaskContext, ref layerAlphaMask); - GetMaskAlphaRow(y, decodeContext, decodeContext.UserMaskContext, ref userAlphaMask); - ApplyPDNMask(pDestStart, pDestEnd, surface.width, surface.color, layerAlphaMask, userAlphaMask); - } - userAlphaMask.Dispose(); - layerAlphaMask.Dispose(); - } - - private static unsafe void GetMaskAlphaRow(int y, DecodeContext layerContext, MaskDecodeContext maskContext, ref NativeArray alphaBuffer) - { - if (maskContext == null) - return; - var mask = maskContext.Mask; - - // Background color for areas not covered by the mask - byte backgroundColor = mask.InvertOnBlend - ? (byte)(255 - mask.BackgroundColor) - : mask.BackgroundColor; - { - var alphaBufferPtr = NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(alphaBuffer); - UnsafeUtility.MemSet(alphaBufferPtr, backgroundColor, alphaBuffer.Length); - } - if (maskContext.IsRowEmpty(y)) - { - return; - } - - ////////////////////////////////////// - // Transfer mask into the alpha array - var pMaskData = mask.ImageData; - { - // Get pointers to starting positions - int alphaColumn = maskContext.Rectangle.X - layerContext.Rectangle.X; - var pAlpha = alphaColumn; - var pAlphaEnd = pAlpha + maskContext.Rectangle.Width; - - int maskRow = y - mask.Rect.Y; - int maskColumn = maskContext.Rectangle.X - mask.Rect.X; - int idxMaskPixel = (maskRow * mask.Rect.Width) + maskColumn; - var pMask = idxMaskPixel * layerContext.ByteDepth; - - // Take the high-order byte if values are 16-bit (little-endian) - if (layerContext.ByteDepth == 2) - pMask++; - - // Decode mask into the alpha array. - if (layerContext.ByteDepth == 4) - { - DecodeMaskAlphaRow32(alphaBuffer, pAlpha, pAlphaEnd, pMaskData, pMask); - } - else - { - DecodeMaskAlphaRow(alphaBuffer, pAlpha, pAlphaEnd, pMaskData, pMask, layerContext.ByteDepth); - } - - // Obsolete since Photoshop CS6, but retained for compatibility with - // older versions. Note that the background has already been inverted. - if (mask.InvertOnBlend) - { - Util.Invert(alphaBuffer, pAlpha, pAlphaEnd); - } - } - } - - private static void SetPDNAlphaRow(int pDestStart, int pDestEnd, int width, NativeArray color, int idxSrc, int byteDepth, int hasAlphaChannel, NativeArray alphaChannel) - { - // Set alpha to fully-opaque if there is no alpha channel - if (0 == hasAlphaChannel) - { - var pDest = pDestStart; - while (pDest < pDestEnd) - { - var c = color[pDest]; - c.a = 255; - color[pDest] = c; - pDest++; - } - } - // Set the alpha channel data - else - { - NativeArray srcAlphaChannel = alphaChannel.Reinterpret(1); - { - var pDest = pDestStart; - while (pDest < pDestEnd) - { - var c = color[pDest]; - c.a = (byteDepth < 4) ? alphaChannel[idxSrc] : RGBByteFromHDRFloat(srcAlphaChannel[idxSrc / 4]); - - color[pDest] = c; - pDest++; - idxSrc += byteDepth; - } - } - } - } - - private static void DecodeMaskAlphaRow32(NativeArray pAlpha, int pAlphaStart, int pAlphaEnd, NativeArray pMask, int pMaskStart) - { - - NativeArray floatArray = pMask.Reinterpret(1); - - while (pAlphaStart < pAlphaEnd) - { - pAlpha[pAlphaStart] = RGBByteFromHDRFloat(floatArray[pMaskStart * 4]); - - pAlphaStart++; - pMaskStart += 4; - } - } - - private static void DecodeMaskAlphaRow(NativeArray pAlpha, int pAlphaStart, int pAlphaEnd, NativeArray pMask, int pMaskStart, int byteDepth) - { - while (pAlphaStart < pAlphaEnd) - { - pAlpha[pAlphaStart] = pMask[pMaskStart]; - - pAlphaStart++; - pMaskStart += byteDepth; - } - } - - private static void ApplyPDNMask(int pDestStart, int pDestEnd, int width, NativeArray color, NativeArray layerMaskAlpha, NativeArray userMaskAlpha) - { - // Do nothing if there are no masks - if ((layerMaskAlpha.Length <= 1) && (userMaskAlpha.Length <= 1)) - { - return; - } - // Apply one mask - else if ((layerMaskAlpha.Length <= 1) || (userMaskAlpha.Length <= 1)) - { - var maskAlpha = (layerMaskAlpha.Length <= 1) ? userMaskAlpha : layerMaskAlpha; - var maskStart = 0; - { - while (pDestStart < pDestEnd) - { - var c = color[pDestStart]; - c.a = (byte)(color[pDestStart].a * maskAlpha[maskStart] / 255); - color[pDestStart] = c; - pDestStart++; - maskStart++; - } - } - } - // Apply both masks in one pass, to minimize rounding error - else - { - //fixed (byte* pLayerMaskAlpha = &layerMaskAlpha[0], - // pUserMaskAlpha = &userMaskAlpha[0]) - { - var maskStart = 0; - while (pDestStart < pDestEnd) - { - var alphaFactor = (layerMaskAlpha[maskStart]) * (userMaskAlpha[maskStart]); - var c = color[pDestStart]; - c.a = (byte)(color[pDestStart].a * alphaFactor / 65025); - color[pDestStart] = c; - - pDestStart++; - maskStart++; - } - } - } - } - - /////////////////////////////////////////////////////////////////////////// - - #region Decode 32-bit HDR channels - - private static void SetPDNRowRgb32(int pDestStart, int pDestEnd, int width, NativeArray color, int idxSrc, DecodeContext context) - { - NativeArray redChannel = context.Channels[0].ImageData.Reinterpret(1); - NativeArray greenChannel = context.Channels[1].ImageData.Reinterpret(1); - NativeArray blueChannel = context.Channels[2].ImageData.Reinterpret(1); - - { - while (pDestStart < pDestEnd) - { - var c = color[pDestStart]; - c.r = RGBByteFromHDRFloat(redChannel[idxSrc / 4]); - c.g = RGBByteFromHDRFloat(greenChannel[idxSrc / 4]); - c.b = RGBByteFromHDRFloat(blueChannel[idxSrc / 4]); - color[pDestStart] = c; - pDestStart++; - idxSrc += 4; - } - } - } - - private static void SetPDNRowGrayscale32(int pDestStart, int pDestEnd, int width, NativeArray color, int idxSrc, DecodeContext context) - { - NativeArray channel = context.Channels[0].ImageData.Reinterpret(1); - { - while (pDestStart < pDestEnd) - { - byte rgbValue = RGBByteFromHDRFloat(channel[idxSrc / 4]); - var c = color[pDestStart]; - c.r = rgbValue; - c.g = rgbValue; - c.b = rgbValue; - color[pDestStart] = c; - - pDestStart++; - idxSrc += 4; - } - } - } - - #endregion - - /////////////////////////////////////////////////////////////////////////// - - #region Decode 8-bit and 16-bit channels - - private static void SetPDNRowRgb(int pDestStart, int pDestEnd, int width, NativeArray color, int idxSrc, DecodeContext context) - { - while (pDestStart < pDestEnd) - { - var c = color[pDestStart]; - c.r = context.Channels[0].ImageData[idxSrc]; - c.g = context.Channels[1].ImageData[idxSrc]; - c.b = context.Channels[2].ImageData[idxSrc]; - color[pDestStart] = c; - - pDestStart++; - idxSrc += context.ByteDepth; - } - } - - /////////////////////////////////////////////////////////////////////////////// - // - // The color-conversion formulas come from the Colour Space Conversions FAQ: - // http://www.poynton.com/PDFs/coloureq.pdf - // - // RGB --> CMYK CMYK --> RGB - // --------------------------------------- -------------------------------------------- - // Black = minimum(1-Red,1-Green,1-Blue) Red = 1-minimum(1,Cyan*(1-Black)+Black) - // Cyan = (1-Red-Black)/(1-Black) Green = 1-minimum(1,Magenta*(1-Black)+Black) - // Magenta = (1-Green-Black)/(1-Black) Blue = 1-minimum(1,Yellow*(1-Black)+Black) - // Yellow = (1-Blue-Black)/(1-Black) - // - /////////////////////////////////////////////////////////////////////////////// - - private static void SetPDNRowCmyk(int pDestStart, int pDestEnd, int width, NativeArray color, int idxSrc, DecodeContext context) - { - while (pDestStart < pDestEnd) - { - // CMYK values are stored as complements, presumably to allow for some - // measure of compatibility with RGB-only applications. - var C = 255 - context.Channels[0].ImageData[idxSrc]; - var M = 255 - context.Channels[1].ImageData[idxSrc]; - var Y = 255 - context.Channels[2].ImageData[idxSrc]; - var K = 255 - context.Channels[3].ImageData[idxSrc]; - - int nRed = 255 - Math.Min(255, C * (255 - K) / 255 + K); - int nGreen = 255 - Math.Min(255, M * (255 - K) / 255 + K); - int nBlue = 255 - Math.Min(255, Y * (255 - K) / 255 + K); - - var c = color[pDestStart]; - c.r = (byte)nRed; - c.g = (byte)nGreen; - c.b = (byte)nBlue; - color[pDestStart] = c; - - pDestStart++; - idxSrc += context.ByteDepth; - } - } - - private static void SetPDNRowBitmap(int pDestStart, int pDestEnd, int width, NativeArray color, int idxSrc, DecodeContext context) - { - var bitmap = context.Channels[0].ImageData; - while (pDestStart < pDestEnd) - { - byte mask = (byte)(0x80 >> (idxSrc % 8)); - byte bwValue = (byte)(bitmap[idxSrc / 8] & mask); - bwValue = (bwValue == 0) ? (byte)255 : (byte)0; - - var c = color[pDestStart]; - c.r = bwValue; - c.g = bwValue; - c.b = bwValue; - color[pDestStart] = c; - - pDestStart++; - idxSrc += context.ByteDepth; - } - } - - private static void SetPDNRowGrayscale(int pDestStart, int pDestEnd, int width, NativeArray color, int idxSrc, DecodeContext context) - { - while (pDestStart < pDestEnd) - { - var level = context.Channels[0].ImageData[idxSrc]; - var c = color[pDestStart]; - c.r = level; - c.g = level; - c.b = level; - color[pDestStart] = c; - - pDestStart++; - idxSrc += context.ByteDepth; - } - } - - private static void SetPDNRowIndexed(int pDestStart, int pDestEnd, int width, NativeArray color, int idxSrc, DecodeContext context) - { - while (pDestStart < pDestEnd) - { - int index = (int)context.Channels[0].ImageData[idxSrc]; - var c = color[pDestStart]; - c.r = (byte)context.ColorModeData[index]; - c.g = context.ColorModeData[index + 256]; - c.b = context.ColorModeData[index + 2 * 256]; - color[pDestStart] = c; - - pDestStart++; - idxSrc += context.ByteDepth; - } - } - - private static void SetPDNRowLab(int pDestStart, int pDestEnd, int width, NativeArray color, int idxSrc, DecodeContext context) - { - while (pDestStart < pDestEnd) - { - double exL, exA, exB; - exL = (double)context.Channels[0].ImageData[idxSrc]; - exA = (double)context.Channels[1].ImageData[idxSrc]; - exB = (double)context.Channels[2].ImageData[idxSrc]; - - int L = (int)(exL / 2.55); - int a = (int)(exA - 127.5); - int b = (int)(exB - 127.5); - - // First, convert from Lab to XYZ. - // Standards used Observer = 2, Illuminant = D65 - - const double ref_X = 95.047; - const double ref_Y = 100.000; - const double ref_Z = 108.883; - - double var_Y = ((double)L + 16.0) / 116.0; - double var_X = (double)a / 500.0 + var_Y; - double var_Z = var_Y - (double)b / 200.0; - - double var_X3 = var_X * var_X * var_X; - double var_Y3 = var_Y * var_Y * var_Y; - double var_Z3 = var_Z * var_Z * var_Z; - - if (var_Y3 > 0.008856) - var_Y = var_Y3; - else - var_Y = (var_Y - 16 / 116) / 7.787; - - if (var_X3 > 0.008856) - var_X = var_X3; - else - var_X = (var_X - 16 / 116) / 7.787; - - if (var_Z3 > 0.008856) - var_Z = var_Z3; - else - var_Z = (var_Z - 16 / 116) / 7.787; - - double X = ref_X * var_X; - double Y = ref_Y * var_Y; - double Z = ref_Z * var_Z; - - // Then, convert from XYZ to RGB. - // Standards used Observer = 2, Illuminant = D65 - // ref_X = 95.047, ref_Y = 100.000, ref_Z = 108.883 - - double var_R = X * 0.032406 + Y * (-0.015372) + Z * (-0.004986); - double var_G = X * (-0.009689) + Y * 0.018758 + Z * 0.000415; - double var_B = X * 0.000557 + Y * (-0.002040) + Z * 0.010570; - - if (var_R > 0.0031308) - var_R = 1.055 * (Math.Pow(var_R, 1 / 2.4)) - 0.055; - else - var_R = 12.92 * var_R; - - if (var_G > 0.0031308) - var_G = 1.055 * (Math.Pow(var_G, 1 / 2.4)) - 0.055; - else - var_G = 12.92 * var_G; - - if (var_B > 0.0031308) - var_B = 1.055 * (Math.Pow(var_B, 1 / 2.4)) - 0.055; - else - var_B = 12.92 * var_B; - - int nRed = (int)(var_R * 256.0); - int nGreen = (int)(var_G * 256.0); - int nBlue = (int)(var_B * 256.0); - - if (nRed < 0) - nRed = 0; - else if (nRed > 255) - nRed = 255; - if (nGreen < 0) - nGreen = 0; - else if (nGreen > 255) - nGreen = 255; - if (nBlue < 0) - nBlue = 0; - else if (nBlue > 255) - nBlue = 255; - - var c = color[pDestStart]; - c.r = (byte)nRed; - c.g = (byte)nGreen; - c.b = (byte)nBlue; - color[pDestStart] = c; - - pDestStart++; - idxSrc += context.ByteDepth; - } - } - - #endregion - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2014 Tao Yue +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using PaintDotNet; + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using PDNWrapper; +using System.Text; + +using PhotoshopFile; +using Unity.Collections; +using Unity.Collections.LowLevel.Unsafe; +using UnityEngine; +using Debug = UnityEngine.Debug; +using Unity.Jobs; + +namespace PaintDotNet.Data.PhotoshopFileType +{ + + internal enum DecodeType + { + RGB32 = 0, + Grayscale32 = 1, + RGB = 2, + CMYK = 3, + Bitmap = 4, + Grayscale = 5, + Indexed = 6, + Lab = 7 + }; + + internal static class ImageDecoderPdn + { + private static double rgbExponent = 1 / 2.19921875; + + private class DecodeContext + { + public PhotoshopFile.Layer Layer { get; private set; } + public int ByteDepth { get; private set; } + public int HasAlphaChannel { get; private set; } + public Channel[] Channels { get; private set; } + public NativeArray AlphaChannel { get; private set; } + public PsdColorMode ColorMode { get; private set; } + public NativeArray ColorModeData { get; private set; } + + public Rectangle Rectangle { get; private set; } + public MaskDecodeContext LayerMaskContext { get; private set; } + public MaskDecodeContext UserMaskContext { get; private set; } + + public DecodeContext(PhotoshopFile.Layer layer, Rectangle bounds) + { + Layer = layer; + ByteDepth = Util.BytesFromBitDepth(layer.PsdFile.BitDepth); + HasAlphaChannel = 0; + Channels = layer.Channels.ToIdArray(); + + var alphaSize = 4; + if (layer.AlphaChannel != null && layer.AlphaChannel.ImageData.Length > 0) + { + HasAlphaChannel = 1; + alphaSize = layer.AlphaChannel.ImageData.Length; + alphaSize = (alphaSize / 4) + (alphaSize % 4 > 0 ? 1 : 0); + alphaSize = alphaSize * 4; + } + AlphaChannel = new NativeArray(alphaSize, Allocator.TempJob); + if (HasAlphaChannel > 0) + NativeArray.Copy(layer.AlphaChannel.ImageData, AlphaChannel, layer.AlphaChannel.ImageData.Length); + ColorMode = layer.PsdFile.ColorMode; + ColorModeData = new NativeArray(layer.PsdFile.ColorModeData, Allocator.TempJob); + + // Clip the layer to the specified bounds + Rectangle = Layer.Rect.IntersectWith(bounds); + + if (layer.Masks != null) + { + LayerMaskContext = GetMaskContext(layer.Masks.LayerMask); + UserMaskContext = GetMaskContext(layer.Masks.UserMask); + } + } + + internal void Cleanup() + { + AlphaChannel.Dispose(); + ColorModeData.Dispose(); + } + + private MaskDecodeContext GetMaskContext(Mask mask) + { + if ((mask == null) || (mask.Disabled)) + { + return null; + } + + return new MaskDecodeContext(mask, this); + } + } + + private class MaskDecodeContext + { + public Mask Mask { get; private set; } + public Rectangle Rectangle { get; private set; } + public MaskDecodeContext(Mask mask, DecodeContext layerContext) + { + Mask = mask; + + // The PositionVsLayer flag is documented to indicate a position + // relative to the layer, but Photoshop treats the position as + // absolute. So that's what we do, too. + Rectangle = mask.Rect.IntersectWith(layerContext.Rectangle); + } + + public bool IsRowEmpty(int row) + { + return (Mask.ImageData == null) + || (Mask.ImageData.Length == 0) + || (Rectangle.Size.IsEmpty) + || (row < Rectangle.Top) + || (row >= Rectangle.Bottom); + } + } + + /////////////////////////////////////////////////////////////////////////////// + + internal static byte RGBByteFromHDRFloat(float ptr) + { + var result = (byte)(255 * Math.Pow(ptr, rgbExponent)); + return result; + } + + private static DecodeDelegate GetDecodeDelegate(PsdColorMode psdColorMode, ref DecodeType decoderType) + { + switch (psdColorMode) + { + case PsdColorMode.Bitmap: + decoderType = DecodeType.Bitmap; + return SetPDNRowBitmap; + case PsdColorMode.Grayscale: + case PsdColorMode.Duotone: + decoderType = DecodeType.Grayscale; + return SetPDNRowGrayscale; + case PsdColorMode.Indexed: + decoderType = DecodeType.Indexed; + return SetPDNRowIndexed; + case PsdColorMode.RGB: + decoderType = DecodeType.RGB; + return SetPDNRowRgb; + case PsdColorMode.CMYK: + decoderType = DecodeType.CMYK; + return SetPDNRowCmyk; + case PsdColorMode.Lab: + decoderType = DecodeType.Lab; + return SetPDNRowLab; + case PsdColorMode.Multichannel: + throw new Exception("Cannot decode multichannel."); + default: + throw new Exception("Unknown color mode."); + } + } + + private static DecodeDelegate GetDecodeDelegate32(PsdColorMode psdColorMode, ref DecodeType decoderType) + { + switch (psdColorMode) + { + case PsdColorMode.Grayscale: + decoderType = DecodeType.Grayscale32; + return SetPDNRowGrayscale32; + case PsdColorMode.RGB: + decoderType = DecodeType.RGB32; + return SetPDNRowRgb32; + default: + throw new PsdInvalidException( + "32-bit HDR images must be either RGB or grayscale."); + } + } + + /// + /// Decode image from Photoshop's channel-separated formats to BGRA. + /// + public static JobHandle DecodeImage(BitmapLayer pdnLayer, PhotoshopFile.Layer psdLayer, JobHandle inputDeps) + { + UnityEngine.Profiling.Profiler.BeginSample("DecodeImage"); + var decodeContext = new DecodeContext(psdLayer, pdnLayer.Bounds); + DecodeDelegate decoder = null; + DecodeType decoderType = 0; + + if (decodeContext.ByteDepth == 4) + decoder = GetDecodeDelegate32(decodeContext.ColorMode, ref decoderType); + else + decoder = GetDecodeDelegate(decodeContext.ColorMode, ref decoderType); + + JobHandle jobHandle = DecodeImage(pdnLayer, decodeContext, decoderType, inputDeps); + UnityEngine.Profiling.Profiler.EndSample(); + return jobHandle; + } + + /// + /// Decode image from Photoshop's channel-separated formats to BGRA, + /// using the specified decode delegate on each row. + /// + private static JobHandle DecodeImage(BitmapLayer pdnLayer, DecodeContext decodeContext, DecodeType decoderType, JobHandle inputDeps) + { + + var psdLayer = decodeContext.Layer; + var surface = pdnLayer.Surface; + var rect = decodeContext.Rectangle; + + // Convert rows from the Photoshop representation, writing the + // resulting ARGB values to to the Paint.NET Surface. + + int jobCount = Unity.Jobs.LowLevel.Unsafe.JobsUtility.JobWorkerMaximumCount; + int execCount = (rect.Bottom - rect.Top); + int sliceCount = execCount / jobCount; + PDNDecoderJob decoderJob = new PDNDecoderJob(); + + decoderJob.Data.Rect = rect; + decoderJob.Data.LayerRect = psdLayer.Rect; + decoderJob.Data.ClippedRect = rect; + decoderJob.Data.SurfaceWidth = surface.width; + decoderJob.Data.SurfaceHeight = surface.height; + decoderJob.Data.SurfaceByteDepth = decodeContext.ByteDepth; + decoderJob.Data.DecoderType = decoderType; + + decoderJob.Data.ColorChannel0 = decodeContext.Channels[0].ImageData; + decoderJob.Data.ColorChannel1 = decodeContext.Channels.Length > 1 ? decodeContext.Channels[1].ImageData : decodeContext.Channels[0].ImageData; + decoderJob.Data.ColorChannel2 = decodeContext.Channels.Length > 2 ? decodeContext.Channels[2].ImageData : decodeContext.Channels[0].ImageData; + decoderJob.Data.ColorChannel3 = decodeContext.Channels.Length > 3 ? decodeContext.Channels[3].ImageData : decodeContext.Channels[0].ImageData; + decoderJob.Data.ColorModeData = decodeContext.ColorModeData; + decoderJob.Data.DecodedImage = surface.color; + + // Schedule the job, returns the JobHandle which can be waited upon later on + JobHandle jobHandle = decoderJob.Schedule(execCount, sliceCount, inputDeps); + + // Mask and Alpha. + int userMaskContextSize = decodeContext.UserMaskContext != null ? decodeContext.Rectangle.Width : 1; + int layerMaskContextSize = decodeContext.LayerMaskContext != null ? decodeContext.Rectangle.Width : 1; + var userAlphaMask = new NativeArray(userMaskContextSize, Allocator.TempJob); + var layerAlphaMask = new NativeArray(layerMaskContextSize, Allocator.TempJob); + var userAlphaMaskEmpty = new NativeArray(rect.Bottom, Allocator.TempJob); + var layerAlphaMaskEmpty = new NativeArray(rect.Bottom, Allocator.TempJob); + + PDNAlphaMaskJob alphaMaskJob = new PDNAlphaMaskJob(); + + for (int y = rect.Top; y < rect.Bottom; ++y) + { + if (decodeContext.UserMaskContext != null) + userAlphaMaskEmpty[y] = decodeContext.UserMaskContext.IsRowEmpty(y) ? (byte)1 : (byte)0; + if (decodeContext.LayerMaskContext != null) + layerAlphaMaskEmpty[y] = decodeContext.LayerMaskContext.IsRowEmpty(y) ? (byte)1 : (byte)0; + } + + alphaMaskJob.Data.Rect = rect; + alphaMaskJob.Data.LayerRect = psdLayer.Rect; + alphaMaskJob.Data.ClippedRect = rect; + alphaMaskJob.Data.SurfaceWidth = surface.width; + alphaMaskJob.Data.SurfaceHeight = surface.height; + alphaMaskJob.Data.SurfaceByteDepth = decodeContext.ByteDepth; + alphaMaskJob.Data.HasAlphaChannel = decodeContext.HasAlphaChannel; + + alphaMaskJob.Data.HasUserAlphaMask = decodeContext.UserMaskContext != null ? 1 : 0; + alphaMaskJob.Data.UserMaskInvertOnBlend = decodeContext.UserMaskContext != null ? (decodeContext.UserMaskContext.Mask.InvertOnBlend ? 1 : 0) : 0; + alphaMaskJob.Data.UserMaskRect = decodeContext.UserMaskContext != null ? decodeContext.UserMaskContext.Mask.Rect : rect; + alphaMaskJob.Data.UserMaskContextRect = decodeContext.UserMaskContext != null ? decodeContext.UserMaskContext.Rectangle : rect; + alphaMaskJob.Data.HasLayerAlphaMask = decodeContext.LayerMaskContext != null ? 1 : 0; + alphaMaskJob.Data.LayerMaskInvertOnBlend = decodeContext.LayerMaskContext != null ? (decodeContext.LayerMaskContext.Mask.InvertOnBlend ? 1 : 0) : 0; + alphaMaskJob.Data.LayerMaskRect = decodeContext.LayerMaskContext != null ? decodeContext.LayerMaskContext.Mask.Rect : rect; + alphaMaskJob.Data.LayerMaskContextRect = decodeContext.LayerMaskContext != null ? decodeContext.LayerMaskContext.Rectangle : rect; + + alphaMaskJob.Data.AlphaChannel0 = decodeContext.AlphaChannel; + alphaMaskJob.Data.UserMask = decodeContext.UserMaskContext != null ? decodeContext.UserMaskContext.Mask.ImageData : decodeContext.AlphaChannel; + alphaMaskJob.Data.UserAlphaMask = userAlphaMask; + alphaMaskJob.Data.UserAlphaMaskEmpty = userAlphaMaskEmpty; + alphaMaskJob.Data.LayerMask = decodeContext.LayerMaskContext != null ? decodeContext.LayerMaskContext.Mask.ImageData : decodeContext.AlphaChannel; + alphaMaskJob.Data.LayerAlphaMask = layerAlphaMask; + alphaMaskJob.Data.LayerAlphaMaskEmpty = layerAlphaMaskEmpty; + alphaMaskJob.Data.DecodedImage = surface.color; + alphaMaskJob.Data.UserMaskBackgroundColor = decodeContext.UserMaskContext != null ? decodeContext.UserMaskContext.Mask.BackgroundColor : (byte)0; + alphaMaskJob.Data.LayerMaskBackgroundColor = decodeContext.LayerMaskContext != null ? decodeContext.LayerMaskContext.Mask.BackgroundColor : (byte)0; + + jobHandle = alphaMaskJob.Schedule(jobHandle); + return jobHandle; + + } + + /////////////////////////////////////////////////////////////////////////// + /// SINGLE THREADED - KEPT FOR REFERENCE + /////////////////////////////////////////////////////////////////////////// + + /// + /// Decode image from Photoshop's channel-separated formats to BGRA. + /// + public static void DecodeImage(BitmapLayer pdnLayer, PhotoshopFile.Layer psdLayer) + { + UnityEngine.Profiling.Profiler.BeginSample("DecodeImage"); + var decodeContext = new DecodeContext(psdLayer, pdnLayer.Bounds); + DecodeDelegate decoder = null; + DecodeType decoderType = 0; + + if (decodeContext.ByteDepth == 4) + decoder = GetDecodeDelegate32(decodeContext.ColorMode, ref decoderType); + else + decoder = GetDecodeDelegate(decodeContext.ColorMode, ref decoderType); + + DecodeImage(pdnLayer, decodeContext, decoder); + decodeContext.Cleanup(); + UnityEngine.Profiling.Profiler.EndSample(); + } + + private delegate void DecodeDelegate(int pDestStart, int pDestEnd, int width, NativeArray color, int idxSrc, DecodeContext context); + + /// + /// Decode image from Photoshop's channel-separated formats to BGRA, + /// using the specified decode delegate on each row. + /// + private static void DecodeImage(BitmapLayer pdnLayer, DecodeContext decodeContext, DecodeDelegate decoder) + { + + var psdLayer = decodeContext.Layer; + var surface = pdnLayer.Surface; + var rect = decodeContext.Rectangle; + + // Convert rows from the Photoshop representation, writing the + // resulting ARGB values to to the Paint.NET Surface. + for (int y = rect.Top; y < rect.Bottom; y++) + { + // Calculate index into ImageData source from row and column. + int idxSrcPixel = (y - psdLayer.Rect.Top) * psdLayer.Rect.Width + + (rect.Left - psdLayer.Rect.Left); + int idxSrcByte = idxSrcPixel * decodeContext.ByteDepth; + + // Calculate pointers to destination Surface. + //var pDestRow = surface.GetRowAddress(y); + //var pDestStart = pDestRow + decodeContext.Rectangle.Left; + //var pDestEnd = pDestRow + decodeContext.Rectangle.Right; + var pDestStart = y * surface.width + decodeContext.Rectangle.Left; + var pDestEnd = y * surface.width + decodeContext.Rectangle.Right; + + // For 16-bit images, take the higher-order byte from the image + // data, which is now in little-endian order. + if (decodeContext.ByteDepth == 2) + idxSrcByte++; + + // Decode the color and alpha channels + decoder(pDestStart, pDestEnd, surface.width, surface.color, idxSrcByte, decodeContext); + } + + // Mask and Alpha. + int userMaskContextSize = decodeContext.UserMaskContext != null ? decodeContext.Rectangle.Width : 1; + int layerMaskContextSize = decodeContext.LayerMaskContext != null ? decodeContext.Rectangle.Width : 1; + var userAlphaMask = new NativeArray(userMaskContextSize, Allocator.TempJob); + var layerAlphaMask = new NativeArray(layerMaskContextSize, Allocator.TempJob); + + for (int y = rect.Top; y < rect.Bottom; y++) + { + // Calculate index into ImageData source from row and column. + int idxSrcPixel = (y - psdLayer.Rect.Top) * psdLayer.Rect.Width + (rect.Left - psdLayer.Rect.Left); + int idxSrcByte = idxSrcPixel * decodeContext.ByteDepth; + + // Calculate pointers to destination Surface. + //var pDestRow = surface.GetRowAddress(y); + //var pDestStart = pDestRow + decodeContext.Rectangle.Left; + //var pDestEnd = pDestRow + decodeContext.Rectangle.Right; + var pDestStart = y * surface.width + decodeContext.Rectangle.Left; + var pDestEnd = y * surface.width + decodeContext.Rectangle.Right; + + // For 16-bit images, take the higher-order byte from the image + // data, which is now in little-endian order. + if (decodeContext.ByteDepth == 2) + idxSrcByte++; + + // Decode the color and alpha channels + SetPDNAlphaRow(pDestStart, pDestEnd, surface.width, surface.color, idxSrcByte, decodeContext.ByteDepth, decodeContext.HasAlphaChannel, decodeContext.AlphaChannel); + // Apply layer masks(s) to the alpha channel + GetMaskAlphaRow(y, decodeContext, decodeContext.LayerMaskContext, ref layerAlphaMask); + GetMaskAlphaRow(y, decodeContext, decodeContext.UserMaskContext, ref userAlphaMask); + ApplyPDNMask(pDestStart, pDestEnd, surface.width, surface.color, layerAlphaMask, userAlphaMask); + } + userAlphaMask.Dispose(); + layerAlphaMask.Dispose(); + } + + private static unsafe void GetMaskAlphaRow(int y, DecodeContext layerContext, MaskDecodeContext maskContext, ref NativeArray alphaBuffer) + { + if (maskContext == null) + return; + var mask = maskContext.Mask; + + // Background color for areas not covered by the mask + byte backgroundColor = mask.InvertOnBlend + ? (byte)(255 - mask.BackgroundColor) + : mask.BackgroundColor; + { + var alphaBufferPtr = NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(alphaBuffer); + UnsafeUtility.MemSet(alphaBufferPtr, backgroundColor, alphaBuffer.Length); + } + if (maskContext.IsRowEmpty(y)) + { + return; + } + + ////////////////////////////////////// + // Transfer mask into the alpha array + var pMaskData = mask.ImageData; + { + // Get pointers to starting positions + int alphaColumn = maskContext.Rectangle.X - layerContext.Rectangle.X; + var pAlpha = alphaColumn; + var pAlphaEnd = pAlpha + maskContext.Rectangle.Width; + + int maskRow = y - mask.Rect.Y; + int maskColumn = maskContext.Rectangle.X - mask.Rect.X; + int idxMaskPixel = (maskRow * mask.Rect.Width) + maskColumn; + var pMask = idxMaskPixel * layerContext.ByteDepth; + + // Take the high-order byte if values are 16-bit (little-endian) + if (layerContext.ByteDepth == 2) + pMask++; + + // Decode mask into the alpha array. + if (layerContext.ByteDepth == 4) + { + DecodeMaskAlphaRow32(alphaBuffer, pAlpha, pAlphaEnd, pMaskData, pMask); + } + else + { + DecodeMaskAlphaRow(alphaBuffer, pAlpha, pAlphaEnd, pMaskData, pMask, layerContext.ByteDepth); + } + + // Obsolete since Photoshop CS6, but retained for compatibility with + // older versions. Note that the background has already been inverted. + if (mask.InvertOnBlend) + { + Util.Invert(alphaBuffer, pAlpha, pAlphaEnd); + } + } + } + + private static void SetPDNAlphaRow(int pDestStart, int pDestEnd, int width, NativeArray color, int idxSrc, int byteDepth, int hasAlphaChannel, NativeArray alphaChannel) + { + // Set alpha to fully-opaque if there is no alpha channel + if (0 == hasAlphaChannel) + { + var pDest = pDestStart; + while (pDest < pDestEnd) + { + var c = color[pDest]; + c.a = 255; + color[pDest] = c; + pDest++; + } + } + // Set the alpha channel data + else + { + NativeArray srcAlphaChannel = alphaChannel.Reinterpret(1); + { + var pDest = pDestStart; + while (pDest < pDestEnd) + { + var c = color[pDest]; + c.a = (byteDepth < 4) ? alphaChannel[idxSrc] : RGBByteFromHDRFloat(srcAlphaChannel[idxSrc / 4]); + + color[pDest] = c; + pDest++; + idxSrc += byteDepth; + } + } + } + } + + private static void DecodeMaskAlphaRow32(NativeArray pAlpha, int pAlphaStart, int pAlphaEnd, NativeArray pMask, int pMaskStart) + { + + NativeArray floatArray = pMask.Reinterpret(1); + + while (pAlphaStart < pAlphaEnd) + { + pAlpha[pAlphaStart] = RGBByteFromHDRFloat(floatArray[pMaskStart * 4]); + + pAlphaStart++; + pMaskStart += 4; + } + } + + private static void DecodeMaskAlphaRow(NativeArray pAlpha, int pAlphaStart, int pAlphaEnd, NativeArray pMask, int pMaskStart, int byteDepth) + { + while (pAlphaStart < pAlphaEnd) + { + pAlpha[pAlphaStart] = pMask[pMaskStart]; + + pAlphaStart++; + pMaskStart += byteDepth; + } + } + + private static void ApplyPDNMask(int pDestStart, int pDestEnd, int width, NativeArray color, NativeArray layerMaskAlpha, NativeArray userMaskAlpha) + { + // Do nothing if there are no masks + if ((layerMaskAlpha.Length <= 1) && (userMaskAlpha.Length <= 1)) + { + return; + } + // Apply one mask + else if ((layerMaskAlpha.Length <= 1) || (userMaskAlpha.Length <= 1)) + { + var maskAlpha = (layerMaskAlpha.Length <= 1) ? userMaskAlpha : layerMaskAlpha; + var maskStart = 0; + { + while (pDestStart < pDestEnd) + { + var c = color[pDestStart]; + c.a = (byte)(color[pDestStart].a * maskAlpha[maskStart] / 255); + color[pDestStart] = c; + pDestStart++; + maskStart++; + } + } + } + // Apply both masks in one pass, to minimize rounding error + else + { + //fixed (byte* pLayerMaskAlpha = &layerMaskAlpha[0], + // pUserMaskAlpha = &userMaskAlpha[0]) + { + var maskStart = 0; + while (pDestStart < pDestEnd) + { + var alphaFactor = (layerMaskAlpha[maskStart]) * (userMaskAlpha[maskStart]); + var c = color[pDestStart]; + c.a = (byte)(color[pDestStart].a * alphaFactor / 65025); + color[pDestStart] = c; + + pDestStart++; + maskStart++; + } + } + } + } + + /////////////////////////////////////////////////////////////////////////// + + #region Decode 32-bit HDR channels + + private static void SetPDNRowRgb32(int pDestStart, int pDestEnd, int width, NativeArray color, int idxSrc, DecodeContext context) + { + NativeArray redChannel = context.Channels[0].ImageData.Reinterpret(1); + NativeArray greenChannel = context.Channels[1].ImageData.Reinterpret(1); + NativeArray blueChannel = context.Channels[2].ImageData.Reinterpret(1); + + { + while (pDestStart < pDestEnd) + { + var c = color[pDestStart]; + c.r = RGBByteFromHDRFloat(redChannel[idxSrc / 4]); + c.g = RGBByteFromHDRFloat(greenChannel[idxSrc / 4]); + c.b = RGBByteFromHDRFloat(blueChannel[idxSrc / 4]); + color[pDestStart] = c; + pDestStart++; + idxSrc += 4; + } + } + } + + private static void SetPDNRowGrayscale32(int pDestStart, int pDestEnd, int width, NativeArray color, int idxSrc, DecodeContext context) + { + NativeArray channel = context.Channels[0].ImageData.Reinterpret(1); + { + while (pDestStart < pDestEnd) + { + byte rgbValue = RGBByteFromHDRFloat(channel[idxSrc / 4]); + var c = color[pDestStart]; + c.r = rgbValue; + c.g = rgbValue; + c.b = rgbValue; + color[pDestStart] = c; + + pDestStart++; + idxSrc += 4; + } + } + } + + #endregion + + /////////////////////////////////////////////////////////////////////////// + + #region Decode 8-bit and 16-bit channels + + private static void SetPDNRowRgb(int pDestStart, int pDestEnd, int width, NativeArray color, int idxSrc, DecodeContext context) + { + while (pDestStart < pDestEnd) + { + var c = color[pDestStart]; + c.r = context.Channels[0].ImageData[idxSrc]; + c.g = context.Channels[1].ImageData[idxSrc]; + c.b = context.Channels[2].ImageData[idxSrc]; + color[pDestStart] = c; + + pDestStart++; + idxSrc += context.ByteDepth; + } + } + + /////////////////////////////////////////////////////////////////////////////// + // + // The color-conversion formulas come from the Colour Space Conversions FAQ: + // http://www.poynton.com/PDFs/coloureq.pdf + // + // RGB --> CMYK CMYK --> RGB + // --------------------------------------- -------------------------------------------- + // Black = minimum(1-Red,1-Green,1-Blue) Red = 1-minimum(1,Cyan*(1-Black)+Black) + // Cyan = (1-Red-Black)/(1-Black) Green = 1-minimum(1,Magenta*(1-Black)+Black) + // Magenta = (1-Green-Black)/(1-Black) Blue = 1-minimum(1,Yellow*(1-Black)+Black) + // Yellow = (1-Blue-Black)/(1-Black) + // + /////////////////////////////////////////////////////////////////////////////// + + private static void SetPDNRowCmyk(int pDestStart, int pDestEnd, int width, NativeArray color, int idxSrc, DecodeContext context) + { + while (pDestStart < pDestEnd) + { + // CMYK values are stored as complements, presumably to allow for some + // measure of compatibility with RGB-only applications. + var C = 255 - context.Channels[0].ImageData[idxSrc]; + var M = 255 - context.Channels[1].ImageData[idxSrc]; + var Y = 255 - context.Channels[2].ImageData[idxSrc]; + var K = 255 - context.Channels[3].ImageData[idxSrc]; + + int nRed = 255 - Math.Min(255, C * (255 - K) / 255 + K); + int nGreen = 255 - Math.Min(255, M * (255 - K) / 255 + K); + int nBlue = 255 - Math.Min(255, Y * (255 - K) / 255 + K); + + var c = color[pDestStart]; + c.r = (byte)nRed; + c.g = (byte)nGreen; + c.b = (byte)nBlue; + color[pDestStart] = c; + + pDestStart++; + idxSrc += context.ByteDepth; + } + } + + private static void SetPDNRowBitmap(int pDestStart, int pDestEnd, int width, NativeArray color, int idxSrc, DecodeContext context) + { + var bitmap = context.Channels[0].ImageData; + while (pDestStart < pDestEnd) + { + byte mask = (byte)(0x80 >> (idxSrc % 8)); + byte bwValue = (byte)(bitmap[idxSrc / 8] & mask); + bwValue = (bwValue == 0) ? (byte)255 : (byte)0; + + var c = color[pDestStart]; + c.r = bwValue; + c.g = bwValue; + c.b = bwValue; + color[pDestStart] = c; + + pDestStart++; + idxSrc += context.ByteDepth; + } + } + + private static void SetPDNRowGrayscale(int pDestStart, int pDestEnd, int width, NativeArray color, int idxSrc, DecodeContext context) + { + while (pDestStart < pDestEnd) + { + var level = context.Channels[0].ImageData[idxSrc]; + var c = color[pDestStart]; + c.r = level; + c.g = level; + c.b = level; + color[pDestStart] = c; + + pDestStart++; + idxSrc += context.ByteDepth; + } + } + + private static void SetPDNRowIndexed(int pDestStart, int pDestEnd, int width, NativeArray color, int idxSrc, DecodeContext context) + { + while (pDestStart < pDestEnd) + { + int index = (int)context.Channels[0].ImageData[idxSrc]; + var c = color[pDestStart]; + c.r = (byte)context.ColorModeData[index]; + c.g = context.ColorModeData[index + 256]; + c.b = context.ColorModeData[index + 2 * 256]; + color[pDestStart] = c; + + pDestStart++; + idxSrc += context.ByteDepth; + } + } + + private static void SetPDNRowLab(int pDestStart, int pDestEnd, int width, NativeArray color, int idxSrc, DecodeContext context) + { + while (pDestStart < pDestEnd) + { + double exL, exA, exB; + exL = (double)context.Channels[0].ImageData[idxSrc]; + exA = (double)context.Channels[1].ImageData[idxSrc]; + exB = (double)context.Channels[2].ImageData[idxSrc]; + + int L = (int)(exL / 2.55); + int a = (int)(exA - 127.5); + int b = (int)(exB - 127.5); + + // First, convert from Lab to XYZ. + // Standards used Observer = 2, Illuminant = D65 + + const double ref_X = 95.047; + const double ref_Y = 100.000; + const double ref_Z = 108.883; + + double var_Y = ((double)L + 16.0) / 116.0; + double var_X = (double)a / 500.0 + var_Y; + double var_Z = var_Y - (double)b / 200.0; + + double var_X3 = var_X * var_X * var_X; + double var_Y3 = var_Y * var_Y * var_Y; + double var_Z3 = var_Z * var_Z * var_Z; + + if (var_Y3 > 0.008856) + var_Y = var_Y3; + else + var_Y = (var_Y - 16 / 116) / 7.787; + + if (var_X3 > 0.008856) + var_X = var_X3; + else + var_X = (var_X - 16 / 116) / 7.787; + + if (var_Z3 > 0.008856) + var_Z = var_Z3; + else + var_Z = (var_Z - 16 / 116) / 7.787; + + double X = ref_X * var_X; + double Y = ref_Y * var_Y; + double Z = ref_Z * var_Z; + + // Then, convert from XYZ to RGB. + // Standards used Observer = 2, Illuminant = D65 + // ref_X = 95.047, ref_Y = 100.000, ref_Z = 108.883 + + double var_R = X * 0.032406 + Y * (-0.015372) + Z * (-0.004986); + double var_G = X * (-0.009689) + Y * 0.018758 + Z * 0.000415; + double var_B = X * 0.000557 + Y * (-0.002040) + Z * 0.010570; + + if (var_R > 0.0031308) + var_R = 1.055 * (Math.Pow(var_R, 1 / 2.4)) - 0.055; + else + var_R = 12.92 * var_R; + + if (var_G > 0.0031308) + var_G = 1.055 * (Math.Pow(var_G, 1 / 2.4)) - 0.055; + else + var_G = 12.92 * var_G; + + if (var_B > 0.0031308) + var_B = 1.055 * (Math.Pow(var_B, 1 / 2.4)) - 0.055; + else + var_B = 12.92 * var_B; + + int nRed = (int)(var_R * 256.0); + int nGreen = (int)(var_G * 256.0); + int nBlue = (int)(var_B * 256.0); + + if (nRed < 0) + nRed = 0; + else if (nRed > 255) + nRed = 255; + if (nGreen < 0) + nGreen = 0; + else if (nGreen > 255) + nGreen = 255; + if (nBlue < 0) + nBlue = 0; + else if (nBlue > 255) + nBlue = 255; + + var c = color[pDestStart]; + c.r = (byte)nRed; + c.g = (byte)nGreen; + c.b = (byte)nBlue; + color[pDestStart] = c; + + pDestStart++; + idxSrc += context.ByteDepth; + } + } + + #endregion + } +} diff --git a/Editor/PSDPlugin/PhotoShopFileType/ImageDecoderPdn.cs.meta b/Editor/PSDPlugin/PhotoShopFileType/ImageDecoderPdn.cs.meta index 1346286..35d0cc1 100644 --- a/Editor/PSDPlugin/PhotoShopFileType/ImageDecoderPdn.cs.meta +++ b/Editor/PSDPlugin/PhotoShopFileType/ImageDecoderPdn.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 812b92369e1c26c4eb12b733b257bd85 -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 812b92369e1c26c4eb12b733b257bd85 +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PhotoShopFileType/PsdLoad.cs b/Editor/PSDPlugin/PhotoShopFileType/PsdLoad.cs index 7efbef9..9b93e4d 100644 --- a/Editor/PSDPlugin/PhotoShopFileType/PsdLoad.cs +++ b/Editor/PSDPlugin/PhotoShopFileType/PsdLoad.cs @@ -1,301 +1,301 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2016 Tao Yue -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; - -using PhotoshopFile; -using UnityEngine; -using PDNWrapper; -using Unity.Collections; -using Unity.Jobs; - -namespace PaintDotNet.Data.PhotoshopFileType -{ - internal static class PsdLoad - { - public static PsdFile Load(System.IO.Stream input, ELoadFlag loadFlag) - { - var loadContext = new DocumentLoadContext(); - return new PsdFile(input, loadContext, loadFlag); - } - - public static Document Load(System.IO.Stream input) - { - // Load and decompress Photoshop file structures - var loadContext = new DocumentLoadContext(); - var psdFile = new PsdFile(input, loadContext); - - // Multichannel images are loaded by processing each channel as a - // grayscale layer. - if (psdFile.ColorMode == PsdColorMode.Multichannel) - { - CreateLayersFromChannels(psdFile); - psdFile.ColorMode = PsdColorMode.Grayscale; - } - - // Convert into Paint.NET internal representation - var document = new Document(psdFile.ColumnCount, psdFile.RowCount); - - if (psdFile.Layers.Count == 0) - { - psdFile.BaseLayer.CreateMissingChannels(); - var layer = PDNWrapper.Layer.CreateBackgroundLayer(psdFile.ColumnCount, psdFile.RowCount); - ImageDecoderPdn.DecodeImage(layer, psdFile.BaseLayer); - layer.Name = String.IsNullOrEmpty(psdFile.BaseLayer.Name)? "Background" : psdFile.BaseLayer.Name; - layer.Opacity = psdFile.BaseLayer.Opacity; - layer.Visible = psdFile.BaseLayer.Visible; - layer.IsGroup = psdFile.BaseLayer.IsGroup; - layer.LayerID = psdFile.BaseLayer.LayerID; - layer.BlendMode = BlendModeMapping.FromPsdBlendMode(psdFile.BaseLayer.BlendModeKey); - document.Layers.Add(layer); - } - else - { - psdFile.VerifyLayerSections(); - ApplyLayerSections(psdFile.Layers); - - //var pdnLayers = psdFile.Layers.AsParallel().AsOrdered() - // .Select(psdLayer => psdLayer.DecodeToPdnLayer()) - // .ToList(); - //document.Layers.AddRange(pdnLayers); - /* - foreach (var l in psdFile.Layers) - { - document.Layers.Add(l.DecodeToPdnLayer()); - } - */ - BitmapLayer parent = null; - JobHandle jobHandle = default(JobHandle); - foreach (var l in Enumerable.Reverse(psdFile.Layers)) - { - if (l.IsEndGroupMarker) - { - parent = parent != null ? parent.ParentLayer : null; - continue; - } - BitmapLayer b = null; - jobHandle = l.DecodeToPdnLayer(jobHandle, out b); - b.ParentLayer = parent; - if (parent != null) - parent.ChildLayer.Add(b); - else - document.Layers.Add(b); - - if (b.IsGroup) - parent = b; - } - jobHandle.Complete(); - } - SetPdnResolutionInfo(psdFile, document); - psdFile.Cleanup(); - return document; - } - - internal static JobHandle DecodeToPdnLayer(this PhotoshopFile.Layer psdLayer, JobHandle inputDeps, out BitmapLayer pdnLayer) - { - var psdFile = psdLayer.PsdFile; - psdLayer.CreateMissingChannels(); - - pdnLayer = new BitmapLayer(psdFile.ColumnCount, psdFile.RowCount); - pdnLayer.Name = psdLayer.Name; - pdnLayer.Opacity = psdLayer.Opacity; - pdnLayer.Visible = psdLayer.Visible; - pdnLayer.IsGroup = psdLayer.IsGroup; - pdnLayer.LayerID = psdLayer.LayerID; - pdnLayer.BlendMode = BlendModeMapping.FromPsdBlendMode(psdLayer.BlendModeKey); - return ImageDecoderPdn.DecodeImage(pdnLayer, psdLayer, inputDeps); - } - - /// - /// Creates a layer for each channel in a multichannel image. - /// - private static void CreateLayersFromChannels(PsdFile psdFile) - { - if (psdFile.ColorMode != PsdColorMode.Multichannel) - throw new Exception("Not a multichannel image."); - if (psdFile.Layers.Count > 0) - throw new PsdInvalidException("Multichannel image should not have layers."); - - // Get alpha channel names, preferably in Unicode. - var alphaChannelNames = (AlphaChannelNames)psdFile.ImageResources - .Get(ResourceID.AlphaChannelNames); - var unicodeAlphaNames = (UnicodeAlphaNames)psdFile.ImageResources - .Get(ResourceID.UnicodeAlphaNames); - if ((alphaChannelNames == null) && (unicodeAlphaNames == null)) - throw new PsdInvalidException("No channel names found."); - - var channelNames = (unicodeAlphaNames != null) - ? unicodeAlphaNames.ChannelNames - : alphaChannelNames.ChannelNames; - var channels = psdFile.BaseLayer.Channels; - if (channels.Count > channelNames.Count) - throw new PsdInvalidException("More channels than channel names."); - - // Channels are stored from top to bottom, but layers are stored from - // bottom to top. - for (int i = channels.Count - 1; i >= 0; i--) - { - var channel = channels[i]; - var channelName = channelNames[i]; - - // Copy metadata over from base layer - var layer = new PhotoshopFile.Layer(psdFile); - layer.Rect = psdFile.BaseLayer.Rect; - layer.Visible = true; - layer.Masks = new MaskInfo(); - layer.BlendingRangesData = new BlendingRanges(layer); - - // We do not attempt to reconstruct the appearance of the image, but - // only to provide access to the channels image data. - layer.Name = channelName; - layer.BlendModeKey = PsdBlendMode.Darken; - layer.Opacity = 255; - - // Copy channel image data into the new grayscale layer - var layerChannel = new Channel(0, layer); - layerChannel.ImageCompression = channel.ImageCompression; - layerChannel.ImageData = new NativeArray(channel.ImageData, Allocator.Persistent); - layer.Channels.Add(layerChannel); - - psdFile.Layers.Add(layer); - } - } - - /// - /// Transform Photoshop's layer tree to Paint.NET's flat layer list. - /// Indicate where layer sections begin and end, and hide all layers within - /// hidden layer sections. - /// - private static void ApplyLayerSections(List layers) - { - // BUG: PsdPluginResources.GetString will always return English resource, - // because Paint.NET does not set the CurrentUICulture when OnLoad is - // called. This situation should be resolved with Paint.NET 4.0, which - // will provide an alternative mechanism to retrieve the UI language. - - // Track the depth of the topmost hidden section. Any nested sections - // will be hidden, whether or not they themselves have the flag set. - int topHiddenSectionDepth = Int32.MaxValue; - var layerSectionNames = new Stack(); - - // Layers are stored bottom-to-top, but layer sections are specified - // top-to-bottom. - foreach (var layer in Enumerable.Reverse(layers)) - { - // Leo: Since we are importing, we don't care if the group is collapsed - // Apply to all layers within the layer section, as well as the - // closing layer. - //if (layerSectionNames.Count > topHiddenSectionDepth) - // layer.Visible = false; - - var sectionInfo = (LayerSectionInfo)layer.AdditionalInfo - .SingleOrDefault(x => x is LayerSectionInfo); - if (sectionInfo == null) - continue; - - switch (sectionInfo.SectionType) - { - case LayerSectionType.OpenFolder: - case LayerSectionType.ClosedFolder: - // Start a new layer section - if ((!layer.Visible) && (topHiddenSectionDepth == Int32.MaxValue)) - topHiddenSectionDepth = layerSectionNames.Count; - layerSectionNames.Push(layer.Name); - layer.IsGroup = true; - //layer.Name = String.Format(beginSectionWrapper, layer.Name); - break; - - case LayerSectionType.SectionDivider: - // End the current layer section - //var layerSectionName = layerSectionNames.Pop (); - if (layerSectionNames.Count == topHiddenSectionDepth) - topHiddenSectionDepth = Int32.MaxValue; - layer.IsEndGroupMarker = true; - //layer.Name = String.Format(endSectionWrapper, layerSectionName); - break; - } - } - } - - /// - /// Set the resolution on the Paint.NET Document to match the PSD file. - /// - private static void SetPdnResolutionInfo(PsdFile psdFile, Document document) - { - if (psdFile.Resolution != null) - { - // PSD files always specify the resolution in DPI. When loading and - // saving cm, we will have to round-trip the conversion, but doubles - // have plenty of precision to spare vs. PSD's 16/16 fixed-point. - - if ((psdFile.Resolution.HResDisplayUnit == ResolutionInfo.ResUnit.PxPerCm) - && (psdFile.Resolution.VResDisplayUnit == ResolutionInfo.ResUnit.PxPerCm)) - { - document.DpuUnit = MeasurementUnit.Centimeter; - - // HACK: Paint.NET truncates DpuX and DpuY to three decimal places, - // so add 0.0005 to get a rounded value instead. - document.DpuX = psdFile.Resolution.HDpi / 2.54 + 0.0005; - document.DpuY = psdFile.Resolution.VDpi / 2.54 + 0.0005; - } - else - { - document.DpuUnit = MeasurementUnit.Inch; - document.DpuX = psdFile.Resolution.HDpi; - document.DpuY = psdFile.Resolution.VDpi; - } - } - } - - /// - /// Verify that the PSD file will fit into physical memory once loaded - /// and converted to Paint.NET format. - /// - /// - /// This check is necessary because layers in Paint.NET have the same - /// dimensions as the canvas. Thus, PSD files that contain lots of - /// tiny adjustment layers may blow up in size by several - /// orders of magnitude. - /// - internal static void CheckSufficientMemory(PsdFile psdFile) - { - // Multichannel images have channels converted to layers - var numLayers = (psdFile.ColorMode == PsdColorMode.Multichannel) - ? psdFile.BaseLayer.Channels.Count - : Math.Max(psdFile.Layers.Count, 1); - - // Paint.NET also requires a scratch layer and composite layer - numLayers += 2; - - long numPixels = (long)psdFile.ColumnCount * psdFile.RowCount; - ulong bytesRequired = (ulong)(checked(4 * numPixels * numLayers)); - - // Check that the file will fit entirely into physical memory, so that we - // do not thrash and make the Paint.NET UI nonresponsive. We also have - // to check against virtual memory address space because 32-bit processes - // cannot access all 4 GB. - //var computerInfo = new Microsoft.VisualBasic.Devices.ComputerInfo(); - //var accessibleMemory = Math.Min(computerInfo.TotalPhysicalMemory, - // computerInfo.TotalVirtualMemory); - var accessibleMemory = (ulong)SystemInfo.systemMemorySize * 1024 * 1024; - if (bytesRequired > accessibleMemory) - { - throw new OutOfMemoryException(); - } - } - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2016 Tao Yue +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; + +using PhotoshopFile; +using UnityEngine; +using PDNWrapper; +using Unity.Collections; +using Unity.Jobs; + +namespace PaintDotNet.Data.PhotoshopFileType +{ + internal static class PsdLoad + { + public static PsdFile Load(System.IO.Stream input, ELoadFlag loadFlag) + { + var loadContext = new DocumentLoadContext(); + return new PsdFile(input, loadContext, loadFlag); + } + + public static Document Load(System.IO.Stream input) + { + // Load and decompress Photoshop file structures + var loadContext = new DocumentLoadContext(); + var psdFile = new PsdFile(input, loadContext); + + // Multichannel images are loaded by processing each channel as a + // grayscale layer. + if (psdFile.ColorMode == PsdColorMode.Multichannel) + { + CreateLayersFromChannels(psdFile); + psdFile.ColorMode = PsdColorMode.Grayscale; + } + + // Convert into Paint.NET internal representation + var document = new Document(psdFile.ColumnCount, psdFile.RowCount); + + if (psdFile.Layers.Count == 0) + { + psdFile.BaseLayer.CreateMissingChannels(); + var layer = PDNWrapper.Layer.CreateBackgroundLayer(psdFile.ColumnCount, psdFile.RowCount); + ImageDecoderPdn.DecodeImage(layer, psdFile.BaseLayer); + layer.Name = String.IsNullOrEmpty(psdFile.BaseLayer.Name)? "Background" : psdFile.BaseLayer.Name; + layer.Opacity = psdFile.BaseLayer.Opacity; + layer.Visible = psdFile.BaseLayer.Visible; + layer.IsGroup = psdFile.BaseLayer.IsGroup; + layer.LayerID = psdFile.BaseLayer.LayerID; + layer.BlendMode = BlendModeMapping.FromPsdBlendMode(psdFile.BaseLayer.BlendModeKey); + document.Layers.Add(layer); + } + else + { + psdFile.VerifyLayerSections(); + ApplyLayerSections(psdFile.Layers); + + //var pdnLayers = psdFile.Layers.AsParallel().AsOrdered() + // .Select(psdLayer => psdLayer.DecodeToPdnLayer()) + // .ToList(); + //document.Layers.AddRange(pdnLayers); + /* + foreach (var l in psdFile.Layers) + { + document.Layers.Add(l.DecodeToPdnLayer()); + } + */ + BitmapLayer parent = null; + JobHandle jobHandle = default(JobHandle); + foreach (var l in Enumerable.Reverse(psdFile.Layers)) + { + if (l.IsEndGroupMarker) + { + parent = parent != null ? parent.ParentLayer : null; + continue; + } + BitmapLayer b = null; + jobHandle = l.DecodeToPdnLayer(jobHandle, out b); + b.ParentLayer = parent; + if (parent != null) + parent.ChildLayer.Add(b); + else + document.Layers.Add(b); + + if (b.IsGroup) + parent = b; + } + jobHandle.Complete(); + } + SetPdnResolutionInfo(psdFile, document); + psdFile.Cleanup(); + return document; + } + + internal static JobHandle DecodeToPdnLayer(this PhotoshopFile.Layer psdLayer, JobHandle inputDeps, out BitmapLayer pdnLayer) + { + var psdFile = psdLayer.PsdFile; + psdLayer.CreateMissingChannels(); + + pdnLayer = new BitmapLayer(psdFile.ColumnCount, psdFile.RowCount); + pdnLayer.Name = psdLayer.Name; + pdnLayer.Opacity = psdLayer.Opacity; + pdnLayer.Visible = psdLayer.Visible; + pdnLayer.IsGroup = psdLayer.IsGroup; + pdnLayer.LayerID = psdLayer.LayerID; + pdnLayer.BlendMode = BlendModeMapping.FromPsdBlendMode(psdLayer.BlendModeKey); + return ImageDecoderPdn.DecodeImage(pdnLayer, psdLayer, inputDeps); + } + + /// + /// Creates a layer for each channel in a multichannel image. + /// + private static void CreateLayersFromChannels(PsdFile psdFile) + { + if (psdFile.ColorMode != PsdColorMode.Multichannel) + throw new Exception("Not a multichannel image."); + if (psdFile.Layers.Count > 0) + throw new PsdInvalidException("Multichannel image should not have layers."); + + // Get alpha channel names, preferably in Unicode. + var alphaChannelNames = (AlphaChannelNames)psdFile.ImageResources + .Get(ResourceID.AlphaChannelNames); + var unicodeAlphaNames = (UnicodeAlphaNames)psdFile.ImageResources + .Get(ResourceID.UnicodeAlphaNames); + if ((alphaChannelNames == null) && (unicodeAlphaNames == null)) + throw new PsdInvalidException("No channel names found."); + + var channelNames = (unicodeAlphaNames != null) + ? unicodeAlphaNames.ChannelNames + : alphaChannelNames.ChannelNames; + var channels = psdFile.BaseLayer.Channels; + if (channels.Count > channelNames.Count) + throw new PsdInvalidException("More channels than channel names."); + + // Channels are stored from top to bottom, but layers are stored from + // bottom to top. + for (int i = channels.Count - 1; i >= 0; i--) + { + var channel = channels[i]; + var channelName = channelNames[i]; + + // Copy metadata over from base layer + var layer = new PhotoshopFile.Layer(psdFile); + layer.Rect = psdFile.BaseLayer.Rect; + layer.Visible = true; + layer.Masks = new MaskInfo(); + layer.BlendingRangesData = new BlendingRanges(layer); + + // We do not attempt to reconstruct the appearance of the image, but + // only to provide access to the channels image data. + layer.Name = channelName; + layer.BlendModeKey = PsdBlendMode.Darken; + layer.Opacity = 255; + + // Copy channel image data into the new grayscale layer + var layerChannel = new Channel(0, layer); + layerChannel.ImageCompression = channel.ImageCompression; + layerChannel.ImageData = new NativeArray(channel.ImageData, Allocator.Persistent); + layer.Channels.Add(layerChannel); + + psdFile.Layers.Add(layer); + } + } + + /// + /// Transform Photoshop's layer tree to Paint.NET's flat layer list. + /// Indicate where layer sections begin and end, and hide all layers within + /// hidden layer sections. + /// + private static void ApplyLayerSections(List layers) + { + // BUG: PsdPluginResources.GetString will always return English resource, + // because Paint.NET does not set the CurrentUICulture when OnLoad is + // called. This situation should be resolved with Paint.NET 4.0, which + // will provide an alternative mechanism to retrieve the UI language. + + // Track the depth of the topmost hidden section. Any nested sections + // will be hidden, whether or not they themselves have the flag set. + int topHiddenSectionDepth = Int32.MaxValue; + var layerSectionNames = new Stack(); + + // Layers are stored bottom-to-top, but layer sections are specified + // top-to-bottom. + foreach (var layer in Enumerable.Reverse(layers)) + { + // Leo: Since we are importing, we don't care if the group is collapsed + // Apply to all layers within the layer section, as well as the + // closing layer. + //if (layerSectionNames.Count > topHiddenSectionDepth) + // layer.Visible = false; + + var sectionInfo = (LayerSectionInfo)layer.AdditionalInfo + .SingleOrDefault(x => x is LayerSectionInfo); + if (sectionInfo == null) + continue; + + switch (sectionInfo.SectionType) + { + case LayerSectionType.OpenFolder: + case LayerSectionType.ClosedFolder: + // Start a new layer section + if ((!layer.Visible) && (topHiddenSectionDepth == Int32.MaxValue)) + topHiddenSectionDepth = layerSectionNames.Count; + layerSectionNames.Push(layer.Name); + layer.IsGroup = true; + //layer.Name = String.Format(beginSectionWrapper, layer.Name); + break; + + case LayerSectionType.SectionDivider: + // End the current layer section + //var layerSectionName = layerSectionNames.Pop (); + if (layerSectionNames.Count == topHiddenSectionDepth) + topHiddenSectionDepth = Int32.MaxValue; + layer.IsEndGroupMarker = true; + //layer.Name = String.Format(endSectionWrapper, layerSectionName); + break; + } + } + } + + /// + /// Set the resolution on the Paint.NET Document to match the PSD file. + /// + private static void SetPdnResolutionInfo(PsdFile psdFile, Document document) + { + if (psdFile.Resolution != null) + { + // PSD files always specify the resolution in DPI. When loading and + // saving cm, we will have to round-trip the conversion, but doubles + // have plenty of precision to spare vs. PSD's 16/16 fixed-point. + + if ((psdFile.Resolution.HResDisplayUnit == ResolutionInfo.ResUnit.PxPerCm) + && (psdFile.Resolution.VResDisplayUnit == ResolutionInfo.ResUnit.PxPerCm)) + { + document.DpuUnit = MeasurementUnit.Centimeter; + + // HACK: Paint.NET truncates DpuX and DpuY to three decimal places, + // so add 0.0005 to get a rounded value instead. + document.DpuX = psdFile.Resolution.HDpi / 2.54 + 0.0005; + document.DpuY = psdFile.Resolution.VDpi / 2.54 + 0.0005; + } + else + { + document.DpuUnit = MeasurementUnit.Inch; + document.DpuX = psdFile.Resolution.HDpi; + document.DpuY = psdFile.Resolution.VDpi; + } + } + } + + /// + /// Verify that the PSD file will fit into physical memory once loaded + /// and converted to Paint.NET format. + /// + /// + /// This check is necessary because layers in Paint.NET have the same + /// dimensions as the canvas. Thus, PSD files that contain lots of + /// tiny adjustment layers may blow up in size by several + /// orders of magnitude. + /// + internal static void CheckSufficientMemory(PsdFile psdFile) + { + // Multichannel images have channels converted to layers + var numLayers = (psdFile.ColorMode == PsdColorMode.Multichannel) + ? psdFile.BaseLayer.Channels.Count + : Math.Max(psdFile.Layers.Count, 1); + + // Paint.NET also requires a scratch layer and composite layer + numLayers += 2; + + long numPixels = (long)psdFile.ColumnCount * psdFile.RowCount; + ulong bytesRequired = (ulong)(checked(4 * numPixels * numLayers)); + + // Check that the file will fit entirely into physical memory, so that we + // do not thrash and make the Paint.NET UI nonresponsive. We also have + // to check against virtual memory address space because 32-bit processes + // cannot access all 4 GB. + //var computerInfo = new Microsoft.VisualBasic.Devices.ComputerInfo(); + //var accessibleMemory = Math.Min(computerInfo.TotalPhysicalMemory, + // computerInfo.TotalVirtualMemory); + var accessibleMemory = (ulong)SystemInfo.systemMemorySize * 1024 * 1024; + if (bytesRequired > accessibleMemory) + { + throw new OutOfMemoryException(); + } + } + } +} diff --git a/Editor/PSDPlugin/PhotoShopFileType/PsdLoad.cs.meta b/Editor/PSDPlugin/PhotoShopFileType/PsdLoad.cs.meta index 00a5360..8f57c51 100644 --- a/Editor/PSDPlugin/PhotoShopFileType/PsdLoad.cs.meta +++ b/Editor/PSDPlugin/PhotoShopFileType/PsdLoad.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: da02470271ab86841bf9d88cc0bed2ec -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: da02470271ab86841bf9d88cc0bed2ec +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile.meta b/Editor/PSDPlugin/PsdFile.meta index 78ac90c..ad53108 100644 --- a/Editor/PSDPlugin/PsdFile.meta +++ b/Editor/PSDPlugin/PsdFile.meta @@ -1,9 +1,9 @@ -fileFormatVersion: 2 -guid: e59e9fe7abf273d468dc9e55f8a8acaa -folderAsset: yes -timeCreated: 1495006553 -licenseType: Pro -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: e59e9fe7abf273d468dc9e55f8a8acaa +folderAsset: yes +timeCreated: 1495006553 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/Compression.meta b/Editor/PSDPlugin/PsdFile/Compression.meta index d89d125..330f7f1 100644 --- a/Editor/PSDPlugin/PsdFile/Compression.meta +++ b/Editor/PSDPlugin/PsdFile/Compression.meta @@ -1,9 +1,9 @@ -fileFormatVersion: 2 -guid: cea9a02ce8d970946b9534af754bfda1 -folderAsset: yes -timeCreated: 1495006553 -licenseType: Pro -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: cea9a02ce8d970946b9534af754bfda1 +folderAsset: yes +timeCreated: 1495006553 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/Compression/EndianReverser.cs b/Editor/PSDPlugin/PsdFile/Compression/EndianReverser.cs index 38808eb..e5408f3 100644 --- a/Editor/PSDPlugin/PsdFile/Compression/EndianReverser.cs +++ b/Editor/PSDPlugin/PsdFile/Compression/EndianReverser.cs @@ -1,50 +1,50 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2016 Tao Yue -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; - -namespace PhotoshopFile.Compression -{ - internal class EndianReverser : ImageData - { - private ImageData imageData; - - protected override bool AltersWrittenData - { - get { return true; } - } - - public EndianReverser(ImageData imageData) - : base(imageData.Size, imageData.BitDepth) - { - this.imageData = imageData; - } - - internal override void Read(byte[] buffer) - { - imageData.Read(buffer); - - var numPixels = Size.Width * Size.Height; - if (numPixels == 0) - { - return; - } - Util.SwapByteArray(BitDepth, buffer, 0, numPixels); - } - - public override byte[] ReadCompressed() - { - return imageData.ReadCompressed(); - } - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2016 Tao Yue +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; + +namespace PhotoshopFile.Compression +{ + internal class EndianReverser : ImageData + { + private ImageData imageData; + + protected override bool AltersWrittenData + { + get { return true; } + } + + public EndianReverser(ImageData imageData) + : base(imageData.Size, imageData.BitDepth) + { + this.imageData = imageData; + } + + internal override void Read(byte[] buffer) + { + imageData.Read(buffer); + + var numPixels = Size.Width * Size.Height; + if (numPixels == 0) + { + return; + } + Util.SwapByteArray(BitDepth, buffer, 0, numPixels); + } + + public override byte[] ReadCompressed() + { + return imageData.ReadCompressed(); + } + } +} diff --git a/Editor/PSDPlugin/PsdFile/Compression/EndianReverser.cs.meta b/Editor/PSDPlugin/PsdFile/Compression/EndianReverser.cs.meta index f85a03b..c4631c1 100644 --- a/Editor/PSDPlugin/PsdFile/Compression/EndianReverser.cs.meta +++ b/Editor/PSDPlugin/PsdFile/Compression/EndianReverser.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 1a1cbf26300dbdd4ebaf8e0a92b67db6 -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 1a1cbf26300dbdd4ebaf8e0a92b67db6 +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/Compression/ImageData.cs b/Editor/PSDPlugin/PsdFile/Compression/ImageData.cs index 7b3b009..39fed98 100644 --- a/Editor/PSDPlugin/PsdFile/Compression/ImageData.cs +++ b/Editor/PSDPlugin/PsdFile/Compression/ImageData.cs @@ -1,57 +1,57 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2016 Tao Yue -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using PDNWrapper; -using System.IO.Compression; - -namespace PhotoshopFile.Compression -{ - internal abstract class ImageData - { - public int BitDepth { get; private set; } - - public int BytesPerRow { get; private set; } - - public Size Size { get; private set; } - - protected abstract bool AltersWrittenData { get; } - - protected ImageData(Size size, int bitDepth) - { - Size = size; - BitDepth = bitDepth; - BytesPerRow = Util.BytesPerRow(size, bitDepth); - } - - /// - /// Reads decompressed image data. - /// - public virtual byte[] Read() - { - var imageLongLength = (long)BytesPerRow * Size.Height; - Util.CheckByteArrayLength(imageLongLength); - - var buffer = new byte[imageLongLength]; - Read(buffer); - return buffer; - } - - internal abstract void Read(byte[] buffer); - - /// - /// Reads compressed image data. - /// - public abstract byte[] ReadCompressed(); - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2016 Tao Yue +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using PDNWrapper; +using System.IO.Compression; + +namespace PhotoshopFile.Compression +{ + internal abstract class ImageData + { + public int BitDepth { get; private set; } + + public int BytesPerRow { get; private set; } + + public Size Size { get; private set; } + + protected abstract bool AltersWrittenData { get; } + + protected ImageData(Size size, int bitDepth) + { + Size = size; + BitDepth = bitDepth; + BytesPerRow = Util.BytesPerRow(size, bitDepth); + } + + /// + /// Reads decompressed image data. + /// + public virtual byte[] Read() + { + var imageLongLength = (long)BytesPerRow * Size.Height; + Util.CheckByteArrayLength(imageLongLength); + + var buffer = new byte[imageLongLength]; + Read(buffer); + return buffer; + } + + internal abstract void Read(byte[] buffer); + + /// + /// Reads compressed image data. + /// + public abstract byte[] ReadCompressed(); + } +} diff --git a/Editor/PSDPlugin/PsdFile/Compression/ImageData.cs.meta b/Editor/PSDPlugin/PsdFile/Compression/ImageData.cs.meta index e1c944c..e5c74cf 100644 --- a/Editor/PSDPlugin/PsdFile/Compression/ImageData.cs.meta +++ b/Editor/PSDPlugin/PsdFile/Compression/ImageData.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 23318de62729646489ccb1545e7c5bbf -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 23318de62729646489ccb1545e7c5bbf +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/Compression/ImageDataFactory.cs b/Editor/PSDPlugin/PsdFile/Compression/ImageDataFactory.cs index 98cac8b..1d4aec4 100644 --- a/Editor/PSDPlugin/PsdFile/Compression/ImageDataFactory.cs +++ b/Editor/PSDPlugin/PsdFile/Compression/ImageDataFactory.cs @@ -1,96 +1,96 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2016 Tao Yue -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using System.IO.Compression; -using PDNWrapper; - -namespace PhotoshopFile.Compression -{ - internal static class ImageDataFactory - { - /// - /// Creates an ImageData object to compress or decompress image data. - /// - /// The Channel associated with the image data. - /// The image data to be decompressed, or null if - /// image data is to be compressed. - public static ImageData Create(Channel channel, byte[] data) - { - var bitDepth = channel.Layer.PsdFile.BitDepth; - ImageData imageData; - switch (channel.ImageCompression) - { - case ImageCompression.Raw: - imageData = new RawImage(data, channel.Rect.Size, bitDepth); - break; - - case ImageCompression.Rle: - imageData = new RleImage(data, channel.RleRowLengths, - channel.Rect.Size, bitDepth); - break; - - case ImageCompression.Zip: - // Photoshop treats 32-bit Zip as 32-bit ZipPrediction - imageData = (bitDepth == 32) - ? CreateZipPredict(data, channel.Rect.Size, bitDepth) - : new ZipImage(data, channel.Rect.Size, bitDepth); - break; - - case ImageCompression.ZipPrediction: - imageData = CreateZipPredict(data, channel.Rect.Size, bitDepth); - break; - - default: - throw new PsdInvalidException("Unknown image compression method."); - } - - // Reverse endianness of multi-byte image data - imageData = WrapEndianness(imageData); - - return imageData; - } - - private static ImageData CreateZipPredict(byte[] data, Size size, - int bitDepth) - { - switch (bitDepth) - { - case 16: - return new ZipPredict16Image(data, size); - case 32: - return new ZipPredict32Image(data, size); - default: - throw new PsdInvalidException( - "ZIP with prediction is only available for 16 and 32 bit depths."); - } - } - - private static ImageData WrapEndianness(ImageData imageData) - { - // Single-byte image does not require endianness reversal - if (imageData.BitDepth <= 8) - { - return imageData; - } - - // Bytes will be reordered by the compressor, so no wrapper is needed - if ((imageData is ZipPredict16Image) || (imageData is ZipPredict32Image)) - { - return imageData; - } - - return new EndianReverser(imageData); - } - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2016 Tao Yue +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using System.IO.Compression; +using PDNWrapper; + +namespace PhotoshopFile.Compression +{ + internal static class ImageDataFactory + { + /// + /// Creates an ImageData object to compress or decompress image data. + /// + /// The Channel associated with the image data. + /// The image data to be decompressed, or null if + /// image data is to be compressed. + public static ImageData Create(Channel channel, byte[] data) + { + var bitDepth = channel.Layer.PsdFile.BitDepth; + ImageData imageData; + switch (channel.ImageCompression) + { + case ImageCompression.Raw: + imageData = new RawImage(data, channel.Rect.Size, bitDepth); + break; + + case ImageCompression.Rle: + imageData = new RleImage(data, channel.RleRowLengths, + channel.Rect.Size, bitDepth); + break; + + case ImageCompression.Zip: + // Photoshop treats 32-bit Zip as 32-bit ZipPrediction + imageData = (bitDepth == 32) + ? CreateZipPredict(data, channel.Rect.Size, bitDepth) + : new ZipImage(data, channel.Rect.Size, bitDepth); + break; + + case ImageCompression.ZipPrediction: + imageData = CreateZipPredict(data, channel.Rect.Size, bitDepth); + break; + + default: + throw new PsdInvalidException("Unknown image compression method."); + } + + // Reverse endianness of multi-byte image data + imageData = WrapEndianness(imageData); + + return imageData; + } + + private static ImageData CreateZipPredict(byte[] data, Size size, + int bitDepth) + { + switch (bitDepth) + { + case 16: + return new ZipPredict16Image(data, size); + case 32: + return new ZipPredict32Image(data, size); + default: + throw new PsdInvalidException( + "ZIP with prediction is only available for 16 and 32 bit depths."); + } + } + + private static ImageData WrapEndianness(ImageData imageData) + { + // Single-byte image does not require endianness reversal + if (imageData.BitDepth <= 8) + { + return imageData; + } + + // Bytes will be reordered by the compressor, so no wrapper is needed + if ((imageData is ZipPredict16Image) || (imageData is ZipPredict32Image)) + { + return imageData; + } + + return new EndianReverser(imageData); + } + } +} diff --git a/Editor/PSDPlugin/PsdFile/Compression/ImageDataFactory.cs.meta b/Editor/PSDPlugin/PsdFile/Compression/ImageDataFactory.cs.meta index 67988a5..c05ad0f 100644 --- a/Editor/PSDPlugin/PsdFile/Compression/ImageDataFactory.cs.meta +++ b/Editor/PSDPlugin/PsdFile/Compression/ImageDataFactory.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 3a37c02e17e67be44b01952ad661991c -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 3a37c02e17e67be44b01952ad661991c +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/Compression/RawImage.cs b/Editor/PSDPlugin/PsdFile/Compression/RawImage.cs index 4c4ddb3..7c1e763 100644 --- a/Editor/PSDPlugin/PsdFile/Compression/RawImage.cs +++ b/Editor/PSDPlugin/PsdFile/Compression/RawImage.cs @@ -1,44 +1,44 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2016 Tao Yue -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using PDNWrapper; - -namespace PhotoshopFile.Compression -{ - internal class RawImage : ImageData - { - private byte[] data; - - protected override bool AltersWrittenData - { - get { return false; } - } - - public RawImage(byte[] data, Size size, int bitDepth) - : base(size, bitDepth) - { - this.data = data; - } - - internal override void Read(byte[] buffer) - { - Array.Copy(data, buffer, data.Length); - } - - public override byte[] ReadCompressed() - { - return data; - } - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2016 Tao Yue +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using PDNWrapper; + +namespace PhotoshopFile.Compression +{ + internal class RawImage : ImageData + { + private byte[] data; + + protected override bool AltersWrittenData + { + get { return false; } + } + + public RawImage(byte[] data, Size size, int bitDepth) + : base(size, bitDepth) + { + this.data = data; + } + + internal override void Read(byte[] buffer) + { + Array.Copy(data, buffer, data.Length); + } + + public override byte[] ReadCompressed() + { + return data; + } + } +} diff --git a/Editor/PSDPlugin/PsdFile/Compression/RawImage.cs.meta b/Editor/PSDPlugin/PsdFile/Compression/RawImage.cs.meta index c8ad3bd..ece1327 100644 --- a/Editor/PSDPlugin/PsdFile/Compression/RawImage.cs.meta +++ b/Editor/PSDPlugin/PsdFile/Compression/RawImage.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: b976ddccf1109574c922e1aa8cdd48fb -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: b976ddccf1109574c922e1aa8cdd48fb +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/Compression/RleImage.cs b/Editor/PSDPlugin/PsdFile/Compression/RleImage.cs index 35ed8f7..c255005 100644 --- a/Editor/PSDPlugin/PsdFile/Compression/RleImage.cs +++ b/Editor/PSDPlugin/PsdFile/Compression/RleImage.cs @@ -1,61 +1,61 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is ptortorovided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2016 Tao Yue -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using System.Diagnostics; -using PDNWrapper; -using System.IO; -using System.Linq; - -namespace PhotoshopFile.Compression -{ - internal class RleImage : ImageData - { - private byte[] rleData; - private RleRowLengths rleRowLengths; - - protected override bool AltersWrittenData - { - get { return false; } - } - - public RleImage(byte[] rleData, RleRowLengths rleRowLengths, - Size size, int bitDepth) - : base(size, bitDepth) - { - this.rleData = rleData; - this.rleRowLengths = rleRowLengths; - } - - internal override void Read(byte[] buffer) - { - var rleStream = new MemoryStream(rleData); - var rleReader = new RleReader(rleStream); - var bufferIndex = 0; - for (int i = 0; i < Size.Height; i++) - { - var bytesRead = rleReader.Read(buffer, bufferIndex, BytesPerRow); - if (bytesRead != BytesPerRow) - { - throw new Exception("RLE row decompressed to unexpected length."); - } - bufferIndex += bytesRead; - } - } - - public override byte[] ReadCompressed() - { - return rleData; - } - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is ptortorovided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2016 Tao Yue +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Diagnostics; +using PDNWrapper; +using System.IO; +using System.Linq; + +namespace PhotoshopFile.Compression +{ + internal class RleImage : ImageData + { + private byte[] rleData; + private RleRowLengths rleRowLengths; + + protected override bool AltersWrittenData + { + get { return false; } + } + + public RleImage(byte[] rleData, RleRowLengths rleRowLengths, + Size size, int bitDepth) + : base(size, bitDepth) + { + this.rleData = rleData; + this.rleRowLengths = rleRowLengths; + } + + internal override void Read(byte[] buffer) + { + var rleStream = new MemoryStream(rleData); + var rleReader = new RleReader(rleStream); + var bufferIndex = 0; + for (int i = 0; i < Size.Height; i++) + { + var bytesRead = rleReader.Read(buffer, bufferIndex, BytesPerRow); + if (bytesRead != BytesPerRow) + { + throw new Exception("RLE row decompressed to unexpected length."); + } + bufferIndex += bytesRead; + } + } + + public override byte[] ReadCompressed() + { + return rleData; + } + } +} diff --git a/Editor/PSDPlugin/PsdFile/Compression/RleImage.cs.meta b/Editor/PSDPlugin/PsdFile/Compression/RleImage.cs.meta index d63feae..128ec65 100644 --- a/Editor/PSDPlugin/PsdFile/Compression/RleImage.cs.meta +++ b/Editor/PSDPlugin/PsdFile/Compression/RleImage.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 66819b54b3c858446a1518b135b6514b -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 66819b54b3c858446a1518b135b6514b +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/Compression/ZipImage.cs b/Editor/PSDPlugin/PsdFile/Compression/ZipImage.cs index 1a526f6..3a6cae6 100644 --- a/Editor/PSDPlugin/PsdFile/Compression/ZipImage.cs +++ b/Editor/PSDPlugin/PsdFile/Compression/ZipImage.cs @@ -1,101 +1,101 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2016 Tao Yue -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using PDNWrapper; -using System.IO; -using System.IO.Compression; - -namespace PhotoshopFile.Compression -{ - internal class ZipImage : ImageData - { - private MemoryStream zipDataStream; - private DeflateStream zipStream; - - protected override bool AltersWrittenData - { - get { return false; } - } - - public ZipImage(byte[] data, Size size, int bitDepth) - : base(size, bitDepth) - { - if (data == null) - { - InitCompress(); - } - else - { - InitDecompress(data); - } - } - - private void InitCompress() - { - zipDataStream = new MemoryStream(); - - // Write 2-byte zlib (RFC 1950) header - // - // CMF Compression Method and flags: - // CM 0:3 = 8 = deflate - // CINFO 4:7 = 4 = undefined, RFC 1950 only defines CINFO = 8 - // - // FLG Flags: - // FCHECK 0:4 = 9 = check bits for CMF and FLG - // FDICT 5 = 0 = no preset dictionary - // FLEVEL 6:7 = 2 = default compression level - - zipDataStream.WriteByte(0x48); - zipDataStream.WriteByte(0x89); - zipStream = new DeflateStream(zipDataStream, CompressionMode.Compress, - true); - } - - private void InitDecompress(byte[] data) - { - zipDataStream = new MemoryStream(data); - - // .NET implements Deflate (RFC 1951) but not zlib (RFC 1950), - // so we have to skip the first two bytes. - zipDataStream.ReadByte(); - zipDataStream.ReadByte(); - zipStream = new DeflateStream(zipDataStream, CompressionMode.Decompress, - true); - } - - internal override void Read(byte[] buffer) - { - var bytesToRead = (long)Size.Height * BytesPerRow; - Util.CheckByteArrayLength(bytesToRead); - - var bytesRead = zipStream.Read(buffer, 0, (int)bytesToRead); - if (bytesRead != bytesToRead) - { - throw new Exception("ZIP stream was not fully decompressed."); - } - } - - public override byte[] ReadCompressed() - { - // Write out the last block. (Flush leaves the last block open.) - zipStream.Close(); - - // Do not write the zlib header when the image data is empty - var result = (zipDataStream.Length == 2) - ? new byte[0] - : zipDataStream.ToArray(); - return result; - } - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2016 Tao Yue +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using PDNWrapper; +using System.IO; +using System.IO.Compression; + +namespace PhotoshopFile.Compression +{ + internal class ZipImage : ImageData + { + private MemoryStream zipDataStream; + private DeflateStream zipStream; + + protected override bool AltersWrittenData + { + get { return false; } + } + + public ZipImage(byte[] data, Size size, int bitDepth) + : base(size, bitDepth) + { + if (data == null) + { + InitCompress(); + } + else + { + InitDecompress(data); + } + } + + private void InitCompress() + { + zipDataStream = new MemoryStream(); + + // Write 2-byte zlib (RFC 1950) header + // + // CMF Compression Method and flags: + // CM 0:3 = 8 = deflate + // CINFO 4:7 = 4 = undefined, RFC 1950 only defines CINFO = 8 + // + // FLG Flags: + // FCHECK 0:4 = 9 = check bits for CMF and FLG + // FDICT 5 = 0 = no preset dictionary + // FLEVEL 6:7 = 2 = default compression level + + zipDataStream.WriteByte(0x48); + zipDataStream.WriteByte(0x89); + zipStream = new DeflateStream(zipDataStream, CompressionMode.Compress, + true); + } + + private void InitDecompress(byte[] data) + { + zipDataStream = new MemoryStream(data); + + // .NET implements Deflate (RFC 1951) but not zlib (RFC 1950), + // so we have to skip the first two bytes. + zipDataStream.ReadByte(); + zipDataStream.ReadByte(); + zipStream = new DeflateStream(zipDataStream, CompressionMode.Decompress, + true); + } + + internal override void Read(byte[] buffer) + { + var bytesToRead = (long)Size.Height * BytesPerRow; + Util.CheckByteArrayLength(bytesToRead); + + var bytesRead = zipStream.Read(buffer, 0, (int)bytesToRead); + if (bytesRead != bytesToRead) + { + throw new Exception("ZIP stream was not fully decompressed."); + } + } + + public override byte[] ReadCompressed() + { + // Write out the last block. (Flush leaves the last block open.) + zipStream.Close(); + + // Do not write the zlib header when the image data is empty + var result = (zipDataStream.Length == 2) + ? new byte[0] + : zipDataStream.ToArray(); + return result; + } + } +} diff --git a/Editor/PSDPlugin/PsdFile/Compression/ZipImage.cs.meta b/Editor/PSDPlugin/PsdFile/Compression/ZipImage.cs.meta index 3381e49..88523db 100644 --- a/Editor/PSDPlugin/PsdFile/Compression/ZipImage.cs.meta +++ b/Editor/PSDPlugin/PsdFile/Compression/ZipImage.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 87da90d1a63b1174cb56810e4d9f769e -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 87da90d1a63b1174cb56810e4d9f769e +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/Compression/ZipPredict16Image.cs b/Editor/PSDPlugin/PsdFile/Compression/ZipPredict16Image.cs index 591a3fd..d585676 100644 --- a/Editor/PSDPlugin/PsdFile/Compression/ZipPredict16Image.cs +++ b/Editor/PSDPlugin/PsdFile/Compression/ZipPredict16Image.cs @@ -1,113 +1,113 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2016 Tao Yue -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using PDNWrapper; -using System.IO.Compression; - -namespace PhotoshopFile.Compression -{ - internal class ZipPredict16Image : ImageData - { - private ImageData zipImage; - - protected override bool AltersWrittenData - { - get { return true; } - } - - public ZipPredict16Image(byte[] zipData, Size size) - : base(size, 16) - { - // 16-bitdepth images are delta-encoded word-by-word. The deltas - // are thus big-endian and must be reversed for further processing. - var zipRawImage = new ZipImage(zipData, size, 16); - zipImage = new EndianReverser(zipRawImage); - } - - internal override void Read(byte[] buffer) - { - if (buffer.Length == 0) - { - return; - } - - zipImage.Read(buffer); - - { - { - Unpredict(buffer); - } - } - } - - public override byte[] ReadCompressed() - { - return zipImage.ReadCompressed(); - } - - private void Predict(/*UInt16**/ byte[] ptrData) - { - int size = sizeof(UInt16); - // Delta-encode each row - for (int i = 0; i < Size.Height; i++) - { - int rowOffset = Size.Width * i * size; - //UInt16* ptrDataRow = ptrData; - var ptrDataRowEnd = Size.Width - 1; - - // Start with the last column in the row - while (ptrDataRowEnd > 0) - { - var v = BitConverter.ToUInt16(ptrData, ptrDataRowEnd * size + rowOffset); - var v1 = BitConverter.ToUInt16(ptrData, (ptrDataRowEnd - 1) * size + rowOffset); - v -= v1; - var b = BitConverter.GetBytes(v); - for (int c = 0; c < b.Length; ++c) - { - ptrData[ptrDataRowEnd * size + rowOffset + c] = b[c]; - } - ptrDataRowEnd--; - } - } - } - - /// - /// Unpredicts the decompressed, native-endian image data. - /// - private void Unpredict(byte[] ptrData) - { - int size = sizeof(UInt16); - // Delta-decode each row - for (int i = 0; i < Size.Height; i++) - { - //UInt16* ptrDataRowEnd = ptrData + Size.Width; - int rowOffset = Size.Width * i * size; - // Start with column index 1 on each row - int start = 1; - while (start < Size.Width) - { - var v = BitConverter.ToUInt16(ptrData, start * size + rowOffset); - var v1 = BitConverter.ToUInt16(ptrData, (start - 1) * size + rowOffset); - v += v1; - var b = BitConverter.GetBytes(v); - for (int c = 0; c < b.Length; ++c) - { - ptrData[start * size + rowOffset + c] = b[c]; - } - start++; - } - } - } - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2016 Tao Yue +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using PDNWrapper; +using System.IO.Compression; + +namespace PhotoshopFile.Compression +{ + internal class ZipPredict16Image : ImageData + { + private ImageData zipImage; + + protected override bool AltersWrittenData + { + get { return true; } + } + + public ZipPredict16Image(byte[] zipData, Size size) + : base(size, 16) + { + // 16-bitdepth images are delta-encoded word-by-word. The deltas + // are thus big-endian and must be reversed for further processing. + var zipRawImage = new ZipImage(zipData, size, 16); + zipImage = new EndianReverser(zipRawImage); + } + + internal override void Read(byte[] buffer) + { + if (buffer.Length == 0) + { + return; + } + + zipImage.Read(buffer); + + { + { + Unpredict(buffer); + } + } + } + + public override byte[] ReadCompressed() + { + return zipImage.ReadCompressed(); + } + + private void Predict(/*UInt16**/ byte[] ptrData) + { + int size = sizeof(UInt16); + // Delta-encode each row + for (int i = 0; i < Size.Height; i++) + { + int rowOffset = Size.Width * i * size; + //UInt16* ptrDataRow = ptrData; + var ptrDataRowEnd = Size.Width - 1; + + // Start with the last column in the row + while (ptrDataRowEnd > 0) + { + var v = BitConverter.ToUInt16(ptrData, ptrDataRowEnd * size + rowOffset); + var v1 = BitConverter.ToUInt16(ptrData, (ptrDataRowEnd - 1) * size + rowOffset); + v -= v1; + var b = BitConverter.GetBytes(v); + for (int c = 0; c < b.Length; ++c) + { + ptrData[ptrDataRowEnd * size + rowOffset + c] = b[c]; + } + ptrDataRowEnd--; + } + } + } + + /// + /// Unpredicts the decompressed, native-endian image data. + /// + private void Unpredict(byte[] ptrData) + { + int size = sizeof(UInt16); + // Delta-decode each row + for (int i = 0; i < Size.Height; i++) + { + //UInt16* ptrDataRowEnd = ptrData + Size.Width; + int rowOffset = Size.Width * i * size; + // Start with column index 1 on each row + int start = 1; + while (start < Size.Width) + { + var v = BitConverter.ToUInt16(ptrData, start * size + rowOffset); + var v1 = BitConverter.ToUInt16(ptrData, (start - 1) * size + rowOffset); + v += v1; + var b = BitConverter.GetBytes(v); + for (int c = 0; c < b.Length; ++c) + { + ptrData[start * size + rowOffset + c] = b[c]; + } + start++; + } + } + } + } +} diff --git a/Editor/PSDPlugin/PsdFile/Compression/ZipPredict16Image.cs.meta b/Editor/PSDPlugin/PsdFile/Compression/ZipPredict16Image.cs.meta index e930d0a..823cfcb 100644 --- a/Editor/PSDPlugin/PsdFile/Compression/ZipPredict16Image.cs.meta +++ b/Editor/PSDPlugin/PsdFile/Compression/ZipPredict16Image.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 6259913e8d526e447bf2ff536882fa6c -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 6259913e8d526e447bf2ff536882fa6c +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/Compression/ZipPredict32Image.cs b/Editor/PSDPlugin/PsdFile/Compression/ZipPredict32Image.cs index f9f142f..1e248dd 100644 --- a/Editor/PSDPlugin/PsdFile/Compression/ZipPredict32Image.cs +++ b/Editor/PSDPlugin/PsdFile/Compression/ZipPredict32Image.cs @@ -1,175 +1,175 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2016 Tao Yue -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using PDNWrapper; - -namespace PhotoshopFile.Compression -{ - internal class ZipPredict32Image : ImageData - { - private ZipImage zipImage; - - protected override bool AltersWrittenData - { - // Prediction will pack the data into a temporary buffer, so the - // original data will remain unchanged. - get { return false; } - } - - public ZipPredict32Image(byte[] zipData, Size size) - : base(size, 32) - { - zipImage = new ZipImage(zipData, size, 32); - } - - internal override void Read(byte[] buffer) - { - if (buffer.Length == 0) - { - return; - } - - var predictedData = new byte[buffer.Length]; - zipImage.Read(predictedData); - - - { - //fixed (byte* ptrData = &predictedData[0]) - //fixed (byte* ptrOutput = &buffer[0]) - { - Unpredict(predictedData, buffer); - } - } - } - - public override byte[] ReadCompressed() - { - return zipImage.ReadCompressed(); - } - - private void Predict(byte[] ptrData, byte[] ptrOutput /*Int32* ptrData, byte* ptrOutput*/) - { - int size = sizeof(Int32); - int inputIndex = 0; - int outputIndex = 0; - for (int i = 0; i < Size.Height; i++) - { - // Pack together the individual bytes of the 32-bit words, high-order - // bytes before low-order bytes. - int offset1 = Size.Width; - int offset2 = 2 * offset1; - int offset3 = 3 * offset1; - - //Int32* ptrDataRow = ptrData; - //Int32* ptrDataRowEnd = ptrDataRow + Size.Width; - int start = 0, end = Size.Width; - //while (ptrData < ptrDataRowEnd) - while (start < end) - { - Int32 data = BitConverter.ToInt32(ptrData, inputIndex); - ptrOutput[start + outputIndex] = (byte)(data >> 24); - ptrOutput[start + outputIndex + offset1] = (byte)(data >> 16); - ptrOutput[start + outputIndex + offset2] = (byte)(data >> 8); - ptrOutput[start + outputIndex + offset3] = (byte)(data); - - //ptrData++; - //ptrOutput++; - start++; - inputIndex += size; - } - - // Delta-encode the row - //byte* ptrOutputRow = ptrOutput; - //byte* ptrOutputRowEnd = ptrOutputRow + BytesPerRow; - - //ptrOutput = ptrOutputRowEnd - 1; - start = BytesPerRow - 1; - while (start > 0) - { - ptrOutput[start + outputIndex] -= ptrOutput[start + outputIndex - 1]; - start--; - } - outputIndex += BytesPerRow; - // Advance pointer to next row - //ptrOutput = ptrOutputRowEnd; - //Debug.Assert(ptrData == ptrDataRowEnd); - } - } - - /// - /// Unpredicts the raw decompressed image data into a 32-bpp bitmap with - /// native endianness. - /// - private void Unpredict(byte[] ptrData, byte[] ptrOutput /*byte* ptrData, Int32* ptrOutput*/) - { - int inputIndex = 0; - int outputIndex = 0; - for (int i = 0; i < Size.Height; i++) - { - //byte* ptrDataRow = ptrData; - //byte* ptrDataRowEnd = ptrDataRow + BytesPerRow; - - // Delta-decode each row - //ptrData++; - //while (ptrData < ptrDataRowEnd) - int startIndex = 1; - while (startIndex < BytesPerRow) - { - //*ptrData += *(ptrData - 1); - //ptrData++; - ptrData[inputIndex + startIndex] += ptrData[inputIndex + startIndex - 1]; - startIndex++; - } - - // Within each row, the individual bytes of the 32-bit words are - // packed together, high-order bytes before low-order bytes. - // We now unpack them into words. - int offset1 = Size.Width; - int offset2 = 2 * offset1; - int offset3 = 3 * offset1; - - //ptrData = ptrDataRow; - //Int32* ptrOutputRowEnd = ptrOutput + Size.Width; - //while (ptrOutput < ptrOutputRowEnd) - startIndex = 0; - while (startIndex < Size.Width) - { - Int32 pp = (Int32)ptrData[inputIndex + startIndex] << 24; - pp |= (Int32)ptrData[inputIndex + startIndex + offset1] << 16; - pp |= (Int32)ptrData[inputIndex + startIndex + offset2] << 8; - pp |= (Int32)ptrData[inputIndex + startIndex + offset3]; - byte[] rr = BitConverter.GetBytes(pp); - for (int k = 0; k < rr.Length; ++k) - { - ptrOutput[outputIndex] = rr[k]; - outputIndex++; - } - startIndex++; - //*ptrOutput = *(ptrData) << 24 - // | *(ptrData + offset1) << 16 - // | *(ptrData + offset2) << 8 - // | *(ptrData + offset3); - - //ptrData++; - //ptrOutput++; - } - - // Advance pointer to next row - //ptrData = ptrDataRowEnd; - //Debug.Assert(ptrOutput == ptrOutputRowEnd); - inputIndex += BytesPerRow; - } - } - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2016 Tao Yue +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using PDNWrapper; + +namespace PhotoshopFile.Compression +{ + internal class ZipPredict32Image : ImageData + { + private ZipImage zipImage; + + protected override bool AltersWrittenData + { + // Prediction will pack the data into a temporary buffer, so the + // original data will remain unchanged. + get { return false; } + } + + public ZipPredict32Image(byte[] zipData, Size size) + : base(size, 32) + { + zipImage = new ZipImage(zipData, size, 32); + } + + internal override void Read(byte[] buffer) + { + if (buffer.Length == 0) + { + return; + } + + var predictedData = new byte[buffer.Length]; + zipImage.Read(predictedData); + + + { + //fixed (byte* ptrData = &predictedData[0]) + //fixed (byte* ptrOutput = &buffer[0]) + { + Unpredict(predictedData, buffer); + } + } + } + + public override byte[] ReadCompressed() + { + return zipImage.ReadCompressed(); + } + + private void Predict(byte[] ptrData, byte[] ptrOutput /*Int32* ptrData, byte* ptrOutput*/) + { + int size = sizeof(Int32); + int inputIndex = 0; + int outputIndex = 0; + for (int i = 0; i < Size.Height; i++) + { + // Pack together the individual bytes of the 32-bit words, high-order + // bytes before low-order bytes. + int offset1 = Size.Width; + int offset2 = 2 * offset1; + int offset3 = 3 * offset1; + + //Int32* ptrDataRow = ptrData; + //Int32* ptrDataRowEnd = ptrDataRow + Size.Width; + int start = 0, end = Size.Width; + //while (ptrData < ptrDataRowEnd) + while (start < end) + { + Int32 data = BitConverter.ToInt32(ptrData, inputIndex); + ptrOutput[start + outputIndex] = (byte)(data >> 24); + ptrOutput[start + outputIndex + offset1] = (byte)(data >> 16); + ptrOutput[start + outputIndex + offset2] = (byte)(data >> 8); + ptrOutput[start + outputIndex + offset3] = (byte)(data); + + //ptrData++; + //ptrOutput++; + start++; + inputIndex += size; + } + + // Delta-encode the row + //byte* ptrOutputRow = ptrOutput; + //byte* ptrOutputRowEnd = ptrOutputRow + BytesPerRow; + + //ptrOutput = ptrOutputRowEnd - 1; + start = BytesPerRow - 1; + while (start > 0) + { + ptrOutput[start + outputIndex] -= ptrOutput[start + outputIndex - 1]; + start--; + } + outputIndex += BytesPerRow; + // Advance pointer to next row + //ptrOutput = ptrOutputRowEnd; + //Debug.Assert(ptrData == ptrDataRowEnd); + } + } + + /// + /// Unpredicts the raw decompressed image data into a 32-bpp bitmap with + /// native endianness. + /// + private void Unpredict(byte[] ptrData, byte[] ptrOutput /*byte* ptrData, Int32* ptrOutput*/) + { + int inputIndex = 0; + int outputIndex = 0; + for (int i = 0; i < Size.Height; i++) + { + //byte* ptrDataRow = ptrData; + //byte* ptrDataRowEnd = ptrDataRow + BytesPerRow; + + // Delta-decode each row + //ptrData++; + //while (ptrData < ptrDataRowEnd) + int startIndex = 1; + while (startIndex < BytesPerRow) + { + //*ptrData += *(ptrData - 1); + //ptrData++; + ptrData[inputIndex + startIndex] += ptrData[inputIndex + startIndex - 1]; + startIndex++; + } + + // Within each row, the individual bytes of the 32-bit words are + // packed together, high-order bytes before low-order bytes. + // We now unpack them into words. + int offset1 = Size.Width; + int offset2 = 2 * offset1; + int offset3 = 3 * offset1; + + //ptrData = ptrDataRow; + //Int32* ptrOutputRowEnd = ptrOutput + Size.Width; + //while (ptrOutput < ptrOutputRowEnd) + startIndex = 0; + while (startIndex < Size.Width) + { + Int32 pp = (Int32)ptrData[inputIndex + startIndex] << 24; + pp |= (Int32)ptrData[inputIndex + startIndex + offset1] << 16; + pp |= (Int32)ptrData[inputIndex + startIndex + offset2] << 8; + pp |= (Int32)ptrData[inputIndex + startIndex + offset3]; + byte[] rr = BitConverter.GetBytes(pp); + for (int k = 0; k < rr.Length; ++k) + { + ptrOutput[outputIndex] = rr[k]; + outputIndex++; + } + startIndex++; + //*ptrOutput = *(ptrData) << 24 + // | *(ptrData + offset1) << 16 + // | *(ptrData + offset2) << 8 + // | *(ptrData + offset3); + + //ptrData++; + //ptrOutput++; + } + + // Advance pointer to next row + //ptrData = ptrDataRowEnd; + //Debug.Assert(ptrOutput == ptrOutputRowEnd); + inputIndex += BytesPerRow; + } + } + } +} diff --git a/Editor/PSDPlugin/PsdFile/Compression/ZipPredict32Image.cs.meta b/Editor/PSDPlugin/PsdFile/Compression/ZipPredict32Image.cs.meta index 4212af7..c824185 100644 --- a/Editor/PSDPlugin/PsdFile/Compression/ZipPredict32Image.cs.meta +++ b/Editor/PSDPlugin/PsdFile/Compression/ZipPredict32Image.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 2bb49ac2cee975745af2d48523e135c9 -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 2bb49ac2cee975745af2d48523e135c9 +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/Exceptions.cs b/Editor/PSDPlugin/PsdFile/Exceptions.cs index 538d234..3bce07d 100644 --- a/Editor/PSDPlugin/PsdFile/Exceptions.cs +++ b/Editor/PSDPlugin/PsdFile/Exceptions.cs @@ -1,43 +1,43 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is perovided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2012 Tao Yue -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using PDNWrapper; -using System.Linq; -using System.Text; - -namespace PhotoshopFile -{ - [Serializable] - internal class PsdInvalidException : Exception - { - public PsdInvalidException() - { - } - - public PsdInvalidException(string message) - : base(message) - { - } - } - - [Serializable] - internal class RleException : Exception - { - public RleException() {} - - public RleException(string message) : base(message) {} - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is perovided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2012 Tao Yue +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using PDNWrapper; +using System.Linq; +using System.Text; + +namespace PhotoshopFile +{ + [Serializable] + internal class PsdInvalidException : Exception + { + public PsdInvalidException() + { + } + + public PsdInvalidException(string message) + : base(message) + { + } + } + + [Serializable] + internal class RleException : Exception + { + public RleException() {} + + public RleException(string message) : base(message) {} + } +} diff --git a/Editor/PSDPlugin/PsdFile/Exceptions.cs.meta b/Editor/PSDPlugin/PsdFile/Exceptions.cs.meta index 5ca1b9b..c0444bb 100644 --- a/Editor/PSDPlugin/PsdFile/Exceptions.cs.meta +++ b/Editor/PSDPlugin/PsdFile/Exceptions.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 1359900d9d213c641b1d44f49de5281d -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 1359900d9d213c641b1d44f49de5281d +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/ImageResource.cs b/Editor/PSDPlugin/PsdFile/ImageResource.cs index bc57e35..8b7d321 100644 --- a/Editor/PSDPlugin/PsdFile/ImageResource.cs +++ b/Editor/PSDPlugin/PsdFile/ImageResource.cs @@ -1,234 +1,234 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2015 Tao Yue -// -// Portions of this file are provided under the BSD 3-clause License: -// Copyright (c) 2006, Jonas Beckeman -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using System.IO; -using System.Linq; - -namespace PhotoshopFile -{ - internal enum ResourceID - { - Undefined = 0, - MacPrintInfo = 1001, - ResolutionInfo = 1005, - AlphaChannelNames = 1006, - DisplayInfo = 1007, - Caption = 1008, - BorderInfo = 1009, - BackgroundColor = 1010, - PrintFlags = 1011, - MultichannelHalftoneInfo = 1012, - ColorHalftoneInfo = 1013, - DuotoneHalftoneInfo = 1014, - MultichannelTransferFunctions = 1015, - ColorTransferFunctions = 1016, - DuotoneTransferFunctions = 1017, - DuotoneImageInfo = 1018, - BlackWhiteRange = 1019, - EpsOptions = 1021, - QuickMaskInfo = 1022, - LayerStateInfo = 1024, - WorkingPathUnsaved = 1025, - LayersGroupInfo = 1026, - IptcNaa = 1028, - RawFormatImageMode = 1029, - JpegQuality = 1030, - GridGuidesInfo = 1032, - ThumbnailBgr = 1033, - CopyrightInfo = 1034, - Url = 1035, - ThumbnailRgb = 1036, - GlobalAngle = 1037, - ColorSamplersObsolete = 1038, - IccProfile = 1039, - Watermark = 1040, - IccUntagged = 1041, - EffectsVisible = 1042, - SpotHalftone = 1043, - DocumentSpecific = 1044, - UnicodeAlphaNames = 1045, - IndexedColorTableCount = 1046, - TransparentIndex = 1047, - GlobalAltitude = 1049, - Slices = 1050, - WorkflowUrl = 1051, - JumpToXpep = 1052, - AlphaIdentifiers = 1053, - UrlList = 1054, - VersionInfo = 1057, - ExifData1 = 1058, - ExifData3 = 1059, - XmpMetadata = 1060, - CaptionDigest = 1061, - PrintScale = 1062, - PixelAspectRatio = 1064, - LayerComps = 1065, - AlternateDuotoneColors = 1066, - AlternateSpotColors = 1067, - LayerSelectionIDs = 1069, - HdrToningInfo = 1070, - PrintInfo = 1071, - LayerGroupsEnabled = 1072, - ColorSamplers = 1073, - MeasurementScale = 1074, - TimelineInfo = 1075, - SheetDisclosure = 1076, - FloatDisplayInfo = 1077, - OnionSkins = 1078, - CountInfo = 1080, - PrintSettingsInfo = 1082, - PrintStyle = 1083, - MacNSPrintInfo = 1084, - WinDevMode = 1085, - AutoSaveFilePath = 1086, - AutoSaveFormat = 1087, - PathInfo = 2000, // 2000-2999: Path Information - ClippingPathName = 2999, - LightroomWorkflow = 8000, - PrintFlagsInfo = 10000 - } - - /// - /// Abstract class for Image Resources - /// - internal abstract class ImageResource - { - private string signature; - public string Signature - { - get { return signature; } - set - { - if (value.Length != 4) - { - throw new ArgumentException( - "Signature must be 4 characters in length."); - } - signature = value; - } - } - - public string Name { get; set; } - - public abstract ResourceID ID { get; } - - protected ImageResource(string name) - { - Signature = "8BIM"; - Name = name; - } - } - - /// - /// Creates the appropriate subclass of ImageResource. - /// - internal static class ImageResourceFactory - { - public static ImageResource CreateImageResource(PsdBinaryReader reader) - { - Util.DebugMessage(reader.BaseStream, "Load, Begin, ImageResource"); - - var signature = reader.ReadAsciiChars(4); - var resourceIdInt = reader.ReadUInt16(); - var name = reader.ReadPascalString(2); - var dataLength = (int)reader.ReadUInt32(); - - var dataPaddedLength = Util.RoundUp(dataLength, 2); - var endPosition = reader.BaseStream.Position + dataPaddedLength; - - ImageResource resource = null; - var resourceId = (ResourceID)resourceIdInt; - switch (resourceId) - { - case ResourceID.ResolutionInfo: - resource = new ResolutionInfo(reader, name); - break; - case ResourceID.ThumbnailRgb: - case ResourceID.ThumbnailBgr: - resource = new Thumbnail(reader, resourceId, name, dataLength); - break; - case ResourceID.AlphaChannelNames: - resource = new AlphaChannelNames(reader, name, dataLength); - break; - case ResourceID.UnicodeAlphaNames: - resource = new UnicodeAlphaNames(reader, name, dataLength); - break; - case ResourceID.VersionInfo: - resource = new VersionInfo(reader, name); - break; - default: - resource = new RawImageResource(reader, signature, resourceId, name, dataLength); - break; - } - - Util.DebugMessage(reader.BaseStream, "Load, End, ImageResource, {0}", - resourceId); - - // Reposition the reader if we do not consume the full resource block. - // This takes care of the even-padding, and also preserves forward- - // compatibility in case a resource block is later extended with - // additional properties. - if (reader.BaseStream.Position < endPosition) - reader.BaseStream.Position = endPosition; - - // However, overruns are definitely an error. - if (reader.BaseStream.Position > endPosition) - throw new PsdInvalidException("Corruption detected in resource."); - - return resource; - } - } - - internal class ImageResources : List - { - public ImageResources() : base() - { - } - - public ImageResource Get(ResourceID id) - { - return Find(x => x.ID == id); - } - - public void Set(ImageResource resource) - { - Predicate matchId = delegate(ImageResource res) - { - return res.ID == resource.ID; - }; - var itemIdx = this.FindIndex(matchId); - var lastItemIdx = this.FindLastIndex(matchId); - - if (itemIdx == -1) - { - Add(resource); - } - else if (itemIdx != lastItemIdx) - { - RemoveAll(matchId); - Insert(itemIdx, resource); - } - else - { - this[itemIdx] = resource; - } - } - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2015 Tao Yue +// +// Portions of this file are provided under the BSD 3-clause License: +// Copyright (c) 2006, Jonas Beckeman +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Linq; + +namespace PhotoshopFile +{ + internal enum ResourceID + { + Undefined = 0, + MacPrintInfo = 1001, + ResolutionInfo = 1005, + AlphaChannelNames = 1006, + DisplayInfo = 1007, + Caption = 1008, + BorderInfo = 1009, + BackgroundColor = 1010, + PrintFlags = 1011, + MultichannelHalftoneInfo = 1012, + ColorHalftoneInfo = 1013, + DuotoneHalftoneInfo = 1014, + MultichannelTransferFunctions = 1015, + ColorTransferFunctions = 1016, + DuotoneTransferFunctions = 1017, + DuotoneImageInfo = 1018, + BlackWhiteRange = 1019, + EpsOptions = 1021, + QuickMaskInfo = 1022, + LayerStateInfo = 1024, + WorkingPathUnsaved = 1025, + LayersGroupInfo = 1026, + IptcNaa = 1028, + RawFormatImageMode = 1029, + JpegQuality = 1030, + GridGuidesInfo = 1032, + ThumbnailBgr = 1033, + CopyrightInfo = 1034, + Url = 1035, + ThumbnailRgb = 1036, + GlobalAngle = 1037, + ColorSamplersObsolete = 1038, + IccProfile = 1039, + Watermark = 1040, + IccUntagged = 1041, + EffectsVisible = 1042, + SpotHalftone = 1043, + DocumentSpecific = 1044, + UnicodeAlphaNames = 1045, + IndexedColorTableCount = 1046, + TransparentIndex = 1047, + GlobalAltitude = 1049, + Slices = 1050, + WorkflowUrl = 1051, + JumpToXpep = 1052, + AlphaIdentifiers = 1053, + UrlList = 1054, + VersionInfo = 1057, + ExifData1 = 1058, + ExifData3 = 1059, + XmpMetadata = 1060, + CaptionDigest = 1061, + PrintScale = 1062, + PixelAspectRatio = 1064, + LayerComps = 1065, + AlternateDuotoneColors = 1066, + AlternateSpotColors = 1067, + LayerSelectionIDs = 1069, + HdrToningInfo = 1070, + PrintInfo = 1071, + LayerGroupsEnabled = 1072, + ColorSamplers = 1073, + MeasurementScale = 1074, + TimelineInfo = 1075, + SheetDisclosure = 1076, + FloatDisplayInfo = 1077, + OnionSkins = 1078, + CountInfo = 1080, + PrintSettingsInfo = 1082, + PrintStyle = 1083, + MacNSPrintInfo = 1084, + WinDevMode = 1085, + AutoSaveFilePath = 1086, + AutoSaveFormat = 1087, + PathInfo = 2000, // 2000-2999: Path Information + ClippingPathName = 2999, + LightroomWorkflow = 8000, + PrintFlagsInfo = 10000 + } + + /// + /// Abstract class for Image Resources + /// + internal abstract class ImageResource + { + private string signature; + public string Signature + { + get { return signature; } + set + { + if (value.Length != 4) + { + throw new ArgumentException( + "Signature must be 4 characters in length."); + } + signature = value; + } + } + + public string Name { get; set; } + + public abstract ResourceID ID { get; } + + protected ImageResource(string name) + { + Signature = "8BIM"; + Name = name; + } + } + + /// + /// Creates the appropriate subclass of ImageResource. + /// + internal static class ImageResourceFactory + { + public static ImageResource CreateImageResource(PsdBinaryReader reader) + { + Util.DebugMessage(reader.BaseStream, "Load, Begin, ImageResource"); + + var signature = reader.ReadAsciiChars(4); + var resourceIdInt = reader.ReadUInt16(); + var name = reader.ReadPascalString(2); + var dataLength = (int)reader.ReadUInt32(); + + var dataPaddedLength = Util.RoundUp(dataLength, 2); + var endPosition = reader.BaseStream.Position + dataPaddedLength; + + ImageResource resource = null; + var resourceId = (ResourceID)resourceIdInt; + switch (resourceId) + { + case ResourceID.ResolutionInfo: + resource = new ResolutionInfo(reader, name); + break; + case ResourceID.ThumbnailRgb: + case ResourceID.ThumbnailBgr: + resource = new Thumbnail(reader, resourceId, name, dataLength); + break; + case ResourceID.AlphaChannelNames: + resource = new AlphaChannelNames(reader, name, dataLength); + break; + case ResourceID.UnicodeAlphaNames: + resource = new UnicodeAlphaNames(reader, name, dataLength); + break; + case ResourceID.VersionInfo: + resource = new VersionInfo(reader, name); + break; + default: + resource = new RawImageResource(reader, signature, resourceId, name, dataLength); + break; + } + + Util.DebugMessage(reader.BaseStream, "Load, End, ImageResource, {0}", + resourceId); + + // Reposition the reader if we do not consume the full resource block. + // This takes care of the even-padding, and also preserves forward- + // compatibility in case a resource block is later extended with + // additional properties. + if (reader.BaseStream.Position < endPosition) + reader.BaseStream.Position = endPosition; + + // However, overruns are definitely an error. + if (reader.BaseStream.Position > endPosition) + throw new PsdInvalidException("Corruption detected in resource."); + + return resource; + } + } + + internal class ImageResources : List + { + public ImageResources() : base() + { + } + + public ImageResource Get(ResourceID id) + { + return Find(x => x.ID == id); + } + + public void Set(ImageResource resource) + { + Predicate matchId = delegate(ImageResource res) + { + return res.ID == resource.ID; + }; + var itemIdx = this.FindIndex(matchId); + var lastItemIdx = this.FindLastIndex(matchId); + + if (itemIdx == -1) + { + Add(resource); + } + else if (itemIdx != lastItemIdx) + { + RemoveAll(matchId); + Insert(itemIdx, resource); + } + else + { + this[itemIdx] = resource; + } + } + } +} diff --git a/Editor/PSDPlugin/PsdFile/ImageResource.cs.meta b/Editor/PSDPlugin/PsdFile/ImageResource.cs.meta index bc65b62..e6e38a4 100644 --- a/Editor/PSDPlugin/PsdFile/ImageResource.cs.meta +++ b/Editor/PSDPlugin/PsdFile/ImageResource.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 4bdfc57c0f4c65947a6971d815bd7ea7 -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 4bdfc57c0f4c65947a6971d815bd7ea7 +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/ImageResources.meta b/Editor/PSDPlugin/PsdFile/ImageResources.meta index c49386b..8d4acf4 100644 --- a/Editor/PSDPlugin/PsdFile/ImageResources.meta +++ b/Editor/PSDPlugin/PsdFile/ImageResources.meta @@ -1,9 +1,9 @@ -fileFormatVersion: 2 -guid: f6b2d5715ac4ed8478b3819e8fe5918a -folderAsset: yes -timeCreated: 1495006553 -licenseType: Pro -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: f6b2d5715ac4ed8478b3819e8fe5918a +folderAsset: yes +timeCreated: 1495006553 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/ImageResources/AlphaChannelNames.cs b/Editor/PSDPlugin/PsdFile/ImageResources/AlphaChannelNames.cs index d73a1e5..964e5d6 100644 --- a/Editor/PSDPlugin/PsdFile/ImageResources/AlphaChannelNames.cs +++ b/Editor/PSDPlugin/PsdFile/ImageResources/AlphaChannelNames.cs @@ -1,52 +1,52 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2013 Tao Yue -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using System.Collections.Generic; - -namespace PhotoshopFile -{ - /// - /// The names of the alpha channels - /// - internal class AlphaChannelNames : ImageResource - { - public override ResourceID ID - { - get { return ResourceID.AlphaChannelNames; } - } - - private List channelNames = new List(); - public List ChannelNames - { - get { return channelNames; } - } - - public AlphaChannelNames() : base(String.Empty) - { - } - - public AlphaChannelNames(PsdBinaryReader reader, string name, int resourceDataLength) - : base(name) - { - var endPosition = reader.BaseStream.Position + resourceDataLength; - - // Alpha channel names are Pascal strings, with no padding in-between. - while (reader.BaseStream.Position < endPosition) - { - var channelName = reader.ReadPascalString(1); - ChannelNames.Add(channelName); - } - } - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2013 Tao Yue +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Collections.Generic; + +namespace PhotoshopFile +{ + /// + /// The names of the alpha channels + /// + internal class AlphaChannelNames : ImageResource + { + public override ResourceID ID + { + get { return ResourceID.AlphaChannelNames; } + } + + private List channelNames = new List(); + public List ChannelNames + { + get { return channelNames; } + } + + public AlphaChannelNames() : base(String.Empty) + { + } + + public AlphaChannelNames(PsdBinaryReader reader, string name, int resourceDataLength) + : base(name) + { + var endPosition = reader.BaseStream.Position + resourceDataLength; + + // Alpha channel names are Pascal strings, with no padding in-between. + while (reader.BaseStream.Position < endPosition) + { + var channelName = reader.ReadPascalString(1); + ChannelNames.Add(channelName); + } + } + } +} diff --git a/Editor/PSDPlugin/PsdFile/ImageResources/AlphaChannelNames.cs.meta b/Editor/PSDPlugin/PsdFile/ImageResources/AlphaChannelNames.cs.meta index ebc598c..7d3939e 100644 --- a/Editor/PSDPlugin/PsdFile/ImageResources/AlphaChannelNames.cs.meta +++ b/Editor/PSDPlugin/PsdFile/ImageResources/AlphaChannelNames.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 3e90381151086314691cd7a595ba9a62 -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 3e90381151086314691cd7a595ba9a62 +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/ImageResources/RawImageResource.cs b/Editor/PSDPlugin/PsdFile/ImageResources/RawImageResource.cs index efe54e5..e7f646b 100644 --- a/Editor/PSDPlugin/PsdFile/ImageResources/RawImageResource.cs +++ b/Editor/PSDPlugin/PsdFile/ImageResources/RawImageResource.cs @@ -1,48 +1,48 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2013 Tao Yue -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using System.IO; -using PDNWrapper; - -namespace PhotoshopFile -{ - /// - /// Stores the raw data for unimplemented image resource types. - /// - internal class RawImageResource : ImageResource - { - public byte[] Data { get; private set; } - - private ResourceID id; - public override ResourceID ID - { - get { return id; } - } - - public RawImageResource(ResourceID resourceId, string name) - : base(name) - { - this.id = resourceId; - } - - public RawImageResource(PsdBinaryReader reader, string signature, - ResourceID resourceId, string name, int numBytes) - : base(name) - { - this.Signature = signature; - this.id = resourceId; - Data = reader.ReadBytes(numBytes); - } - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2013 Tao Yue +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using System.IO; +using PDNWrapper; + +namespace PhotoshopFile +{ + /// + /// Stores the raw data for unimplemented image resource types. + /// + internal class RawImageResource : ImageResource + { + public byte[] Data { get; private set; } + + private ResourceID id; + public override ResourceID ID + { + get { return id; } + } + + public RawImageResource(ResourceID resourceId, string name) + : base(name) + { + this.id = resourceId; + } + + public RawImageResource(PsdBinaryReader reader, string signature, + ResourceID resourceId, string name, int numBytes) + : base(name) + { + this.Signature = signature; + this.id = resourceId; + Data = reader.ReadBytes(numBytes); + } + } +} diff --git a/Editor/PSDPlugin/PsdFile/ImageResources/RawImageResource.cs.meta b/Editor/PSDPlugin/PsdFile/ImageResources/RawImageResource.cs.meta index fe8ef81..24f100e 100644 --- a/Editor/PSDPlugin/PsdFile/ImageResources/RawImageResource.cs.meta +++ b/Editor/PSDPlugin/PsdFile/ImageResources/RawImageResource.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 764df10adc2353a47a5ae0e9649e51a6 -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 764df10adc2353a47a5ae0e9649e51a6 +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/ImageResources/ResolutionInfo.cs b/Editor/PSDPlugin/PsdFile/ImageResources/ResolutionInfo.cs index ce86574..18de7b3 100644 --- a/Editor/PSDPlugin/PsdFile/ImageResources/ResolutionInfo.cs +++ b/Editor/PSDPlugin/PsdFile/ImageResources/ResolutionInfo.cs @@ -1,94 +1,94 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2012 Tao Yue -// -// Portions of this file are provided under the BSD 3-clause License: -// Copyright (c) 2006, Jonas Beckeman -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; - -namespace PhotoshopFile -{ - /// - /// Summary description for ResolutionInfo. - /// - internal class ResolutionInfo : ImageResource - { - public override ResourceID ID - { - get { return ResourceID.ResolutionInfo; } - } - - /// - /// Horizontal DPI. - /// - public UFixed16_16 HDpi { get; set; } - - /// - /// Vertical DPI. - /// - public UFixed16_16 VDpi { get; set; } - - /// - /// 1 = pixels per inch, 2 = pixels per centimeter - /// - internal enum ResUnit - { - PxPerInch = 1, - PxPerCm = 2 - } - - /// - /// Display units for horizontal resolution. This only affects the - /// user interface; the resolution is still stored in the PSD file - /// as pixels/inch. - /// - public ResUnit HResDisplayUnit { get; set; } - - /// - /// Display units for vertical resolution. - /// - public ResUnit VResDisplayUnit { get; set; } - - /// - /// Physical units. - /// - internal enum Unit - { - Inches = 1, - Centimeters = 2, - Points = 3, - Picas = 4, - Columns = 5 - } - - public Unit WidthDisplayUnit { get; set; } - - public Unit HeightDisplayUnit { get; set; } - - public ResolutionInfo() : base(String.Empty) - { - } - - public ResolutionInfo(PsdBinaryReader reader, string name) - : base(name) - { - this.HDpi = new UFixed16_16(reader.ReadUInt32()); - this.HResDisplayUnit = (ResUnit)reader.ReadInt16(); - this.WidthDisplayUnit = (Unit)reader.ReadInt16(); - - this.VDpi = new UFixed16_16(reader.ReadUInt32()); - this.VResDisplayUnit = (ResUnit)reader.ReadInt16(); - this.HeightDisplayUnit = (Unit)reader.ReadInt16(); - } - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2012 Tao Yue +// +// Portions of this file are provided under the BSD 3-clause License: +// Copyright (c) 2006, Jonas Beckeman +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; + +namespace PhotoshopFile +{ + /// + /// Summary description for ResolutionInfo. + /// + internal class ResolutionInfo : ImageResource + { + public override ResourceID ID + { + get { return ResourceID.ResolutionInfo; } + } + + /// + /// Horizontal DPI. + /// + public UFixed16_16 HDpi { get; set; } + + /// + /// Vertical DPI. + /// + public UFixed16_16 VDpi { get; set; } + + /// + /// 1 = pixels per inch, 2 = pixels per centimeter + /// + internal enum ResUnit + { + PxPerInch = 1, + PxPerCm = 2 + } + + /// + /// Display units for horizontal resolution. This only affects the + /// user interface; the resolution is still stored in the PSD file + /// as pixels/inch. + /// + public ResUnit HResDisplayUnit { get; set; } + + /// + /// Display units for vertical resolution. + /// + public ResUnit VResDisplayUnit { get; set; } + + /// + /// Physical units. + /// + internal enum Unit + { + Inches = 1, + Centimeters = 2, + Points = 3, + Picas = 4, + Columns = 5 + } + + public Unit WidthDisplayUnit { get; set; } + + public Unit HeightDisplayUnit { get; set; } + + public ResolutionInfo() : base(String.Empty) + { + } + + public ResolutionInfo(PsdBinaryReader reader, string name) + : base(name) + { + this.HDpi = new UFixed16_16(reader.ReadUInt32()); + this.HResDisplayUnit = (ResUnit)reader.ReadInt16(); + this.WidthDisplayUnit = (Unit)reader.ReadInt16(); + + this.VDpi = new UFixed16_16(reader.ReadUInt32()); + this.VResDisplayUnit = (ResUnit)reader.ReadInt16(); + this.HeightDisplayUnit = (Unit)reader.ReadInt16(); + } + } +} diff --git a/Editor/PSDPlugin/PsdFile/ImageResources/ResolutionInfo.cs.meta b/Editor/PSDPlugin/PsdFile/ImageResources/ResolutionInfo.cs.meta index 976a44e..edf38bb 100644 --- a/Editor/PSDPlugin/PsdFile/ImageResources/ResolutionInfo.cs.meta +++ b/Editor/PSDPlugin/PsdFile/ImageResources/ResolutionInfo.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 285de09dadd2d3048a1028754eda2fa1 -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 285de09dadd2d3048a1028754eda2fa1 +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/ImageResources/Thumbnail.cs b/Editor/PSDPlugin/PsdFile/ImageResources/Thumbnail.cs index d17aafb..b5e875f 100644 --- a/Editor/PSDPlugin/PsdFile/ImageResources/Thumbnail.cs +++ b/Editor/PSDPlugin/PsdFile/ImageResources/Thumbnail.cs @@ -1,85 +1,85 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2013 Tao Yue -// -// Portions of this file are provided under the BSD 3-clause License: -// Copyright (c) 2006, Jonas Beckeman -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using System.IO; -using System.Diagnostics; -using PDNWrapper; -//using PDNWrapper.Imaging; - -namespace PhotoshopFile -{ - /// - /// Summary description for Thumbnail. - /// - internal class Thumbnail : RawImageResource - { - public Thumbnail(ResourceID id, string name) - : base(id, name) - { - } - - public Thumbnail(PsdBinaryReader psdReader, ResourceID id, string name, int numBytes) - : base(psdReader, "8BIM", id, name, numBytes) - { - using (var memoryStream = new MemoryStream(Data)) - using (var reader = new PsdBinaryReader(memoryStream, psdReader)) - { - const int HEADER_LENGTH = 28; - var format = reader.ReadUInt32(); - //var width = reader.ReadUInt32(); - //var height = reader.ReadUInt32(); - //var widthBytes = reader.ReadUInt32(); - //var size = reader.ReadUInt32(); - //var compressedSize = reader.ReadUInt32(); - //var bitPerPixel = reader.ReadUInt16(); - //var planes = reader.ReadUInt16(); - - // Raw RGB bitmap - if (format == 0) - { - //Image = new Bitmap((int)width, (int)height, PixelFormat.Format24bppRgb); - } - // JPEG bitmap - else if (format == 1) - { - byte[] imgData = reader.ReadBytes(numBytes - HEADER_LENGTH); - using (MemoryStream stream = new MemoryStream(imgData)) - { - //var bitmap = new Bitmap(stream); - //Image = (Bitmap)bitmap.Clone(); - } - - // Reverse BGR pixels from old thumbnail format - if (id == ResourceID.ThumbnailBgr) - { - //for(int y=0;y + /// Summary description for Thumbnail. + /// + internal class Thumbnail : RawImageResource + { + public Thumbnail(ResourceID id, string name) + : base(id, name) + { + } + + public Thumbnail(PsdBinaryReader psdReader, ResourceID id, string name, int numBytes) + : base(psdReader, "8BIM", id, name, numBytes) + { + using (var memoryStream = new MemoryStream(Data)) + using (var reader = new PsdBinaryReader(memoryStream, psdReader)) + { + const int HEADER_LENGTH = 28; + var format = reader.ReadUInt32(); + //var width = reader.ReadUInt32(); + //var height = reader.ReadUInt32(); + //var widthBytes = reader.ReadUInt32(); + //var size = reader.ReadUInt32(); + //var compressedSize = reader.ReadUInt32(); + //var bitPerPixel = reader.ReadUInt16(); + //var planes = reader.ReadUInt16(); + + // Raw RGB bitmap + if (format == 0) + { + //Image = new Bitmap((int)width, (int)height, PixelFormat.Format24bppRgb); + } + // JPEG bitmap + else if (format == 1) + { + byte[] imgData = reader.ReadBytes(numBytes - HEADER_LENGTH); + using (MemoryStream stream = new MemoryStream(imgData)) + { + //var bitmap = new Bitmap(stream); + //Image = (Bitmap)bitmap.Clone(); + } + + // Reverse BGR pixels from old thumbnail format + if (id == ResourceID.ThumbnailBgr) + { + //for(int y=0;y - /// The names of the alpha channels. - /// - internal class UnicodeAlphaNames : ImageResource - { - public override ResourceID ID - { - get { return ResourceID.UnicodeAlphaNames; } - } - - private List channelNames = new List(); - public List ChannelNames - { - get { return channelNames; } - } - - public UnicodeAlphaNames() - : base(String.Empty) - { - } - - public UnicodeAlphaNames(PsdBinaryReader reader, string name, int resourceDataLength) - : base(name) - { - var endPosition = reader.BaseStream.Position + resourceDataLength; - - while (reader.BaseStream.Position < endPosition) - { - var channelName = reader.ReadUnicodeString(); - - // Photoshop writes out a null terminator for Unicode alpha names. - // There is no null terminator on other Unicode strings in PSD files. - if (channelName.EndsWith("\0")) - { - channelName = channelName.Substring(0, channelName.Length - 1); - } - ChannelNames.Add(channelName); - } - } - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2014 Tao Yue +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Collections.Generic; + +namespace PhotoshopFile +{ + /// + /// The names of the alpha channels. + /// + internal class UnicodeAlphaNames : ImageResource + { + public override ResourceID ID + { + get { return ResourceID.UnicodeAlphaNames; } + } + + private List channelNames = new List(); + public List ChannelNames + { + get { return channelNames; } + } + + public UnicodeAlphaNames() + : base(String.Empty) + { + } + + public UnicodeAlphaNames(PsdBinaryReader reader, string name, int resourceDataLength) + : base(name) + { + var endPosition = reader.BaseStream.Position + resourceDataLength; + + while (reader.BaseStream.Position < endPosition) + { + var channelName = reader.ReadUnicodeString(); + + // Photoshop writes out a null terminator for Unicode alpha names. + // There is no null terminator on other Unicode strings in PSD files. + if (channelName.EndsWith("\0")) + { + channelName = channelName.Substring(0, channelName.Length - 1); + } + ChannelNames.Add(channelName); + } + } + } +} diff --git a/Editor/PSDPlugin/PsdFile/ImageResources/UnicodeAlphaNames.cs.meta b/Editor/PSDPlugin/PsdFile/ImageResources/UnicodeAlphaNames.cs.meta index a715a46..08d54c5 100644 --- a/Editor/PSDPlugin/PsdFile/ImageResources/UnicodeAlphaNames.cs.meta +++ b/Editor/PSDPlugin/PsdFile/ImageResources/UnicodeAlphaNames.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 8ba836b7a6b0c9a4a94c1d6c540b8962 -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 8ba836b7a6b0c9a4a94c1d6c540b8962 +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/ImageResources/VersionInfo.cs b/Editor/PSDPlugin/PsdFile/ImageResources/VersionInfo.cs index 3e1e787..78796d6 100644 --- a/Editor/PSDPlugin/PsdFile/ImageResources/VersionInfo.cs +++ b/Editor/PSDPlugin/PsdFile/ImageResources/VersionInfo.cs @@ -1,53 +1,53 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2012 Tao Yue -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace PhotoshopFile -{ - internal class VersionInfo : ImageResource - { - public override ResourceID ID - { - get { return ResourceID.VersionInfo; } - } - - public UInt32 Version { get; set; } - - public bool HasRealMergedData { get; set; } - - public string ReaderName { get; set; } - - public string WriterName { get; set; } - - public UInt32 FileVersion { get; set; } - - - public VersionInfo() : base(String.Empty) - { - } - - public VersionInfo(PsdBinaryReader reader, string name) - : base(name) - { - Version = reader.ReadUInt32(); - HasRealMergedData = reader.ReadBoolean(); - ReaderName = reader.ReadUnicodeString(); - WriterName = reader.ReadUnicodeString(); - FileVersion = reader.ReadUInt32(); - } - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2012 Tao Yue +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace PhotoshopFile +{ + internal class VersionInfo : ImageResource + { + public override ResourceID ID + { + get { return ResourceID.VersionInfo; } + } + + public UInt32 Version { get; set; } + + public bool HasRealMergedData { get; set; } + + public string ReaderName { get; set; } + + public string WriterName { get; set; } + + public UInt32 FileVersion { get; set; } + + + public VersionInfo() : base(String.Empty) + { + } + + public VersionInfo(PsdBinaryReader reader, string name) + : base(name) + { + Version = reader.ReadUInt32(); + HasRealMergedData = reader.ReadBoolean(); + ReaderName = reader.ReadUnicodeString(); + WriterName = reader.ReadUnicodeString(); + FileVersion = reader.ReadUInt32(); + } + } +} diff --git a/Editor/PSDPlugin/PsdFile/ImageResources/VersionInfo.cs.meta b/Editor/PSDPlugin/PsdFile/ImageResources/VersionInfo.cs.meta index 23105d0..3a2e7d1 100644 --- a/Editor/PSDPlugin/PsdFile/ImageResources/VersionInfo.cs.meta +++ b/Editor/PSDPlugin/PsdFile/ImageResources/VersionInfo.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 948f26d9a8b009540b6574d5b592248d -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 948f26d9a8b009540b6574d5b592248d +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/Layers.meta b/Editor/PSDPlugin/PsdFile/Layers.meta index eb3f3a3..3681cfd 100644 --- a/Editor/PSDPlugin/PsdFile/Layers.meta +++ b/Editor/PSDPlugin/PsdFile/Layers.meta @@ -1,9 +1,9 @@ -fileFormatVersion: 2 -guid: a2b81847c6b672747861b07e47320717 -folderAsset: yes -timeCreated: 1495006553 -licenseType: Pro -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: a2b81847c6b672747861b07e47320717 +folderAsset: yes +timeCreated: 1495006553 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/Layers/BlendingRanges.cs b/Editor/PSDPlugin/PsdFile/Layers/BlendingRanges.cs index c62dc86..bfc784d 100644 --- a/Editor/PSDPlugin/PsdFile/Layers/BlendingRanges.cs +++ b/Editor/PSDPlugin/PsdFile/Layers/BlendingRanges.cs @@ -1,56 +1,56 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2014 Tao Yue -// -// Portions of this file are provided under the BSD 3-clause License: -// Copyright (c) 2006, Jonas Beckeman -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using System.Diagnostics; -using System.Globalization; - -namespace PhotoshopFile -{ - internal class BlendingRanges - { - /// - /// The layer to which this channel belongs - /// - public Layer Layer { get; private set; } - - public byte[] Data { get; set; } - - /////////////////////////////////////////////////////////////////////////// - - public BlendingRanges(Layer layer) - { - Layer = layer; - Data = new byte[0]; - } - - /////////////////////////////////////////////////////////////////////////// - - public BlendingRanges(PsdBinaryReader reader, Layer layer) - { - Util.DebugMessage(reader.BaseStream, "Load, Begin, BlendingRanges"); - - Layer = layer; - var dataLength = reader.ReadInt32(); - if (dataLength <= 0) - return; - - Data = reader.ReadBytes(dataLength); - - Util.DebugMessage(reader.BaseStream, "Load, End, BlendingRanges"); - } - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2014 Tao Yue +// +// Portions of this file are provided under the BSD 3-clause License: +// Copyright (c) 2006, Jonas Beckeman +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Diagnostics; +using System.Globalization; + +namespace PhotoshopFile +{ + internal class BlendingRanges + { + /// + /// The layer to which this channel belongs + /// + public Layer Layer { get; private set; } + + public byte[] Data { get; set; } + + /////////////////////////////////////////////////////////////////////////// + + public BlendingRanges(Layer layer) + { + Layer = layer; + Data = new byte[0]; + } + + /////////////////////////////////////////////////////////////////////////// + + public BlendingRanges(PsdBinaryReader reader, Layer layer) + { + Util.DebugMessage(reader.BaseStream, "Load, Begin, BlendingRanges"); + + Layer = layer; + var dataLength = reader.ReadInt32(); + if (dataLength <= 0) + return; + + Data = reader.ReadBytes(dataLength); + + Util.DebugMessage(reader.BaseStream, "Load, End, BlendingRanges"); + } + } +} diff --git a/Editor/PSDPlugin/PsdFile/Layers/BlendingRanges.cs.meta b/Editor/PSDPlugin/PsdFile/Layers/BlendingRanges.cs.meta index af10960..52d120b 100644 --- a/Editor/PSDPlugin/PsdFile/Layers/BlendingRanges.cs.meta +++ b/Editor/PSDPlugin/PsdFile/Layers/BlendingRanges.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 9f4a47927e764174fa3984b07f9d4b58 -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 9f4a47927e764174fa3984b07f9d4b58 +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/Layers/Channel.cs b/Editor/PSDPlugin/PsdFile/Layers/Channel.cs index 0e49d48..f35a350 100644 --- a/Editor/PSDPlugin/PsdFile/Layers/Channel.cs +++ b/Editor/PSDPlugin/PsdFile/Layers/Channel.cs @@ -1,232 +1,232 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2016 Tao Yue -// -// Portions of this file are provided under the BSD 3-clause License: -// Copyright (c) 2006, Jonas Beckeman -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using PDNWrapper; -using System.Linq; -using Unity.Collections; -using PhotoshopFile.Compression; - -namespace PhotoshopFile -{ - internal class ChannelList : List - { - /// - /// Returns channels with nonnegative IDs as an array, so that accessing - /// a channel by Id can be optimized into pointer arithmetic rather than - /// being implemented as a List scan. - /// - /// - /// This optimization is crucial for blitting lots of pixels back and - /// forth between Photoshop's per-channel representation, and Paint.NET's - /// per-pixel BGRA representation. - /// - public Channel[] ToIdArray() - { - var maxId = this.Max(x => x.ID); - var idArray = new Channel[maxId + 1]; - foreach (var channel in this) - { - if (channel.ID >= 0) - idArray[channel.ID] = channel; - } - return idArray; - } - - public ChannelList() - : base() - { - } - - public Channel GetId(int id) - { - return this.Single(x => x.ID == id); - } - - public bool ContainsId(int id) - { - return this.Exists(x => x.ID == id); - } - } - - /////////////////////////////////////////////////////////////////////////// - - [DebuggerDisplay("ID = {ID}")] - internal class Channel - { - /// - /// The layer to which this channel belongs - /// - public Layer Layer { get; private set; } - - /// - /// Channel ID. - /// - /// -1 = transparency mask - /// -2 = user-supplied layer mask, or vector mask - /// -3 = user-supplied layer mask, if channel -2 contains a vector mask - /// - /// Nonnegative channel IDs give the actual image channels, in the - /// order defined by the colormode. For example, 0, 1, 2 = R, G, B. - /// - /// - /// - public short ID { get; set; } - - public Rectangle Rect - { - get - { - switch (ID) - { - case -2: - return Layer.Masks.LayerMask.Rect; - case -3: - return Layer.Masks.UserMask.Rect; - default: - return Layer.Rect; - } - } - } - - /// - /// Total length of the channel data, including compression headers. - /// - public long Length { get; set; } - - /// - /// Raw image data for this color channel, in compressed on-disk format. - /// - /// - /// If null, the ImageData will be automatically compressed during save. - /// - public byte[] ImageDataRaw { get; set; } - - /// - /// Decompressed image data for this color channel. - /// - /// - /// When making changes to the ImageData, set ImageDataRaw to null so that - /// the correct data will be compressed during save. - /// - public NativeArray ImageData { get; set; } - - /// - /// Image compression method used. - /// - public ImageCompression ImageCompression { get; set; } - - /// - /// RLE-compressed length of each row. - /// - public RleRowLengths RleRowLengths { get; set; } - - ////////////////////////////////////////////////////////////////// - - internal Channel(short id, Layer layer) - { - ID = id; - Layer = layer; - } - - internal Channel(PsdBinaryReader reader, Layer layer) - { - Util.DebugMessage(reader.BaseStream, "Load, Begin, Channel"); - - ID = reader.ReadInt16(); - Length = (layer.PsdFile.IsLargeDocument) - ? reader.ReadInt64() - : reader.ReadInt32(); - Layer = layer; - - Util.DebugMessage(reader.BaseStream, "Load, End, Channel, {0}", ID); - } - - internal void Cleanup() - { - if (ImageData.IsCreated) - ImageData.Dispose(); - } - ////////////////////////////////////////////////////////////////// - - internal void LoadPixelData(PsdBinaryReader reader) - { - Util.DebugMessage(reader.BaseStream, "Load, Begin, Channel image"); - - if (Length == 0) - { - ImageCompression = ImageCompression.Raw; - ImageDataRaw = new byte[0]; - return; - } - - var endPosition = reader.BaseStream.Position + this.Length; - ImageCompression = (ImageCompression)reader.ReadInt16(); - var longDataLength = this.Length - 2; - Util.CheckByteArrayLength(longDataLength); - var dataLength = (int)longDataLength; - - switch (ImageCompression) - { - case ImageCompression.Raw: - ImageDataRaw = reader.ReadBytes(dataLength); - break; - case ImageCompression.Rle: - // RLE row lengths - RleRowLengths = new RleRowLengths(reader, Rect.Height, Layer.PsdFile.IsLargeDocument); - var rleDataLength = (int)(endPosition - reader.BaseStream.Position); - Debug.Assert(rleDataLength == RleRowLengths.Total, - "RLE row lengths do not sum to length of channel image data."); - - // The PSD specification states that rows are padded to even sizes. - // However, Photoshop doesn't actually do this. RLE rows can have - // odd lengths in the header, and there is no padding between rows. - ImageDataRaw = reader.ReadBytes(rleDataLength); - break; - case ImageCompression.Zip: - case ImageCompression.ZipPrediction: - ImageDataRaw = reader.ReadBytes(dataLength); - break; - } - - Util.DebugMessage(reader.BaseStream, "Load, End, Channel image, {0}", ID, Layer.Name); - Debug.Assert(reader.BaseStream.Position == endPosition, "Pixel data was not fully read in."); - } - - /// - /// Decodes the raw image data from the compressed on-disk format into - /// an uncompressed bitmap, in native byte order. - /// - public void DecodeImageData() - { - if ((ImageCompression == ImageCompression.Raw) && (Layer.PsdFile.BitDepth <= 8)) - { - ImageData = new NativeArray(ImageDataRaw, Allocator.TempJob); - return; - } - - var image = ImageDataFactory.Create(this, ImageDataRaw); - var longLength = (long)image.BytesPerRow * Rect.Height; - Util.CheckByteArrayLength(longLength); - var LocalImageData = new byte[longLength]; - image.Read(LocalImageData); - ImageData = new NativeArray(LocalImageData, Allocator.TempJob); - ImageDataRaw = null; // no longer needed. - } - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2016 Tao Yue +// +// Portions of this file are provided under the BSD 3-clause License: +// Copyright (c) 2006, Jonas Beckeman +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using PDNWrapper; +using System.Linq; +using Unity.Collections; +using PhotoshopFile.Compression; + +namespace PhotoshopFile +{ + internal class ChannelList : List + { + /// + /// Returns channels with nonnegative IDs as an array, so that accessing + /// a channel by Id can be optimized into pointer arithmetic rather than + /// being implemented as a List scan. + /// + /// + /// This optimization is crucial for blitting lots of pixels back and + /// forth between Photoshop's per-channel representation, and Paint.NET's + /// per-pixel BGRA representation. + /// + public Channel[] ToIdArray() + { + var maxId = this.Max(x => x.ID); + var idArray = new Channel[maxId + 1]; + foreach (var channel in this) + { + if (channel.ID >= 0) + idArray[channel.ID] = channel; + } + return idArray; + } + + public ChannelList() + : base() + { + } + + public Channel GetId(int id) + { + return this.Single(x => x.ID == id); + } + + public bool ContainsId(int id) + { + return this.Exists(x => x.ID == id); + } + } + + /////////////////////////////////////////////////////////////////////////// + + [DebuggerDisplay("ID = {ID}")] + internal class Channel + { + /// + /// The layer to which this channel belongs + /// + public Layer Layer { get; private set; } + + /// + /// Channel ID. + /// + /// -1 = transparency mask + /// -2 = user-supplied layer mask, or vector mask + /// -3 = user-supplied layer mask, if channel -2 contains a vector mask + /// + /// Nonnegative channel IDs give the actual image channels, in the + /// order defined by the colormode. For example, 0, 1, 2 = R, G, B. + /// + /// + /// + public short ID { get; set; } + + public Rectangle Rect + { + get + { + switch (ID) + { + case -2: + return Layer.Masks.LayerMask.Rect; + case -3: + return Layer.Masks.UserMask.Rect; + default: + return Layer.Rect; + } + } + } + + /// + /// Total length of the channel data, including compression headers. + /// + public long Length { get; set; } + + /// + /// Raw image data for this color channel, in compressed on-disk format. + /// + /// + /// If null, the ImageData will be automatically compressed during save. + /// + public byte[] ImageDataRaw { get; set; } + + /// + /// Decompressed image data for this color channel. + /// + /// + /// When making changes to the ImageData, set ImageDataRaw to null so that + /// the correct data will be compressed during save. + /// + public NativeArray ImageData { get; set; } + + /// + /// Image compression method used. + /// + public ImageCompression ImageCompression { get; set; } + + /// + /// RLE-compressed length of each row. + /// + public RleRowLengths RleRowLengths { get; set; } + + ////////////////////////////////////////////////////////////////// + + internal Channel(short id, Layer layer) + { + ID = id; + Layer = layer; + } + + internal Channel(PsdBinaryReader reader, Layer layer) + { + Util.DebugMessage(reader.BaseStream, "Load, Begin, Channel"); + + ID = reader.ReadInt16(); + Length = (layer.PsdFile.IsLargeDocument) + ? reader.ReadInt64() + : reader.ReadInt32(); + Layer = layer; + + Util.DebugMessage(reader.BaseStream, "Load, End, Channel, {0}", ID); + } + + internal void Cleanup() + { + if (ImageData.IsCreated) + ImageData.Dispose(); + } + ////////////////////////////////////////////////////////////////// + + internal void LoadPixelData(PsdBinaryReader reader) + { + Util.DebugMessage(reader.BaseStream, "Load, Begin, Channel image"); + + if (Length == 0) + { + ImageCompression = ImageCompression.Raw; + ImageDataRaw = new byte[0]; + return; + } + + var endPosition = reader.BaseStream.Position + this.Length; + ImageCompression = (ImageCompression)reader.ReadInt16(); + var longDataLength = this.Length - 2; + Util.CheckByteArrayLength(longDataLength); + var dataLength = (int)longDataLength; + + switch (ImageCompression) + { + case ImageCompression.Raw: + ImageDataRaw = reader.ReadBytes(dataLength); + break; + case ImageCompression.Rle: + // RLE row lengths + RleRowLengths = new RleRowLengths(reader, Rect.Height, Layer.PsdFile.IsLargeDocument); + var rleDataLength = (int)(endPosition - reader.BaseStream.Position); + Debug.Assert(rleDataLength == RleRowLengths.Total, + "RLE row lengths do not sum to length of channel image data."); + + // The PSD specification states that rows are padded to even sizes. + // However, Photoshop doesn't actually do this. RLE rows can have + // odd lengths in the header, and there is no padding between rows. + ImageDataRaw = reader.ReadBytes(rleDataLength); + break; + case ImageCompression.Zip: + case ImageCompression.ZipPrediction: + ImageDataRaw = reader.ReadBytes(dataLength); + break; + } + + Util.DebugMessage(reader.BaseStream, "Load, End, Channel image, {0}", ID, Layer.Name); + Debug.Assert(reader.BaseStream.Position == endPosition, "Pixel data was not fully read in."); + } + + /// + /// Decodes the raw image data from the compressed on-disk format into + /// an uncompressed bitmap, in native byte order. + /// + public void DecodeImageData() + { + if ((ImageCompression == ImageCompression.Raw) && (Layer.PsdFile.BitDepth <= 8)) + { + ImageData = new NativeArray(ImageDataRaw, Allocator.TempJob); + return; + } + + var image = ImageDataFactory.Create(this, ImageDataRaw); + var longLength = (long)image.BytesPerRow * Rect.Height; + Util.CheckByteArrayLength(longLength); + var LocalImageData = new byte[longLength]; + image.Read(LocalImageData); + ImageData = new NativeArray(LocalImageData, Allocator.TempJob); + ImageDataRaw = null; // no longer needed. + } + } +} diff --git a/Editor/PSDPlugin/PsdFile/Layers/Channel.cs.meta b/Editor/PSDPlugin/PsdFile/Layers/Channel.cs.meta index db7841f..22be46b 100644 --- a/Editor/PSDPlugin/PsdFile/Layers/Channel.cs.meta +++ b/Editor/PSDPlugin/PsdFile/Layers/Channel.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: c12f761461a76f44eab4f22f85e988b1 -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: c12f761461a76f44eab4f22f85e988b1 +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/Layers/Layer.cs b/Editor/PSDPlugin/PsdFile/Layers/Layer.cs index 59a6e42..f46354c 100644 --- a/Editor/PSDPlugin/PsdFile/Layers/Layer.cs +++ b/Editor/PSDPlugin/PsdFile/Layers/Layer.cs @@ -1,240 +1,240 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2016 Tao Yue -// -// Portions of this file are provided under the BSD 3-clause License: -// Copyright (c) 2006, Jonas Beckeman -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Diagnostics; -using PDNWrapper; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Threading; -using Unity.Collections; -using Unity.Collections.LowLevel.Unsafe; - -namespace PhotoshopFile -{ - [DebuggerDisplay("Name = {Name}")] - internal class Layer - { - internal PsdFile PsdFile { get; private set; } - - /// - /// The rectangle containing the contents of the layer. - /// - public Rectangle Rect { get; set; } - - public bool IsGroup { get; set; } - public bool IsEndGroupMarker { get; set; } - public Layer ParentLayer {get; set; } - // ID from Key "lyid" - public int LayerID { get; set; } - - /// - /// Image channels. - /// - public ChannelList Channels { get; private set; } - - /// - /// Returns alpha channel if it exists, otherwise null. - /// - public Channel AlphaChannel - { - get - { - if (Channels.ContainsId(-1)) - return Channels.GetId(-1); - else - return null; - } - } - - private string blendModeKey; - /// - /// Photoshop blend mode key for the layer - /// - public string BlendModeKey - { - get { return blendModeKey; } - set - { - if (value.Length != 4) - { - throw new ArgumentException( - "BlendModeKey must be 4 characters in length."); - } - blendModeKey = value; - } - } - - /// - /// 0 = transparent ... 255 = opaque - /// - public byte Opacity { get; set; } - - /// - /// false = base, true = non-base - /// - public bool Clipping { get; set; } - - private static int protectTransBit = BitVector32.CreateMask(); - private static int visibleBit = BitVector32.CreateMask(protectTransBit); - BitVector32 flags = new BitVector32(); - - /// - /// If true, the layer is visible. - /// - public bool Visible - { - get { return !flags[visibleBit]; } - set { flags[visibleBit] = !value; } - } - - /// - /// Protect the transparency - /// - public bool ProtectTrans - { - get { return flags[protectTransBit]; } - set { flags[protectTransBit] = value; } - } - - /// - /// The descriptive layer name - /// - public string Name { get; set; } - - public BlendingRanges BlendingRangesData { get; set; } - - public MaskInfo Masks { get; set; } - - public List AdditionalInfo { get; set; } - - /////////////////////////////////////////////////////////////////////////// - - public Layer(PsdFile psdFile) - { - PsdFile = psdFile; - Rect = Rectangle.Empty; - Channels = new ChannelList(); - BlendModeKey = PsdBlendMode.Normal; - AdditionalInfo = new List(); - IsGroup = false; - ParentLayer = null; - IsEndGroupMarker = false; - } - - public Layer(PsdBinaryReader reader, PsdFile psdFile) - : this(psdFile) - { - Util.DebugMessage(reader.BaseStream, "Load, Begin, Layer"); - - Rect = reader.ReadRectangle(); - - //----------------------------------------------------------------------- - // Read channel headers. Image data comes later, after the layer header. - - int numberOfChannels = reader.ReadUInt16(); - for (int channel = 0; channel < numberOfChannels; channel++) - { - var ch = new Channel(reader, this); - Channels.Add(ch); - } - - //----------------------------------------------------------------------- - // - - var signature = reader.ReadAsciiChars(4); - if (signature != "8BIM") - throw (new PsdInvalidException("Invalid signature in layer header.")); - - BlendModeKey = reader.ReadAsciiChars(4); - Opacity = reader.ReadByte(); - Clipping = reader.ReadBoolean(); - - var flagsByte = reader.ReadByte(); - flags = new BitVector32(flagsByte); - reader.ReadByte(); //padding - - //----------------------------------------------------------------------- - - // This is the total size of the MaskData, the BlendingRangesData, the - // Name and the AdjustmentLayerInfo. - var extraDataSize = reader.ReadUInt32(); - var extraDataStartPosition = reader.BaseStream.Position; - - Masks = new MaskInfo(reader, this); - BlendingRangesData = new BlendingRanges(reader, this); - Name = reader.ReadPascalString(4); - - //----------------------------------------------------------------------- - // Process Additional Layer Information - - long adjustmentLayerEndPos = extraDataStartPosition + extraDataSize; - while (reader.BaseStream.Position < adjustmentLayerEndPos) - { - var layerInfo = LayerInfoFactory.Load(reader, this.PsdFile, false, adjustmentLayerEndPos); - AdditionalInfo.Add(layerInfo); - } - - foreach (var adjustmentInfo in AdditionalInfo) - { - switch (adjustmentInfo.Key) - { - case "luni": - Name = ((LayerUnicodeName)adjustmentInfo).Name; - break; - case "lyid": - LayerID = ((LayerId)adjustmentInfo).ID; - break; - } - } - - Util.DebugMessage(reader.BaseStream, "Load, End, Layer, {0}", Name); - - PsdFile.LoadContext.OnLoadLayerHeader(this); - } - - /////////////////////////////////////////////////////////////////////////// - - /// - /// Create ImageData for any missing channels. - /// - public void CreateMissingChannels() - { - var channelCount = this.PsdFile.ColorMode.MinChannelCount(); - for (short id = 0; id < channelCount; id++) - { - if (!this.Channels.ContainsId(id)) - { - var size = this.Rect.Height * this.Rect.Width; - - var ch = new Channel(id, this); - ch.ImageData = new NativeArray(size, Allocator.TempJob); - unsafe - { - UnsafeUtility.MemSet(ch.ImageData.GetUnsafePtr(), (byte)255, size); - } - this.Channels.Add(ch); - } - } - } - - /////////////////////////////////////////////////////////////////////////// - - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2016 Tao Yue +// +// Portions of this file are provided under the BSD 3-clause License: +// Copyright (c) 2006, Jonas Beckeman +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Diagnostics; +using PDNWrapper; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Threading; +using Unity.Collections; +using Unity.Collections.LowLevel.Unsafe; + +namespace PhotoshopFile +{ + [DebuggerDisplay("Name = {Name}")] + internal class Layer + { + internal PsdFile PsdFile { get; private set; } + + /// + /// The rectangle containing the contents of the layer. + /// + public Rectangle Rect { get; set; } + + public bool IsGroup { get; set; } + public bool IsEndGroupMarker { get; set; } + public Layer ParentLayer {get; set; } + // ID from Key "lyid" + public int LayerID { get; set; } + + /// + /// Image channels. + /// + public ChannelList Channels { get; private set; } + + /// + /// Returns alpha channel if it exists, otherwise null. + /// + public Channel AlphaChannel + { + get + { + if (Channels.ContainsId(-1)) + return Channels.GetId(-1); + else + return null; + } + } + + private string blendModeKey; + /// + /// Photoshop blend mode key for the layer + /// + public string BlendModeKey + { + get { return blendModeKey; } + set + { + if (value.Length != 4) + { + throw new ArgumentException( + "BlendModeKey must be 4 characters in length."); + } + blendModeKey = value; + } + } + + /// + /// 0 = transparent ... 255 = opaque + /// + public byte Opacity { get; set; } + + /// + /// false = base, true = non-base + /// + public bool Clipping { get; set; } + + private static int protectTransBit = BitVector32.CreateMask(); + private static int visibleBit = BitVector32.CreateMask(protectTransBit); + BitVector32 flags = new BitVector32(); + + /// + /// If true, the layer is visible. + /// + public bool Visible + { + get { return !flags[visibleBit]; } + set { flags[visibleBit] = !value; } + } + + /// + /// Protect the transparency + /// + public bool ProtectTrans + { + get { return flags[protectTransBit]; } + set { flags[protectTransBit] = value; } + } + + /// + /// The descriptive layer name + /// + public string Name { get; set; } + + public BlendingRanges BlendingRangesData { get; set; } + + public MaskInfo Masks { get; set; } + + public List AdditionalInfo { get; set; } + + /////////////////////////////////////////////////////////////////////////// + + public Layer(PsdFile psdFile) + { + PsdFile = psdFile; + Rect = Rectangle.Empty; + Channels = new ChannelList(); + BlendModeKey = PsdBlendMode.Normal; + AdditionalInfo = new List(); + IsGroup = false; + ParentLayer = null; + IsEndGroupMarker = false; + } + + public Layer(PsdBinaryReader reader, PsdFile psdFile) + : this(psdFile) + { + Util.DebugMessage(reader.BaseStream, "Load, Begin, Layer"); + + Rect = reader.ReadRectangle(); + + //----------------------------------------------------------------------- + // Read channel headers. Image data comes later, after the layer header. + + int numberOfChannels = reader.ReadUInt16(); + for (int channel = 0; channel < numberOfChannels; channel++) + { + var ch = new Channel(reader, this); + Channels.Add(ch); + } + + //----------------------------------------------------------------------- + // + + var signature = reader.ReadAsciiChars(4); + if (signature != "8BIM") + throw (new PsdInvalidException("Invalid signature in layer header.")); + + BlendModeKey = reader.ReadAsciiChars(4); + Opacity = reader.ReadByte(); + Clipping = reader.ReadBoolean(); + + var flagsByte = reader.ReadByte(); + flags = new BitVector32(flagsByte); + reader.ReadByte(); //padding + + //----------------------------------------------------------------------- + + // This is the total size of the MaskData, the BlendingRangesData, the + // Name and the AdjustmentLayerInfo. + var extraDataSize = reader.ReadUInt32(); + var extraDataStartPosition = reader.BaseStream.Position; + + Masks = new MaskInfo(reader, this); + BlendingRangesData = new BlendingRanges(reader, this); + Name = reader.ReadPascalString(4); + + //----------------------------------------------------------------------- + // Process Additional Layer Information + + long adjustmentLayerEndPos = extraDataStartPosition + extraDataSize; + while (reader.BaseStream.Position < adjustmentLayerEndPos) + { + var layerInfo = LayerInfoFactory.Load(reader, this.PsdFile, false, adjustmentLayerEndPos); + AdditionalInfo.Add(layerInfo); + } + + foreach (var adjustmentInfo in AdditionalInfo) + { + switch (adjustmentInfo.Key) + { + case "luni": + Name = ((LayerUnicodeName)adjustmentInfo).Name; + break; + case "lyid": + LayerID = ((LayerId)adjustmentInfo).ID; + break; + } + } + + Util.DebugMessage(reader.BaseStream, "Load, End, Layer, {0}", Name); + + PsdFile.LoadContext.OnLoadLayerHeader(this); + } + + /////////////////////////////////////////////////////////////////////////// + + /// + /// Create ImageData for any missing channels. + /// + public void CreateMissingChannels() + { + var channelCount = this.PsdFile.ColorMode.MinChannelCount(); + for (short id = 0; id < channelCount; id++) + { + if (!this.Channels.ContainsId(id)) + { + var size = this.Rect.Height * this.Rect.Width; + + var ch = new Channel(id, this); + ch.ImageData = new NativeArray(size, Allocator.TempJob); + unsafe + { + UnsafeUtility.MemSet(ch.ImageData.GetUnsafePtr(), (byte)255, size); + } + this.Channels.Add(ch); + } + } + } + + /////////////////////////////////////////////////////////////////////////// + + } +} diff --git a/Editor/PSDPlugin/PsdFile/Layers/Layer.cs.meta b/Editor/PSDPlugin/PsdFile/Layers/Layer.cs.meta index 03d1c5c..17aac1b 100644 --- a/Editor/PSDPlugin/PsdFile/Layers/Layer.cs.meta +++ b/Editor/PSDPlugin/PsdFile/Layers/Layer.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 2dff4719950c8914097f7b77c9b07de9 -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 2dff4719950c8914097f7b77c9b07de9 +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/Layers/LayerInfo.cs b/Editor/PSDPlugin/PsdFile/Layers/LayerInfo.cs index f1af051..f984202 100644 --- a/Editor/PSDPlugin/PsdFile/Layers/LayerInfo.cs +++ b/Editor/PSDPlugin/PsdFile/Layers/LayerInfo.cs @@ -1,168 +1,168 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2016 Tao Yue -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using System.Diagnostics; -using System.IO; - -namespace PhotoshopFile -{ - internal static class LayerInfoFactory - { - /// - /// Loads the next LayerInfo record. - /// - /// The file reader - /// The PSD file. - /// True if the LayerInfo record is being - /// loaded from the end of the Layer and Mask Information section; - /// false if it is being loaded from the end of a Layer record. - public static LayerInfo Load(PsdBinaryReader reader, PsdFile psdFile, - bool globalLayerInfo, long fileEndPos) - { - Util.DebugMessage(reader.BaseStream, "Load, Begin, LayerInfo"); - - // Some keys use a signature of 8B64, but the identity of these keys - // is undocumented. We will therefore accept either signature. - var signature = reader.ReadAsciiChars(4); - if ((signature != "8BIM") && (signature != "8B64")) - { - throw new PsdInvalidException( - "LayerInfo signature invalid, must be 8BIM or 8B64."); - } - - var key = reader.ReadAsciiChars(4); - var hasLongLength = LayerInfoUtil.HasLongLength(key, psdFile.IsLargeDocument); - LayerInfo result = new RawLayerInfo("dummy"); - bool breakFromLoop = false; - while (!breakFromLoop) - { - var baseStartPosition = reader.BaseStream.Position; - var length = hasLongLength - ? reader.ReadInt64() - : reader.ReadInt32(); - var startPosition = reader.BaseStream.Position; - - - switch (key) - { - case "Layr": - case "Lr16": - case "Lr32": - result = new InfoLayers(reader, psdFile, key, length); - break; - case "lsct": - case "lsdk": - result = new LayerSectionInfo(reader, key, (int)length); - break; - case "luni": - result = new LayerUnicodeName(reader); - break; - case "lyid": - result = new LayerId(reader, key, length); - break; - default: - result = new RawLayerInfo(reader, signature, key, length); - break; - } - - // May have additional padding applied. - var endPosition = startPosition + length; - if (reader.BaseStream.Position < endPosition) - reader.BaseStream.Position = endPosition; - - // Documentation states that the length is even-padded. Actually: - // 1. Most keys have 4-padded lengths. - // 2. However, some keys (LMsk) have even-padded lengths. - // 3. Other keys (Txt2, Lr16, Lr32) have unpadded lengths. - // - // Photoshop writes data that is always 4-padded, even when the stated - // length is not a multiple of 4. The length mismatch seems to occur - // only on global layer info. We do not read extra padding in other - // cases because third-party programs are likely to follow the spec. - - if (globalLayerInfo) - { - reader.ReadPadding(startPosition, 4); - } - - //try if we can read the next signature - if (reader.BaseStream.Position < fileEndPos) - { - var nowPosition = reader.BaseStream.Position; - signature = reader.ReadAsciiChars(4); - if ((signature != "8BIM") && (signature != "8B64")) - { - hasLongLength = true; - reader.BaseStream.Position = baseStartPosition; - } - else - { - reader.BaseStream.Position = nowPosition; - breakFromLoop = true; - } - } - else - breakFromLoop = true; - } - - - Util.DebugMessage(reader.BaseStream, "Load, End, LayerInfo, {0}, {1}", - result.Signature, result.Key); - return result; - } - } - - internal static class LayerInfoUtil - { - internal static bool HasLongLength(string key, bool isLargeDocument) - { - if (!isLargeDocument) - { - return false; - } - //return false; - - switch (key) - { - case "LMsk": - case "Lr16": - case "Lr32": - case "Layr": - case "Mt16": - case "Mt32": - case "Mtrn": - case "Alph": - case "FMsk": - case "lnk2": - case "FEid": - case "FXid": - case "PxSD": - case "lnkE": // Undocumented - case "extn": // Undocumented - case "cinf": // Undocumented - return true; - - default: - return false; - } - } - } - - internal abstract class LayerInfo - { - public abstract string Signature { get; } - - public abstract string Key { get; } - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2016 Tao Yue +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Diagnostics; +using System.IO; + +namespace PhotoshopFile +{ + internal static class LayerInfoFactory + { + /// + /// Loads the next LayerInfo record. + /// + /// The file reader + /// The PSD file. + /// True if the LayerInfo record is being + /// loaded from the end of the Layer and Mask Information section; + /// false if it is being loaded from the end of a Layer record. + public static LayerInfo Load(PsdBinaryReader reader, PsdFile psdFile, + bool globalLayerInfo, long fileEndPos) + { + Util.DebugMessage(reader.BaseStream, "Load, Begin, LayerInfo"); + + // Some keys use a signature of 8B64, but the identity of these keys + // is undocumented. We will therefore accept either signature. + var signature = reader.ReadAsciiChars(4); + if ((signature != "8BIM") && (signature != "8B64")) + { + throw new PsdInvalidException( + "LayerInfo signature invalid, must be 8BIM or 8B64."); + } + + var key = reader.ReadAsciiChars(4); + var hasLongLength = LayerInfoUtil.HasLongLength(key, psdFile.IsLargeDocument); + LayerInfo result = new RawLayerInfo("dummy"); + bool breakFromLoop = false; + while (!breakFromLoop) + { + var baseStartPosition = reader.BaseStream.Position; + var length = hasLongLength + ? reader.ReadInt64() + : reader.ReadInt32(); + var startPosition = reader.BaseStream.Position; + + + switch (key) + { + case "Layr": + case "Lr16": + case "Lr32": + result = new InfoLayers(reader, psdFile, key, length); + break; + case "lsct": + case "lsdk": + result = new LayerSectionInfo(reader, key, (int)length); + break; + case "luni": + result = new LayerUnicodeName(reader); + break; + case "lyid": + result = new LayerId(reader, key, length); + break; + default: + result = new RawLayerInfo(reader, signature, key, length); + break; + } + + // May have additional padding applied. + var endPosition = startPosition + length; + if (reader.BaseStream.Position < endPosition) + reader.BaseStream.Position = endPosition; + + // Documentation states that the length is even-padded. Actually: + // 1. Most keys have 4-padded lengths. + // 2. However, some keys (LMsk) have even-padded lengths. + // 3. Other keys (Txt2, Lr16, Lr32) have unpadded lengths. + // + // Photoshop writes data that is always 4-padded, even when the stated + // length is not a multiple of 4. The length mismatch seems to occur + // only on global layer info. We do not read extra padding in other + // cases because third-party programs are likely to follow the spec. + + if (globalLayerInfo) + { + reader.ReadPadding(startPosition, 4); + } + + //try if we can read the next signature + if (reader.BaseStream.Position < fileEndPos) + { + var nowPosition = reader.BaseStream.Position; + signature = reader.ReadAsciiChars(4); + if ((signature != "8BIM") && (signature != "8B64")) + { + hasLongLength = true; + reader.BaseStream.Position = baseStartPosition; + } + else + { + reader.BaseStream.Position = nowPosition; + breakFromLoop = true; + } + } + else + breakFromLoop = true; + } + + + Util.DebugMessage(reader.BaseStream, "Load, End, LayerInfo, {0}, {1}", + result.Signature, result.Key); + return result; + } + } + + internal static class LayerInfoUtil + { + internal static bool HasLongLength(string key, bool isLargeDocument) + { + if (!isLargeDocument) + { + return false; + } + //return false; + + switch (key) + { + case "LMsk": + case "Lr16": + case "Lr32": + case "Layr": + case "Mt16": + case "Mt32": + case "Mtrn": + case "Alph": + case "FMsk": + case "lnk2": + case "FEid": + case "FXid": + case "PxSD": + case "lnkE": // Undocumented + case "extn": // Undocumented + case "cinf": // Undocumented + return true; + + default: + return false; + } + } + } + + internal abstract class LayerInfo + { + public abstract string Signature { get; } + + public abstract string Key { get; } + } +} diff --git a/Editor/PSDPlugin/PsdFile/Layers/LayerInfo.cs.meta b/Editor/PSDPlugin/PsdFile/Layers/LayerInfo.cs.meta index 8b538fd..c7745b0 100644 --- a/Editor/PSDPlugin/PsdFile/Layers/LayerInfo.cs.meta +++ b/Editor/PSDPlugin/PsdFile/Layers/LayerInfo.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 5bf52a9b627c3374385cbd0ccc5caacd -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 5bf52a9b627c3374385cbd0ccc5caacd +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/Layers/LayerInfo.meta b/Editor/PSDPlugin/PsdFile/Layers/LayerInfo.meta index a3a3326..407e1fc 100644 --- a/Editor/PSDPlugin/PsdFile/Layers/LayerInfo.meta +++ b/Editor/PSDPlugin/PsdFile/Layers/LayerInfo.meta @@ -1,9 +1,9 @@ -fileFormatVersion: 2 -guid: 45831abf313417241b91683b30dedf45 -folderAsset: yes -timeCreated: 1495006553 -licenseType: Pro -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 45831abf313417241b91683b30dedf45 +folderAsset: yes +timeCreated: 1495006553 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/InfoLayers.cs b/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/InfoLayers.cs index 43c3719..bd5bcce 100644 --- a/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/InfoLayers.cs +++ b/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/InfoLayers.cs @@ -1,87 +1,87 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2016 Tao Yue -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace PhotoshopFile -{ - /// - /// Layers that are stored as Additional Info, rather than in the main - /// Layers section of the PSD file. - /// - /// - /// Photoshop stores layers in the Additional Info section for 16-bit and - /// 32-bit depth images. The Layers section in the PSD file is left empty. - /// - /// This appears to be for backward-compatibility purposes, but it is not - /// required. Photoshop will successfully load a high-bitdepth image that - /// puts the layers in the Layers section. - /// - internal class InfoLayers : LayerInfo - { - public override string Signature - { - get { return "8BIM"; } - } - - private string key; - public override string Key - { - get { return key; } - } - - public PsdFile PsdFile { get; set; } - - public InfoLayers(PsdFile psdFile, string key) - { - PsdFile = psdFile; - - switch (key) - { - // The key does not have to match the bit depth, but it does have to - // be one of the known values. - case "Layr": - case "Lr16": - case "Lr32": - this.key = key; - break; - default: - throw new PsdInvalidException( - "InfoLayers key must be Layr, Lr16, or Lr32."); - } - } - - public InfoLayers(PsdBinaryReader reader, PsdFile psdFile, - string key, long dataLength) - : this(psdFile, key) - { - if (psdFile.Layers.Count > 0) - { - throw new PsdInvalidException( - "Cannot have both regular layers and Additional Info layers"); - } - - var endPosition = reader.BaseStream.Position + dataLength; - psdFile.LoadLayers(reader, false); - - if (reader.BaseStream.Position != endPosition) - { - throw new PsdInvalidException( - "Incorrect length for InfoLayers."); - } - } - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2016 Tao Yue +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace PhotoshopFile +{ + /// + /// Layers that are stored as Additional Info, rather than in the main + /// Layers section of the PSD file. + /// + /// + /// Photoshop stores layers in the Additional Info section for 16-bit and + /// 32-bit depth images. The Layers section in the PSD file is left empty. + /// + /// This appears to be for backward-compatibility purposes, but it is not + /// required. Photoshop will successfully load a high-bitdepth image that + /// puts the layers in the Layers section. + /// + internal class InfoLayers : LayerInfo + { + public override string Signature + { + get { return "8BIM"; } + } + + private string key; + public override string Key + { + get { return key; } + } + + public PsdFile PsdFile { get; set; } + + public InfoLayers(PsdFile psdFile, string key) + { + PsdFile = psdFile; + + switch (key) + { + // The key does not have to match the bit depth, but it does have to + // be one of the known values. + case "Layr": + case "Lr16": + case "Lr32": + this.key = key; + break; + default: + throw new PsdInvalidException( + "InfoLayers key must be Layr, Lr16, or Lr32."); + } + } + + public InfoLayers(PsdBinaryReader reader, PsdFile psdFile, + string key, long dataLength) + : this(psdFile, key) + { + if (psdFile.Layers.Count > 0) + { + throw new PsdInvalidException( + "Cannot have both regular layers and Additional Info layers"); + } + + var endPosition = reader.BaseStream.Position + dataLength; + psdFile.LoadLayers(reader, false); + + if (reader.BaseStream.Position != endPosition) + { + throw new PsdInvalidException( + "Incorrect length for InfoLayers."); + } + } + } +} diff --git a/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/InfoLayers.cs.meta b/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/InfoLayers.cs.meta index b3dc005..15bd023 100644 --- a/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/InfoLayers.cs.meta +++ b/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/InfoLayers.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 81ec2894805ff534395009ab7c13ea4c -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 81ec2894805ff534395009ab7c13ea4c +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/LayerId.cs b/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/LayerId.cs index 5bb0e67..8c5b0a4 100644 --- a/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/LayerId.cs +++ b/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/LayerId.cs @@ -1,71 +1,71 @@ -///////////////////////////////////////////////////////////////////////////////// -// Author : leoyaik@unity3d.com -///////////////////////////////////////////////////////////////////////////////// - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; - -namespace PhotoshopFile -{ - /// - /// Layers that are stored as Additional Info, rather than in the main - /// Layers section of the PSD file. - /// - /// - /// Photoshop stores layers in the Additional Info section for 16-bit and - /// 32-bit depth images. The Layers section in the PSD file is left empty. - /// - /// This appears to be for backward-compatibility purposes, but it is not - /// required. Photoshop will successfully load a high-bitdepth image that - /// puts the layers in the Layers section. - /// - internal class LayerId : LayerInfo - { - public override string Signature - { - get { return "8BIM"; } - } - - private string key; - public override string Key - { - get { return key; } - } - - private int id = 0; - public int ID - { - get { return id; } - } - - - public LayerId(string key) - { - switch (key) - { - // The key does not have to match the bit depth, but it does have to - // be one of the known values. - case "lyid": - case "lnsr": - this.key = key; - break; - default: - throw new PsdInvalidException( - "LayerId key should be lyid or lnsr"); - } - } - - public LayerId(PsdBinaryReader reader, - string key, long dataLength) - : this(key) - { - if (dataLength == 4) - id = reader.ReadInt32(); - else - throw new PsdInvalidException("LayerId data length should be 4"); - } - } -} +///////////////////////////////////////////////////////////////////////////////// +// Author : leoyaik@unity3d.com +///////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; + +namespace PhotoshopFile +{ + /// + /// Layers that are stored as Additional Info, rather than in the main + /// Layers section of the PSD file. + /// + /// + /// Photoshop stores layers in the Additional Info section for 16-bit and + /// 32-bit depth images. The Layers section in the PSD file is left empty. + /// + /// This appears to be for backward-compatibility purposes, but it is not + /// required. Photoshop will successfully load a high-bitdepth image that + /// puts the layers in the Layers section. + /// + internal class LayerId : LayerInfo + { + public override string Signature + { + get { return "8BIM"; } + } + + private string key; + public override string Key + { + get { return key; } + } + + private int id = 0; + public int ID + { + get { return id; } + } + + + public LayerId(string key) + { + switch (key) + { + // The key does not have to match the bit depth, but it does have to + // be one of the known values. + case "lyid": + case "lnsr": + this.key = key; + break; + default: + throw new PsdInvalidException( + "LayerId key should be lyid or lnsr"); + } + } + + public LayerId(PsdBinaryReader reader, + string key, long dataLength) + : this(key) + { + if (dataLength == 4) + id = reader.ReadInt32(); + else + throw new PsdInvalidException("LayerId data length should be 4"); + } + } +} diff --git a/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/LayerId.cs.meta b/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/LayerId.cs.meta index 362e4ba..cd8c7c3 100644 --- a/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/LayerId.cs.meta +++ b/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/LayerId.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 4c40067c9a690e44ca098f5e4ed763e7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 4c40067c9a690e44ca098f5e4ed763e7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/LayerSectionInfo.cs b/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/LayerSectionInfo.cs index 425d53e..5d9993f 100644 --- a/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/LayerSectionInfo.cs +++ b/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/LayerSectionInfo.cs @@ -1,94 +1,94 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2015 Tao Yue -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; - -namespace PhotoshopFile -{ - internal enum LayerSectionType - { - Layer = 0, - OpenFolder = 1, - ClosedFolder = 2, - SectionDivider = 3 - } - - internal enum LayerSectionSubtype - { - Normal = 0, - SceneGroup = 1 - } - - /// - /// Layer sections are known as Groups in the Photoshop UI. - /// - internal class LayerSectionInfo : LayerInfo - { - public override string Signature - { - get { return "8BIM"; } - } - - private string key; - public override string Key - { - get { return key; } - } - - public LayerSectionType SectionType { get; set; } - - private LayerSectionSubtype? subtype; - public LayerSectionSubtype Subtype - { - get { return subtype ?? LayerSectionSubtype.Normal; } - set { subtype = value; } - } - - private string blendModeKey; - public string BlendModeKey - { - get { return blendModeKey; } - set - { - if (value.Length != 4) - { - throw new ArgumentException( - "BlendModeKey must be 4 characters in length."); - } - blendModeKey = value; - } - } - - public LayerSectionInfo(PsdBinaryReader reader, string key, int dataLength) - { - // The key for layer section info is documented to be "lsct". However, - // some Photoshop files use the undocumented key "lsdk", with apparently - // the same data format. - this.key = key; - - SectionType = (LayerSectionType)reader.ReadInt32(); - if (dataLength >= 12) - { - var signature = reader.ReadAsciiChars(4); - if (signature != "8BIM") - throw new PsdInvalidException("Invalid section divider signature."); - - BlendModeKey = reader.ReadAsciiChars(4); - if (dataLength >= 16) - { - Subtype = (LayerSectionSubtype)reader.ReadInt32(); - } - } - } - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2015 Tao Yue +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; + +namespace PhotoshopFile +{ + internal enum LayerSectionType + { + Layer = 0, + OpenFolder = 1, + ClosedFolder = 2, + SectionDivider = 3 + } + + internal enum LayerSectionSubtype + { + Normal = 0, + SceneGroup = 1 + } + + /// + /// Layer sections are known as Groups in the Photoshop UI. + /// + internal class LayerSectionInfo : LayerInfo + { + public override string Signature + { + get { return "8BIM"; } + } + + private string key; + public override string Key + { + get { return key; } + } + + public LayerSectionType SectionType { get; set; } + + private LayerSectionSubtype? subtype; + public LayerSectionSubtype Subtype + { + get { return subtype ?? LayerSectionSubtype.Normal; } + set { subtype = value; } + } + + private string blendModeKey; + public string BlendModeKey + { + get { return blendModeKey; } + set + { + if (value.Length != 4) + { + throw new ArgumentException( + "BlendModeKey must be 4 characters in length."); + } + blendModeKey = value; + } + } + + public LayerSectionInfo(PsdBinaryReader reader, string key, int dataLength) + { + // The key for layer section info is documented to be "lsct". However, + // some Photoshop files use the undocumented key "lsdk", with apparently + // the same data format. + this.key = key; + + SectionType = (LayerSectionType)reader.ReadInt32(); + if (dataLength >= 12) + { + var signature = reader.ReadAsciiChars(4); + if (signature != "8BIM") + throw new PsdInvalidException("Invalid section divider signature."); + + BlendModeKey = reader.ReadAsciiChars(4); + if (dataLength >= 16) + { + Subtype = (LayerSectionSubtype)reader.ReadInt32(); + } + } + } + } +} diff --git a/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/LayerSectionInfo.cs.meta b/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/LayerSectionInfo.cs.meta index 2808ce9..29098d9 100644 --- a/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/LayerSectionInfo.cs.meta +++ b/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/LayerSectionInfo.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 4ca20fe44ab2bfd4d8a1c3547b4a136f -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 4ca20fe44ab2bfd4d8a1c3547b4a136f +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/LayerUnicodeName.cs b/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/LayerUnicodeName.cs index 9de1c63..201d1bf 100644 --- a/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/LayerUnicodeName.cs +++ b/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/LayerUnicodeName.cs @@ -1,42 +1,42 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2014 Tao Yue -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; - -namespace PhotoshopFile -{ - internal class LayerUnicodeName : LayerInfo - { - public override string Signature - { - get { return "8BIM"; } - } - - public override string Key - { - get { return "luni"; } - } - - public string Name { get; set; } - - public LayerUnicodeName(string name) - { - Name = name; - } - - public LayerUnicodeName(PsdBinaryReader reader) - { - Name = reader.ReadUnicodeString(); - } - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2014 Tao Yue +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; + +namespace PhotoshopFile +{ + internal class LayerUnicodeName : LayerInfo + { + public override string Signature + { + get { return "8BIM"; } + } + + public override string Key + { + get { return "luni"; } + } + + public string Name { get; set; } + + public LayerUnicodeName(string name) + { + Name = name; + } + + public LayerUnicodeName(PsdBinaryReader reader) + { + Name = reader.ReadUnicodeString(); + } + } +} diff --git a/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/LayerUnicodeName.cs.meta b/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/LayerUnicodeName.cs.meta index 5f3ce04..ea48643 100644 --- a/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/LayerUnicodeName.cs.meta +++ b/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/LayerUnicodeName.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 277ac9726bb060c48860d92018fc06cf -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 277ac9726bb060c48860d92018fc06cf +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/RawLayerInfo.cs b/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/RawLayerInfo.cs index 06f7a2a..d3a141e 100644 --- a/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/RawLayerInfo.cs +++ b/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/RawLayerInfo.cs @@ -1,52 +1,52 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2014 Tao Yue -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using System.Diagnostics; - -namespace PhotoshopFile -{ - [DebuggerDisplay("Layer Info: { key }")] - internal class RawLayerInfo : LayerInfo - { - private string signature; - public override string Signature - { - get { return signature; } - } - - private string key; - public override string Key - { - get { return key; } - } - - public byte[] Data { get; private set; } - - public RawLayerInfo(string key, string signature = "8BIM") - { - this.signature = signature; - this.key = key; - } - - public RawLayerInfo(PsdBinaryReader reader, string signature, string key, - long dataLength) - { - this.signature = signature; - this.key = key; - - Util.CheckByteArrayLength(dataLength); - Data = reader.ReadBytes((int)dataLength); - } - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2014 Tao Yue +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Diagnostics; + +namespace PhotoshopFile +{ + [DebuggerDisplay("Layer Info: { key }")] + internal class RawLayerInfo : LayerInfo + { + private string signature; + public override string Signature + { + get { return signature; } + } + + private string key; + public override string Key + { + get { return key; } + } + + public byte[] Data { get; private set; } + + public RawLayerInfo(string key, string signature = "8BIM") + { + this.signature = signature; + this.key = key; + } + + public RawLayerInfo(PsdBinaryReader reader, string signature, string key, + long dataLength) + { + this.signature = signature; + this.key = key; + + Util.CheckByteArrayLength(dataLength); + Data = reader.ReadBytes((int)dataLength); + } + } +} diff --git a/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/RawLayerInfo.cs.meta b/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/RawLayerInfo.cs.meta index 45db884..d61de6f 100644 --- a/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/RawLayerInfo.cs.meta +++ b/Editor/PSDPlugin/PsdFile/Layers/LayerInfo/RawLayerInfo.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 8b73fc997c117d641a1673cd96fc8a07 -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 8b73fc997c117d641a1673cd96fc8a07 +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/Layers/Mask.cs b/Editor/PSDPlugin/PsdFile/Layers/Mask.cs index b99a924..1191e93 100644 --- a/Editor/PSDPlugin/PsdFile/Layers/Mask.cs +++ b/Editor/PSDPlugin/PsdFile/Layers/Mask.cs @@ -1,149 +1,149 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2014 Tao Yue -// -// Portions of this file are provided under the BSD 3-clause License: -// Copyright (c) 2006, Jonas Beckeman -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using System.Collections.Specialized; -using System.Diagnostics; -using PDNWrapper; -using System.Globalization; -using Unity.Collections; - -namespace PhotoshopFile -{ - internal class Mask - { - /// - /// The layer to which this mask belongs - /// - public Layer Layer { get; private set; } - - /// - /// The rectangle enclosing the mask. - /// - public Rectangle Rect { get; set; } - - private byte backgroundColor; - public byte BackgroundColor - { - get { return backgroundColor; } - set - { - if ((value != 0) && (value != 255)) - throw new PsdInvalidException("Mask background must be fully-opaque or fully-transparent."); - backgroundColor = value; - } - } - - private static int positionVsLayerBit = BitVector32.CreateMask(); - private static int disabledBit = BitVector32.CreateMask(positionVsLayerBit); - private static int invertOnBlendBit = BitVector32.CreateMask(disabledBit); - - private BitVector32 flags; - public BitVector32 Flags { get { return flags; } } - - /// - /// If true, the position of the mask is relative to the layer. - /// - public bool PositionVsLayer - { - get { return flags[positionVsLayerBit]; } - set { flags[positionVsLayerBit] = value; } - } - - public bool Disabled - { - get { return flags[disabledBit]; } - set { flags[disabledBit] = value; } - } - - /// - /// if true, invert the mask when blending. - /// - public bool InvertOnBlend - { - get { return flags[invertOnBlendBit]; } - set { flags[invertOnBlendBit] = value; } - } - - /// - /// Mask image data. - /// - public NativeArray ImageData { get; set; } - - public Mask(Layer layer) - { - Layer = layer; - this.flags = new BitVector32(); - } - - public Mask(Layer layer, Rectangle rect, byte color, BitVector32 flags) - { - Layer = layer; - Rect = rect; - BackgroundColor = color; - this.flags = flags; - } - } - - /// - /// Mask info for a layer. Contains both the layer and user masks. - /// - internal class MaskInfo - { - public Mask LayerMask { get; set; } - - public Mask UserMask { get; set; } - - /// - /// Construct MaskInfo with null masks. - /// - public MaskInfo() - { - } - - public MaskInfo(PsdBinaryReader reader, Layer layer) - { - Util.DebugMessage(reader.BaseStream, "Load, Begin, MaskInfo"); - - var maskLength = reader.ReadUInt32(); - if (maskLength <= 0) - return; - - var startPosition = reader.BaseStream.Position; - var endPosition = startPosition + maskLength; - - // Read layer mask - var rectangle = reader.ReadRectangle(); - var backgroundColor = reader.ReadByte(); - var flagsByte = reader.ReadByte(); - LayerMask = new Mask(layer, rectangle, backgroundColor, new BitVector32(flagsByte)); - - // User mask is supplied separately when there is also a vector mask. - if (maskLength == 36) - { - var userFlagsByte = reader.ReadByte(); - var userBackgroundColor = reader.ReadByte(); - var userRectangle = reader.ReadRectangle(); - UserMask = new Mask(layer, userRectangle, userBackgroundColor, new BitVector32(userFlagsByte)); - } - - // 20-byte mask data will end with padding. - reader.BaseStream.Position = endPosition; - - Util.DebugMessage(reader.BaseStream, "Load, End, MaskInfo"); - } - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2014 Tao Yue +// +// Portions of this file are provided under the BSD 3-clause License: +// Copyright (c) 2006, Jonas Beckeman +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Collections.Specialized; +using System.Diagnostics; +using PDNWrapper; +using System.Globalization; +using Unity.Collections; + +namespace PhotoshopFile +{ + internal class Mask + { + /// + /// The layer to which this mask belongs + /// + public Layer Layer { get; private set; } + + /// + /// The rectangle enclosing the mask. + /// + public Rectangle Rect { get; set; } + + private byte backgroundColor; + public byte BackgroundColor + { + get { return backgroundColor; } + set + { + if ((value != 0) && (value != 255)) + throw new PsdInvalidException("Mask background must be fully-opaque or fully-transparent."); + backgroundColor = value; + } + } + + private static int positionVsLayerBit = BitVector32.CreateMask(); + private static int disabledBit = BitVector32.CreateMask(positionVsLayerBit); + private static int invertOnBlendBit = BitVector32.CreateMask(disabledBit); + + private BitVector32 flags; + public BitVector32 Flags { get { return flags; } } + + /// + /// If true, the position of the mask is relative to the layer. + /// + public bool PositionVsLayer + { + get { return flags[positionVsLayerBit]; } + set { flags[positionVsLayerBit] = value; } + } + + public bool Disabled + { + get { return flags[disabledBit]; } + set { flags[disabledBit] = value; } + } + + /// + /// if true, invert the mask when blending. + /// + public bool InvertOnBlend + { + get { return flags[invertOnBlendBit]; } + set { flags[invertOnBlendBit] = value; } + } + + /// + /// Mask image data. + /// + public NativeArray ImageData { get; set; } + + public Mask(Layer layer) + { + Layer = layer; + this.flags = new BitVector32(); + } + + public Mask(Layer layer, Rectangle rect, byte color, BitVector32 flags) + { + Layer = layer; + Rect = rect; + BackgroundColor = color; + this.flags = flags; + } + } + + /// + /// Mask info for a layer. Contains both the layer and user masks. + /// + internal class MaskInfo + { + public Mask LayerMask { get; set; } + + public Mask UserMask { get; set; } + + /// + /// Construct MaskInfo with null masks. + /// + public MaskInfo() + { + } + + public MaskInfo(PsdBinaryReader reader, Layer layer) + { + Util.DebugMessage(reader.BaseStream, "Load, Begin, MaskInfo"); + + var maskLength = reader.ReadUInt32(); + if (maskLength <= 0) + return; + + var startPosition = reader.BaseStream.Position; + var endPosition = startPosition + maskLength; + + // Read layer mask + var rectangle = reader.ReadRectangle(); + var backgroundColor = reader.ReadByte(); + var flagsByte = reader.ReadByte(); + LayerMask = new Mask(layer, rectangle, backgroundColor, new BitVector32(flagsByte)); + + // User mask is supplied separately when there is also a vector mask. + if (maskLength == 36) + { + var userFlagsByte = reader.ReadByte(); + var userBackgroundColor = reader.ReadByte(); + var userRectangle = reader.ReadRectangle(); + UserMask = new Mask(layer, userRectangle, userBackgroundColor, new BitVector32(userFlagsByte)); + } + + // 20-byte mask data will end with padding. + reader.BaseStream.Position = endPosition; + + Util.DebugMessage(reader.BaseStream, "Load, End, MaskInfo"); + } + } +} diff --git a/Editor/PSDPlugin/PsdFile/Layers/Mask.cs.meta b/Editor/PSDPlugin/PsdFile/Layers/Mask.cs.meta index 57b01e5..85be818 100644 --- a/Editor/PSDPlugin/PsdFile/Layers/Mask.cs.meta +++ b/Editor/PSDPlugin/PsdFile/Layers/Mask.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 2b6148b9ac6738b4999b4686f3820560 -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 2b6148b9ac6738b4999b4686f3820560 +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/LoadContext.cs b/Editor/PSDPlugin/PsdFile/LoadContext.cs index 513103c..fef5093 100644 --- a/Editor/PSDPlugin/PsdFile/LoadContext.cs +++ b/Editor/PSDPlugin/PsdFile/LoadContext.cs @@ -1,44 +1,44 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2016 Tao Yue -// -// Portions of this file are provided under the BSD 3-clause License: -// Copyright (c) 2006, Jonas Beckeman -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace PhotoshopFile -{ - /// - /// Contains settings and callbacks that affect the loading of a PSD file. - /// - internal class LoadContext - { - public Encoding Encoding { get; set; } - - public LoadContext() - { - Encoding = Encoding.Default; - } - - public virtual void OnLoadLayersHeader(PsdFile psdFile) - { - } - - public virtual void OnLoadLayerHeader(Layer layer) - { - } - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2016 Tao Yue +// +// Portions of this file are provided under the BSD 3-clause License: +// Copyright (c) 2006, Jonas Beckeman +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace PhotoshopFile +{ + /// + /// Contains settings and callbacks that affect the loading of a PSD file. + /// + internal class LoadContext + { + public Encoding Encoding { get; set; } + + public LoadContext() + { + Encoding = Encoding.Default; + } + + public virtual void OnLoadLayersHeader(PsdFile psdFile) + { + } + + public virtual void OnLoadLayerHeader(Layer layer) + { + } + } +} diff --git a/Editor/PSDPlugin/PsdFile/LoadContext.cs.meta b/Editor/PSDPlugin/PsdFile/LoadContext.cs.meta index a090b12..4df0ca7 100644 --- a/Editor/PSDPlugin/PsdFile/LoadContext.cs.meta +++ b/Editor/PSDPlugin/PsdFile/LoadContext.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 3b268b1ee06ace349a872a7d95498aba -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 3b268b1ee06ace349a872a7d95498aba +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/PsdBinaryReader.cs b/Editor/PSDPlugin/PsdFile/PsdBinaryReader.cs index 224554c..e3a2725 100644 --- a/Editor/PSDPlugin/PsdFile/PsdBinaryReader.cs +++ b/Editor/PSDPlugin/PsdFile/PsdBinaryReader.cs @@ -1,229 +1,229 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2013 Tao Yue -// -// Portions of this file are provided under the BSD 3-clause License: -// Copyright (c) 2006, Jonas Beckeman -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using PDNWrapper; -using System.IO; -using System.Text; - -namespace PhotoshopFile -{ - /// - /// Reads PSD data types in big-endian byte order. - /// - internal class PsdBinaryReader : IDisposable - { - private BinaryReader reader; - private Encoding encoding; - - public Stream BaseStream - { - get { return reader.BaseStream; } - } - - public PsdBinaryReader(Stream stream, PsdBinaryReader reader) - : this(stream, reader.encoding) - { - } - - public PsdBinaryReader(Stream stream, Encoding encoding) - { - this.encoding = encoding; - - // ReadPascalString and ReadUnicodeString handle encoding explicitly. - // BinaryReader.ReadString() is never called, so it is constructed with - // ASCII encoding to make accidental usage obvious. - reader = new BinaryReader(stream, Encoding.ASCII); - } - - public byte ReadByte() - { - return reader.ReadByte(); - } - - public byte[] ReadBytes(int count) - { - return reader.ReadBytes(count); - } - - public bool ReadBoolean() - { - return reader.ReadBoolean(); - } - - public Int16 ReadInt16() - { - var val = reader.ReadInt16(); - byte[] b = BitConverter.GetBytes(val); - { - Util.SwapBytes(b, 0, 2); - } - val = BitConverter.ToInt16(b, 0); - return val; - } - - public Int32 ReadInt32() - { - var val = reader.ReadInt32(); - byte[] b = BitConverter.GetBytes(val); - { - Util.SwapBytes(b, 0, 4); - } - val = BitConverter.ToInt32(b, 0); - return val; - } - - public Int64 ReadInt64() - { - var val = reader.ReadInt64(); - var b = BitConverter.GetBytes(val); - { - Util.SwapBytes(b, 0, 8); - } - val = BitConverter.ToInt64(b, 0); - return val; - } - - public UInt16 ReadUInt16() - { - var val = reader.ReadUInt16(); - var b = BitConverter.GetBytes(val); - { - Util.SwapBytes(b, 0, 2); - } - val = BitConverter.ToUInt16(b, 0); - return val; - } - - public UInt32 ReadUInt32() - { - var val = reader.ReadUInt32(); - var b = BitConverter.GetBytes(val); - { - Util.SwapBytes(b, 0, 4); - } - val = BitConverter.ToUInt32(b, 0); - return val; - } - - public UInt64 ReadUInt64() - { - var val = reader.ReadUInt64(); - var b = BitConverter.GetBytes(val); - { - Util.SwapBytes(b, 0, 8); - } - val = BitConverter.ToUInt64(b, 0); - return val; - } - - ////////////////////////////////////////////////////////////////// - - /// - /// Read padding to get to the byte multiple for the block. - /// - /// Starting position of the padded block. - /// Byte multiple that the block is padded to. - public void ReadPadding(long startPosition, int padMultiple) - { - // Pad to specified byte multiple - var totalLength = reader.BaseStream.Position - startPosition; - var padBytes = Util.GetPadding((int)totalLength, padMultiple); - ReadBytes(padBytes); - } - - public Rectangle ReadRectangle() - { - var rect = new Rectangle(); - rect.Y = ReadInt32(); - rect.X = ReadInt32(); - rect.Height = ReadInt32() - rect.Y; - rect.Width = ReadInt32() - rect.X; - return rect; - } - - /// - /// Read a fixed-length ASCII string. - /// - public string ReadAsciiChars(int count) - { - var bytes = reader.ReadBytes(count); - var s = Encoding.ASCII.GetString(bytes); - return s; - } - - /// - /// Read a Pascal string using the specified encoding. - /// - /// Byte multiple that the Pascal string is padded to. - public string ReadPascalString(int padMultiple) - { - var startPosition = reader.BaseStream.Position; - - byte stringLength = ReadByte(); - var bytes = ReadBytes(stringLength); - ReadPadding(startPosition, padMultiple); - - // Default decoder uses best-fit fallback, so it will not throw any - // exceptions if unknown characters are encountered. - var str = encoding.GetString(bytes); - return str; - } - - public string ReadUnicodeString() - { - var numChars = ReadInt32(); - var length = 2 * numChars; - var data = ReadBytes(length); - var str = Encoding.BigEndianUnicode.GetString(data, 0, length); - - return str; - } - - ////////////////////////////////////////////////////////////////// - - #region IDisposable - - private bool disposed = false; - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - // Check to see if Dispose has already been called. - if (disposed) - return; - - if (disposing) - { - if (reader != null) - { - // BinaryReader.Dispose() is protected. - reader.Close(); - reader = null; - } - } - - disposed = true; - } - - #endregion - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2013 Tao Yue +// +// Portions of this file are provided under the BSD 3-clause License: +// Copyright (c) 2006, Jonas Beckeman +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using PDNWrapper; +using System.IO; +using System.Text; + +namespace PhotoshopFile +{ + /// + /// Reads PSD data types in big-endian byte order. + /// + internal class PsdBinaryReader : IDisposable + { + private BinaryReader reader; + private Encoding encoding; + + public Stream BaseStream + { + get { return reader.BaseStream; } + } + + public PsdBinaryReader(Stream stream, PsdBinaryReader reader) + : this(stream, reader.encoding) + { + } + + public PsdBinaryReader(Stream stream, Encoding encoding) + { + this.encoding = encoding; + + // ReadPascalString and ReadUnicodeString handle encoding explicitly. + // BinaryReader.ReadString() is never called, so it is constructed with + // ASCII encoding to make accidental usage obvious. + reader = new BinaryReader(stream, Encoding.ASCII); + } + + public byte ReadByte() + { + return reader.ReadByte(); + } + + public byte[] ReadBytes(int count) + { + return reader.ReadBytes(count); + } + + public bool ReadBoolean() + { + return reader.ReadBoolean(); + } + + public Int16 ReadInt16() + { + var val = reader.ReadInt16(); + byte[] b = BitConverter.GetBytes(val); + { + Util.SwapBytes(b, 0, 2); + } + val = BitConverter.ToInt16(b, 0); + return val; + } + + public Int32 ReadInt32() + { + var val = reader.ReadInt32(); + byte[] b = BitConverter.GetBytes(val); + { + Util.SwapBytes(b, 0, 4); + } + val = BitConverter.ToInt32(b, 0); + return val; + } + + public Int64 ReadInt64() + { + var val = reader.ReadInt64(); + var b = BitConverter.GetBytes(val); + { + Util.SwapBytes(b, 0, 8); + } + val = BitConverter.ToInt64(b, 0); + return val; + } + + public UInt16 ReadUInt16() + { + var val = reader.ReadUInt16(); + var b = BitConverter.GetBytes(val); + { + Util.SwapBytes(b, 0, 2); + } + val = BitConverter.ToUInt16(b, 0); + return val; + } + + public UInt32 ReadUInt32() + { + var val = reader.ReadUInt32(); + var b = BitConverter.GetBytes(val); + { + Util.SwapBytes(b, 0, 4); + } + val = BitConverter.ToUInt32(b, 0); + return val; + } + + public UInt64 ReadUInt64() + { + var val = reader.ReadUInt64(); + var b = BitConverter.GetBytes(val); + { + Util.SwapBytes(b, 0, 8); + } + val = BitConverter.ToUInt64(b, 0); + return val; + } + + ////////////////////////////////////////////////////////////////// + + /// + /// Read padding to get to the byte multiple for the block. + /// + /// Starting position of the padded block. + /// Byte multiple that the block is padded to. + public void ReadPadding(long startPosition, int padMultiple) + { + // Pad to specified byte multiple + var totalLength = reader.BaseStream.Position - startPosition; + var padBytes = Util.GetPadding((int)totalLength, padMultiple); + ReadBytes(padBytes); + } + + public Rectangle ReadRectangle() + { + var rect = new Rectangle(); + rect.Y = ReadInt32(); + rect.X = ReadInt32(); + rect.Height = ReadInt32() - rect.Y; + rect.Width = ReadInt32() - rect.X; + return rect; + } + + /// + /// Read a fixed-length ASCII string. + /// + public string ReadAsciiChars(int count) + { + var bytes = reader.ReadBytes(count); + var s = Encoding.ASCII.GetString(bytes); + return s; + } + + /// + /// Read a Pascal string using the specified encoding. + /// + /// Byte multiple that the Pascal string is padded to. + public string ReadPascalString(int padMultiple) + { + var startPosition = reader.BaseStream.Position; + + byte stringLength = ReadByte(); + var bytes = ReadBytes(stringLength); + ReadPadding(startPosition, padMultiple); + + // Default decoder uses best-fit fallback, so it will not throw any + // exceptions if unknown characters are encountered. + var str = encoding.GetString(bytes); + return str; + } + + public string ReadUnicodeString() + { + var numChars = ReadInt32(); + var length = 2 * numChars; + var data = ReadBytes(length); + var str = Encoding.BigEndianUnicode.GetString(data, 0, length); + + return str; + } + + ////////////////////////////////////////////////////////////////// + + #region IDisposable + + private bool disposed = false; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + // Check to see if Dispose has already been called. + if (disposed) + return; + + if (disposing) + { + if (reader != null) + { + // BinaryReader.Dispose() is protected. + reader.Close(); + reader = null; + } + } + + disposed = true; + } + + #endregion + } +} diff --git a/Editor/PSDPlugin/PsdFile/PsdBinaryReader.cs.meta b/Editor/PSDPlugin/PsdFile/PsdBinaryReader.cs.meta index 42b28fe..747b9d9 100644 --- a/Editor/PSDPlugin/PsdFile/PsdBinaryReader.cs.meta +++ b/Editor/PSDPlugin/PsdFile/PsdBinaryReader.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 9614f1c9b6a2eb5499429bfab13a0c09 -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 9614f1c9b6a2eb5499429bfab13a0c09 +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/PsdBlendMode.cs b/Editor/PSDPlugin/PsdFile/PsdBlendMode.cs index daeeffc..8ebbeb9 100644 --- a/Editor/PSDPlugin/PsdFile/PsdBlendMode.cs +++ b/Editor/PSDPlugin/PsdFile/PsdBlendMode.cs @@ -1,52 +1,52 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2012 Tao Yue -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace PhotoshopFile -{ - internal static class PsdBlendMode - { - public const string Normal = "norm"; - public const string Darken = "dark"; - public const string Lighten = "lite"; - public const string Hue = "hue "; - public const string Saturation = "sat "; - public const string Color = "colr"; - public const string Luminosity = "lum "; - public const string Multiply = "mul "; - public const string Screen = "scrn"; - public const string Dissolve = "diss"; - public const string Overlay = "over"; - public const string HardLight = "hLit"; - public const string SoftLight = "sLit"; - public const string Difference = "diff"; - public const string Exclusion = "smud"; - public const string ColorDodge = "div "; - public const string ColorBurn = "idiv"; - public const string LinearBurn = "lbrn"; - public const string LinearDodge = "lddg"; - public const string VividLight = "vLit"; - public const string LinearLight = "lLit"; - public const string PinLight = "pLit"; - public const string HardMix = "hMix"; - public const string PassThrough = "pass"; - public const string DarkerColor = "dkCl"; - public const string LighterColor = "lgCl"; - public const string Subtract = "fsub"; - public const string Divide = "fdiv"; - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2012 Tao Yue +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace PhotoshopFile +{ + internal static class PsdBlendMode + { + public const string Normal = "norm"; + public const string Darken = "dark"; + public const string Lighten = "lite"; + public const string Hue = "hue "; + public const string Saturation = "sat "; + public const string Color = "colr"; + public const string Luminosity = "lum "; + public const string Multiply = "mul "; + public const string Screen = "scrn"; + public const string Dissolve = "diss"; + public const string Overlay = "over"; + public const string HardLight = "hLit"; + public const string SoftLight = "sLit"; + public const string Difference = "diff"; + public const string Exclusion = "smud"; + public const string ColorDodge = "div "; + public const string ColorBurn = "idiv"; + public const string LinearBurn = "lbrn"; + public const string LinearDodge = "lddg"; + public const string VividLight = "vLit"; + public const string LinearLight = "lLit"; + public const string PinLight = "pLit"; + public const string HardMix = "hMix"; + public const string PassThrough = "pass"; + public const string DarkerColor = "dkCl"; + public const string LighterColor = "lgCl"; + public const string Subtract = "fsub"; + public const string Divide = "fdiv"; + } +} diff --git a/Editor/PSDPlugin/PsdFile/PsdBlendMode.cs.meta b/Editor/PSDPlugin/PsdFile/PsdBlendMode.cs.meta index 222bcbc..3352bf5 100644 --- a/Editor/PSDPlugin/PsdFile/PsdBlendMode.cs.meta +++ b/Editor/PSDPlugin/PsdFile/PsdBlendMode.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: c4e78ec955914854d9c9c68fa7af1742 -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: c4e78ec955914854d9c9c68fa7af1742 +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/PsdFile.cs b/Editor/PSDPlugin/PsdFile/PsdFile.cs index 9e46e43..8092b4a 100644 --- a/Editor/PSDPlugin/PsdFile/PsdFile.cs +++ b/Editor/PSDPlugin/PsdFile/PsdFile.cs @@ -1,708 +1,708 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2016 Tao Yue -// -// Portions of this file are provided under the BSD 3-clause License: -// Copyright (c) 2006, Jonas Beckeman -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using PDNWrapper; -using System.IO; -using System.Linq; -using System.Text; -using PaintDotNet.Data.PhotoshopFileType; - -namespace PhotoshopFile -{ - [Flags] - internal enum ELoadFlag - { - Header = 1, - ColorMode = Header | 1 << 2, - ImageData = ColorMode | 1 << 3, - All = Header | ColorMode | ImageData - } - - - internal enum PsdColorMode - { - Bitmap = 0, - Grayscale = 1, - Indexed = 2, - RGB = 3, - CMYK = 4, - Multichannel = 7, - Duotone = 8, - Lab = 9 - }; - - internal enum PsdFileVersion : short - { - Psd = 1, - PsbLargeDocument = 2 - } - - internal class PsdFile - { - #region Constructors - - ELoadFlag m_LoadFlag; - - public PsdFile(PsdFileVersion version = PsdFileVersion.Psd) - { - Version = version; - - BaseLayer = new Layer(this); - ImageResources = new ImageResources(); - Layers = new List(); - AdditionalInfo = new List(); - } - - public PsdFile(string filename, LoadContext loadContext, ELoadFlag loadFlag = ELoadFlag.All) - : this() - { - using (var stream = new FileStream(filename, FileMode.Open)) - { - Load(stream, loadContext, loadFlag); - } - } - - public PsdFile(Stream stream, LoadContext loadContext, ELoadFlag loadFlag = ELoadFlag.All) - : this() - { - Load(stream, loadContext, loadFlag); - } - - #endregion - - #region Load and save - - internal LoadContext LoadContext { get; private set; } - - private void Load(Stream stream, LoadContext loadContext, ELoadFlag loadFlag) - { - LoadContext = loadContext; - var reader = new PsdBinaryReader(stream, loadContext.Encoding); - - if ((loadFlag & ELoadFlag.Header) == ELoadFlag.Header) - LoadHeader(reader); - - if ((loadFlag & ELoadFlag.ColorMode) == ELoadFlag.ColorMode) - LoadColorModeData(reader); - - if ((loadFlag & ELoadFlag.ImageData) == ELoadFlag.ImageData) - { - LoadImageResources(reader); - LoadLayerAndMaskInfo(reader); - - LoadImage(reader); - DecompressImages(); - } - } - - #endregion - - #region Header - - /// - /// Photoshop file format version. - /// - public PsdFileVersion Version { get; private set; } - - public bool IsLargeDocument - { - get { return Version == PsdFileVersion.PsbLargeDocument; } - } - - private Int16 channelCount; - /// - /// The number of channels in the image, including any alpha channels. - /// - public Int16 ChannelCount - { - get { return channelCount; } - set - { - if (value < 1 || value > 56) - throw new ArgumentException("Number of channels must be from 1 to 56."); - channelCount = value; - } - } - - private void CheckDimension(int dimension) - { - if (dimension < 1) - { - throw new ArgumentException("Image dimension must be at least 1."); - } - if ((Version == PsdFileVersion.Psd) && (dimension > 30000)) - { - throw new ArgumentException("PSD image dimension cannot exceed 30000."); - } - if ((Version == PsdFileVersion.PsbLargeDocument) && (dimension > 300000)) - { - throw new ArgumentException("PSB image dimension cannot exceed 300000."); - } - } - - /// - /// The height of the image in pixels. - /// - public int RowCount - { - get { return this.BaseLayer.Rect.Height; } - set - { - CheckDimension(value); - BaseLayer.Rect = new Rectangle(0, 0, BaseLayer.Rect.Width, value); - } - } - - - /// - /// The width of the image in pixels. - /// - public int ColumnCount - { - get { return this.BaseLayer.Rect.Width; } - set - { - CheckDimension(value); - BaseLayer.Rect = new Rectangle(0, 0, value, BaseLayer.Rect.Height); - } - } - - private int bitDepth; - /// - /// The number of bits per channel. Supported values are 1, 8, 16, and 32. - /// - public int BitDepth - { - get { return bitDepth; } - set - { - switch (value) - { - case 1: - case 8: - case 16: - case 32: - bitDepth = value; - break; - default: - throw new NotImplementedException("Invalid bit depth."); - } - } - } - - /// - /// The color mode of the file. - /// - public PsdColorMode ColorMode { get; set; } - - /////////////////////////////////////////////////////////////////////////// - - private void LoadHeader(PsdBinaryReader reader) - { - Util.DebugMessage(reader.BaseStream, "Load, Begin, File header"); - - var signature = reader.ReadAsciiChars(4); - if (signature != "8BPS") - throw new PsdInvalidException("The given stream is not a valid PSD file"); - - Version = (PsdFileVersion)reader.ReadInt16(); - Util.DebugMessage(reader.BaseStream, "Load, Info, Version {0}", (int)Version); - if ((Version != PsdFileVersion.Psd) - && (Version != PsdFileVersion.PsbLargeDocument)) - { - throw new PsdInvalidException("The PSD file has an unknown version"); - } - - //6 bytes reserved - reader.BaseStream.Position += 6; - - this.ChannelCount = reader.ReadInt16(); - this.RowCount = reader.ReadInt32(); - this.ColumnCount = reader.ReadInt32(); - BitDepth = reader.ReadInt16(); - ColorMode = (PsdColorMode)reader.ReadInt16(); - - Util.DebugMessage(reader.BaseStream, "Load, End, File header"); - } - - #endregion - - /////////////////////////////////////////////////////////////////////////// - - #region ColorModeData - - /// - /// If ColorMode is ColorModes.Indexed, the following 768 bytes will contain - /// a 256-color palette. If the ColorMode is ColorModes.Duotone, the data - /// following presumably consists of screen parameters and other related information. - /// Unfortunately, it is intentionally not documented by Adobe, and non-Photoshop - /// readers are advised to treat duotone images as gray-scale images. - /// - public byte[] ColorModeData = new byte[0]; - - private void LoadColorModeData(PsdBinaryReader reader) - { - Util.DebugMessage(reader.BaseStream, "Load, Begin, ColorModeData"); - - var paletteLength = reader.ReadUInt32(); - if (paletteLength > 0) - { - ColorModeData = reader.ReadBytes((int)paletteLength); - } - - Util.DebugMessage(reader.BaseStream, "Load, End, ColorModeData"); - } - - #endregion - - /////////////////////////////////////////////////////////////////////////// - - #region ImageResources - - /// - /// The Image resource blocks for the file - /// - public ImageResources ImageResources { get; set; } - - public ResolutionInfo Resolution - { - get - { - return (ResolutionInfo)ImageResources.Get(ResourceID.ResolutionInfo); - } - - set - { - ImageResources.Set(value); - } - } - - - /////////////////////////////////////////////////////////////////////////// - - private void LoadImageResources(PsdBinaryReader reader) - { - Util.DebugMessage(reader.BaseStream, "Load, Begin, ImageResources"); - - var imageResourcesLength = reader.ReadUInt32(); - if (imageResourcesLength <= 0) - return; - - var startPosition = reader.BaseStream.Position; - var endPosition = startPosition + imageResourcesLength; - while (reader.BaseStream.Position < endPosition) - { - var imageResource = ImageResourceFactory.CreateImageResource(reader); - ImageResources.Add(imageResource); - } - - Util.DebugMessage(reader.BaseStream, "Load, End, ImageResources"); - - //----------------------------------------------------------------------- - // make sure we are not on a wrong offset, so set the stream position - // manually - reader.BaseStream.Position = startPosition + imageResourcesLength; - } - - #endregion - - /////////////////////////////////////////////////////////////////////////// - - #region LayerAndMaskInfo - - public List Layers { get; private set; } - - public List AdditionalInfo { get; private set; } - - public bool AbsoluteAlpha { get; set; } - - /////////////////////////////////////////////////////////////////////////// - - private void LoadLayerAndMaskInfo(PsdBinaryReader reader) - { - Util.DebugMessage(reader.BaseStream, "Load, Begin, Layer and mask info"); - - var layersAndMaskLength = IsLargeDocument - ? reader.ReadInt64() - : reader.ReadUInt32(); - if (layersAndMaskLength <= 0) - return; - - var startPosition = reader.BaseStream.Position; - var endPosition = startPosition + layersAndMaskLength; - - LoadLayers(reader, true); - LoadGlobalLayerMask(reader); - - //----------------------------------------------------------------------- - // Load Additional Layer Information - - while (reader.BaseStream.Position < endPosition) - { - var info = LayerInfoFactory.Load(reader, this, true, endPosition); - AdditionalInfo.Add(info); - - if (info is RawLayerInfo) - { - var layerInfo = (RawLayerInfo)info; - switch (info.Key) - { - case "LMsk": - m_GlobalLayerMaskData = layerInfo.Data; - break; - } - } - } - - Util.DebugMessage(reader.BaseStream, "Load, End, Layer and mask info"); - - //----------------------------------------------------------------------- - // make sure we are not on a wrong offset, so set the stream position - // manually - reader.BaseStream.Position = startPosition + layersAndMaskLength; - } - - /////////////////////////////////////////////////////////////////////////// - - /// - /// Load Layers Info section, including image data. - /// - /// PSD reader. - /// Whether the Layers Info section has a length header. - internal void LoadLayers(PsdBinaryReader reader, bool hasHeader) - { - Util.DebugMessage(reader.BaseStream, "Load, Begin, Layers Info section"); - - long sectionLength = 0; - if (hasHeader) - { - sectionLength = IsLargeDocument - ? reader.ReadInt64() - : reader.ReadUInt32(); - - if (sectionLength <= 0) - { - // The callback may take action when there are 0 layers, so it must - // be called even though the Layers Info section is empty. - LoadContext.OnLoadLayersHeader(this); - Util.DebugMessage(reader.BaseStream, "Load, End, Layers Info section"); - return; - } - } - - var startPosition = reader.BaseStream.Position; - var numLayers = reader.ReadInt16(); - - // If numLayers < 0, then number of layers is absolute value, - // and the first alpha channel contains the transparency data for - // the merged result. - if (numLayers < 0) - { - AbsoluteAlpha = true; - numLayers = Math.Abs(numLayers); - } - - for (int i = 0; i < numLayers; i++) - { - var layer = new Layer(reader, this); - Layers.Add(layer); - } - - // Header is complete just before loading pixel data - LoadContext.OnLoadLayersHeader(this); - - //----------------------------------------------------------------------- - - // Load image data for all channels. - foreach (var layer in Layers) - { - Util.DebugMessage(reader.BaseStream, - "Load, Begin, Layer image, layer.Name"); - foreach (var channel in layer.Channels) - { - channel.LoadPixelData(reader); - } - Util.DebugMessage(reader.BaseStream, - "Load, End, Layer image, layer.Name"); - } - - // Length is set to 0 when called on higher bitdepth layers. - if (sectionLength > 0) - { - // Layers Info section is documented to be even-padded, but Photoshop - // actually pads to 4 bytes. - var endPosition = startPosition + sectionLength; - var positionOffset = reader.BaseStream.Position - endPosition; - Debug.Assert(positionOffset > -4, - "LoadLayers did not read the full length of the Layers Info section."); - Debug.Assert(positionOffset <= 0, - "LoadLayers read past the end of the Layers Info section."); - - - if (reader.BaseStream.Position < endPosition) - reader.BaseStream.Position = endPosition; - } - - Util.DebugMessage(reader.BaseStream, "Load, End, Layers"); - } - - /////////////////////////////////////////////////////////////////////////// - - /// - /// Cleanup - /// - public void Cleanup() - { - var layersAndComposite = Layers.Concat(new[] { BaseLayer }); - - foreach (var lac in layersAndComposite) - { - foreach (var c in lac.Channels) - { - c.Cleanup(); - } - } - } - /////////////////////////////////////////////////////////////////////////// - - /// - /// Decompress the document image data and all the layers' image data, in parallel. - /// - private void DecompressImages() - { - var layersAndComposite = Layers.Concat(new[] { BaseLayer }); - //var channels = layersAndComposite.SelectMany(x => x.Channels); - //Parallel.ForEach(channels, channel => - //{ - // channel.DecodeImageData(); - //}); - foreach (var lac in layersAndComposite) - { - foreach (var c in lac.Channels) - { - c.DecodeImageData(); - } - } - - foreach (var layer in Layers) - { - foreach (var channel in layer.Channels) - { - if (channel.ID == -2) - layer.Masks.LayerMask.ImageData = channel.ImageData; - else if (channel.ID == -3) - layer.Masks.UserMask.ImageData = channel.ImageData; - } - } - } - - /// - /// Verifies that any Additional Info layers are consistent. - /// - private void VerifyInfoLayers() - { - var infoLayersCount = AdditionalInfo.Count(x => x is InfoLayers); - if (infoLayersCount > 1) - { - throw new PsdInvalidException( - "Cannot have more than one InfoLayers in a PSD file."); - } - if ((infoLayersCount > 0) && (Layers.Count == 0)) - { - throw new PsdInvalidException( - "InfoLayers cannot exist when there are 0 layers."); - } - } - - /// - /// Verify validity of layer sections. Each start marker should have a - /// matching end marker. - /// - internal void VerifyLayerSections() - { - int depth = 0; - foreach (var layer in Enumerable.Reverse(Layers)) - { - var layerSectionInfo = layer.AdditionalInfo.SingleOrDefault( - x => x is LayerSectionInfo); - if (layerSectionInfo == null) - continue; - - var sectionInfo = (LayerSectionInfo)layerSectionInfo; - switch (sectionInfo.SectionType) - { - case LayerSectionType.OpenFolder: - case LayerSectionType.ClosedFolder: - depth++; - break; - - case LayerSectionType.SectionDivider: - depth--; - if (depth < 0) - throw new PsdInvalidException("Layer section ended without matching start marker."); - break; - - default: - throw new PsdInvalidException("Unrecognized layer section type."); - } - } - - if (depth != 0) - throw new PsdInvalidException("Layer section not closed by end marker."); - } - - /// - /// Set the VersionInfo resource on the file. - /// - public void SetVersionInfo() - { - var versionInfo = (VersionInfo)ImageResources.Get(ResourceID.VersionInfo); - if (versionInfo == null) - { - versionInfo = new VersionInfo(); - ImageResources.Set(versionInfo); - - // Get the version string. We don't use the fourth part (revision). - var assembly = System.Reflection.Assembly.GetExecutingAssembly(); - var version = assembly.GetName().Version; - var versionString = version.Major + "." + version.Minor + "." + version.Build; - - // Strings are not localized since they are not shown to the user. - versionInfo.Version = 1; - versionInfo.HasRealMergedData = true; - versionInfo.ReaderName = "Paint.NET PSD Plugin"; - versionInfo.WriterName = "Paint.NET PSD Plugin " + versionString; - versionInfo.FileVersion = 1; - } - } - - - /////////////////////////////////////////////////////////////////////////// - - byte[] m_GlobalLayerMaskData; - - private void LoadGlobalLayerMask(PsdBinaryReader reader) - { - Util.DebugMessage(reader.BaseStream, "Load, Begin, GlobalLayerMask"); - - var maskLength = reader.ReadUInt32(); - if (maskLength <= 0) - { - Util.DebugMessage(reader.BaseStream, "Load, End, GlobalLayerMask"); - return; - } - - m_GlobalLayerMaskData = reader.ReadBytes((int)maskLength); - - Util.DebugMessage(reader.BaseStream, "Load, End, GlobalLayerMask"); - } - - public byte[] globalLayerMaskData - { - get { return m_GlobalLayerMaskData; } - } - - #endregion - - /////////////////////////////////////////////////////////////////////////// - - #region Composite image - - /// - /// Represents the composite image. - /// - public Layer BaseLayer { get; set; } - - public ImageCompression ImageCompression { get; set; } - - private void LoadImage(PsdBinaryReader reader) - { - Util.DebugMessage(reader.BaseStream, "Load, Begin, Composite image"); - - ImageCompression = (ImageCompression)reader.ReadInt16(); - - // Create channels - for (Int16 i = 0; i < ChannelCount; i++) - { - Util.DebugMessage(reader.BaseStream, "Load, Begin, Channel image data"); - - var channel = new Channel(i, this.BaseLayer); - channel.ImageCompression = ImageCompression; - channel.Length = this.RowCount - * Util.BytesPerRow(BaseLayer.Rect.Size, BitDepth); - - // The composite image stores all RLE headers up-front, rather than - // with each channel. - if (ImageCompression == ImageCompression.Rle) - { - channel.RleRowLengths = new RleRowLengths(reader, RowCount, IsLargeDocument); - channel.Length = channel.RleRowLengths.Total; - } - - BaseLayer.Channels.Add(channel); - Util.DebugMessage(reader.BaseStream, "Load, End, Channel image data"); - } - - foreach (var channel in this.BaseLayer.Channels) - { - Util.DebugMessage(reader.BaseStream, "Load, Begin, Channel image data"); - Util.CheckByteArrayLength(channel.Length); - channel.ImageDataRaw = reader.ReadBytes((int)channel.Length); - Util.DebugMessage(reader.BaseStream, "Load, End, Channel image data"); - } - - // If there is exactly one more channel than we need, then it is the - // alpha channel. - if ((ColorMode != PsdColorMode.Multichannel) - && (ChannelCount == ColorMode.MinChannelCount() + 1)) - { - var alphaChannel = BaseLayer.Channels.Last(); - alphaChannel.ID = -1; - } - - Util.DebugMessage(reader.BaseStream, "Load, End, Composite image"); - } - - #endregion - } - - - /// - /// The possible Compression methods. - /// - internal enum ImageCompression - { - /// - /// Raw data - /// - Raw = 0, - /// - /// RLE compressed - /// - Rle = 1, - /// - /// ZIP without prediction. - /// - Zip = 2, - /// - /// ZIP with prediction. - /// - ZipPrediction = 3 - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2016 Tao Yue +// +// Portions of this file are provided under the BSD 3-clause License: +// Copyright (c) 2006, Jonas Beckeman +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using PDNWrapper; +using System.IO; +using System.Linq; +using System.Text; +using PaintDotNet.Data.PhotoshopFileType; + +namespace PhotoshopFile +{ + [Flags] + internal enum ELoadFlag + { + Header = 1, + ColorMode = Header | 1 << 2, + ImageData = ColorMode | 1 << 3, + All = Header | ColorMode | ImageData + } + + + internal enum PsdColorMode + { + Bitmap = 0, + Grayscale = 1, + Indexed = 2, + RGB = 3, + CMYK = 4, + Multichannel = 7, + Duotone = 8, + Lab = 9 + }; + + internal enum PsdFileVersion : short + { + Psd = 1, + PsbLargeDocument = 2 + } + + internal class PsdFile + { + #region Constructors + + ELoadFlag m_LoadFlag; + + public PsdFile(PsdFileVersion version = PsdFileVersion.Psd) + { + Version = version; + + BaseLayer = new Layer(this); + ImageResources = new ImageResources(); + Layers = new List(); + AdditionalInfo = new List(); + } + + public PsdFile(string filename, LoadContext loadContext, ELoadFlag loadFlag = ELoadFlag.All) + : this() + { + using (var stream = new FileStream(filename, FileMode.Open)) + { + Load(stream, loadContext, loadFlag); + } + } + + public PsdFile(Stream stream, LoadContext loadContext, ELoadFlag loadFlag = ELoadFlag.All) + : this() + { + Load(stream, loadContext, loadFlag); + } + + #endregion + + #region Load and save + + internal LoadContext LoadContext { get; private set; } + + private void Load(Stream stream, LoadContext loadContext, ELoadFlag loadFlag) + { + LoadContext = loadContext; + var reader = new PsdBinaryReader(stream, loadContext.Encoding); + + if ((loadFlag & ELoadFlag.Header) == ELoadFlag.Header) + LoadHeader(reader); + + if ((loadFlag & ELoadFlag.ColorMode) == ELoadFlag.ColorMode) + LoadColorModeData(reader); + + if ((loadFlag & ELoadFlag.ImageData) == ELoadFlag.ImageData) + { + LoadImageResources(reader); + LoadLayerAndMaskInfo(reader); + + LoadImage(reader); + DecompressImages(); + } + } + + #endregion + + #region Header + + /// + /// Photoshop file format version. + /// + public PsdFileVersion Version { get; private set; } + + public bool IsLargeDocument + { + get { return Version == PsdFileVersion.PsbLargeDocument; } + } + + private Int16 channelCount; + /// + /// The number of channels in the image, including any alpha channels. + /// + public Int16 ChannelCount + { + get { return channelCount; } + set + { + if (value < 1 || value > 56) + throw new ArgumentException("Number of channels must be from 1 to 56."); + channelCount = value; + } + } + + private void CheckDimension(int dimension) + { + if (dimension < 1) + { + throw new ArgumentException("Image dimension must be at least 1."); + } + if ((Version == PsdFileVersion.Psd) && (dimension > 30000)) + { + throw new ArgumentException("PSD image dimension cannot exceed 30000."); + } + if ((Version == PsdFileVersion.PsbLargeDocument) && (dimension > 300000)) + { + throw new ArgumentException("PSB image dimension cannot exceed 300000."); + } + } + + /// + /// The height of the image in pixels. + /// + public int RowCount + { + get { return this.BaseLayer.Rect.Height; } + set + { + CheckDimension(value); + BaseLayer.Rect = new Rectangle(0, 0, BaseLayer.Rect.Width, value); + } + } + + + /// + /// The width of the image in pixels. + /// + public int ColumnCount + { + get { return this.BaseLayer.Rect.Width; } + set + { + CheckDimension(value); + BaseLayer.Rect = new Rectangle(0, 0, value, BaseLayer.Rect.Height); + } + } + + private int bitDepth; + /// + /// The number of bits per channel. Supported values are 1, 8, 16, and 32. + /// + public int BitDepth + { + get { return bitDepth; } + set + { + switch (value) + { + case 1: + case 8: + case 16: + case 32: + bitDepth = value; + break; + default: + throw new NotImplementedException("Invalid bit depth."); + } + } + } + + /// + /// The color mode of the file. + /// + public PsdColorMode ColorMode { get; set; } + + /////////////////////////////////////////////////////////////////////////// + + private void LoadHeader(PsdBinaryReader reader) + { + Util.DebugMessage(reader.BaseStream, "Load, Begin, File header"); + + var signature = reader.ReadAsciiChars(4); + if (signature != "8BPS") + throw new PsdInvalidException("The given stream is not a valid PSD file"); + + Version = (PsdFileVersion)reader.ReadInt16(); + Util.DebugMessage(reader.BaseStream, "Load, Info, Version {0}", (int)Version); + if ((Version != PsdFileVersion.Psd) + && (Version != PsdFileVersion.PsbLargeDocument)) + { + throw new PsdInvalidException("The PSD file has an unknown version"); + } + + //6 bytes reserved + reader.BaseStream.Position += 6; + + this.ChannelCount = reader.ReadInt16(); + this.RowCount = reader.ReadInt32(); + this.ColumnCount = reader.ReadInt32(); + BitDepth = reader.ReadInt16(); + ColorMode = (PsdColorMode)reader.ReadInt16(); + + Util.DebugMessage(reader.BaseStream, "Load, End, File header"); + } + + #endregion + + /////////////////////////////////////////////////////////////////////////// + + #region ColorModeData + + /// + /// If ColorMode is ColorModes.Indexed, the following 768 bytes will contain + /// a 256-color palette. If the ColorMode is ColorModes.Duotone, the data + /// following presumably consists of screen parameters and other related information. + /// Unfortunately, it is intentionally not documented by Adobe, and non-Photoshop + /// readers are advised to treat duotone images as gray-scale images. + /// + public byte[] ColorModeData = new byte[0]; + + private void LoadColorModeData(PsdBinaryReader reader) + { + Util.DebugMessage(reader.BaseStream, "Load, Begin, ColorModeData"); + + var paletteLength = reader.ReadUInt32(); + if (paletteLength > 0) + { + ColorModeData = reader.ReadBytes((int)paletteLength); + } + + Util.DebugMessage(reader.BaseStream, "Load, End, ColorModeData"); + } + + #endregion + + /////////////////////////////////////////////////////////////////////////// + + #region ImageResources + + /// + /// The Image resource blocks for the file + /// + public ImageResources ImageResources { get; set; } + + public ResolutionInfo Resolution + { + get + { + return (ResolutionInfo)ImageResources.Get(ResourceID.ResolutionInfo); + } + + set + { + ImageResources.Set(value); + } + } + + + /////////////////////////////////////////////////////////////////////////// + + private void LoadImageResources(PsdBinaryReader reader) + { + Util.DebugMessage(reader.BaseStream, "Load, Begin, ImageResources"); + + var imageResourcesLength = reader.ReadUInt32(); + if (imageResourcesLength <= 0) + return; + + var startPosition = reader.BaseStream.Position; + var endPosition = startPosition + imageResourcesLength; + while (reader.BaseStream.Position < endPosition) + { + var imageResource = ImageResourceFactory.CreateImageResource(reader); + ImageResources.Add(imageResource); + } + + Util.DebugMessage(reader.BaseStream, "Load, End, ImageResources"); + + //----------------------------------------------------------------------- + // make sure we are not on a wrong offset, so set the stream position + // manually + reader.BaseStream.Position = startPosition + imageResourcesLength; + } + + #endregion + + /////////////////////////////////////////////////////////////////////////// + + #region LayerAndMaskInfo + + public List Layers { get; private set; } + + public List AdditionalInfo { get; private set; } + + public bool AbsoluteAlpha { get; set; } + + /////////////////////////////////////////////////////////////////////////// + + private void LoadLayerAndMaskInfo(PsdBinaryReader reader) + { + Util.DebugMessage(reader.BaseStream, "Load, Begin, Layer and mask info"); + + var layersAndMaskLength = IsLargeDocument + ? reader.ReadInt64() + : reader.ReadUInt32(); + if (layersAndMaskLength <= 0) + return; + + var startPosition = reader.BaseStream.Position; + var endPosition = startPosition + layersAndMaskLength; + + LoadLayers(reader, true); + LoadGlobalLayerMask(reader); + + //----------------------------------------------------------------------- + // Load Additional Layer Information + + while (reader.BaseStream.Position < endPosition) + { + var info = LayerInfoFactory.Load(reader, this, true, endPosition); + AdditionalInfo.Add(info); + + if (info is RawLayerInfo) + { + var layerInfo = (RawLayerInfo)info; + switch (info.Key) + { + case "LMsk": + m_GlobalLayerMaskData = layerInfo.Data; + break; + } + } + } + + Util.DebugMessage(reader.BaseStream, "Load, End, Layer and mask info"); + + //----------------------------------------------------------------------- + // make sure we are not on a wrong offset, so set the stream position + // manually + reader.BaseStream.Position = startPosition + layersAndMaskLength; + } + + /////////////////////////////////////////////////////////////////////////// + + /// + /// Load Layers Info section, including image data. + /// + /// PSD reader. + /// Whether the Layers Info section has a length header. + internal void LoadLayers(PsdBinaryReader reader, bool hasHeader) + { + Util.DebugMessage(reader.BaseStream, "Load, Begin, Layers Info section"); + + long sectionLength = 0; + if (hasHeader) + { + sectionLength = IsLargeDocument + ? reader.ReadInt64() + : reader.ReadUInt32(); + + if (sectionLength <= 0) + { + // The callback may take action when there are 0 layers, so it must + // be called even though the Layers Info section is empty. + LoadContext.OnLoadLayersHeader(this); + Util.DebugMessage(reader.BaseStream, "Load, End, Layers Info section"); + return; + } + } + + var startPosition = reader.BaseStream.Position; + var numLayers = reader.ReadInt16(); + + // If numLayers < 0, then number of layers is absolute value, + // and the first alpha channel contains the transparency data for + // the merged result. + if (numLayers < 0) + { + AbsoluteAlpha = true; + numLayers = Math.Abs(numLayers); + } + + for (int i = 0; i < numLayers; i++) + { + var layer = new Layer(reader, this); + Layers.Add(layer); + } + + // Header is complete just before loading pixel data + LoadContext.OnLoadLayersHeader(this); + + //----------------------------------------------------------------------- + + // Load image data for all channels. + foreach (var layer in Layers) + { + Util.DebugMessage(reader.BaseStream, + "Load, Begin, Layer image, layer.Name"); + foreach (var channel in layer.Channels) + { + channel.LoadPixelData(reader); + } + Util.DebugMessage(reader.BaseStream, + "Load, End, Layer image, layer.Name"); + } + + // Length is set to 0 when called on higher bitdepth layers. + if (sectionLength > 0) + { + // Layers Info section is documented to be even-padded, but Photoshop + // actually pads to 4 bytes. + var endPosition = startPosition + sectionLength; + var positionOffset = reader.BaseStream.Position - endPosition; + Debug.Assert(positionOffset > -4, + "LoadLayers did not read the full length of the Layers Info section."); + Debug.Assert(positionOffset <= 0, + "LoadLayers read past the end of the Layers Info section."); + + + if (reader.BaseStream.Position < endPosition) + reader.BaseStream.Position = endPosition; + } + + Util.DebugMessage(reader.BaseStream, "Load, End, Layers"); + } + + /////////////////////////////////////////////////////////////////////////// + + /// + /// Cleanup + /// + public void Cleanup() + { + var layersAndComposite = Layers.Concat(new[] { BaseLayer }); + + foreach (var lac in layersAndComposite) + { + foreach (var c in lac.Channels) + { + c.Cleanup(); + } + } + } + /////////////////////////////////////////////////////////////////////////// + + /// + /// Decompress the document image data and all the layers' image data, in parallel. + /// + private void DecompressImages() + { + var layersAndComposite = Layers.Concat(new[] { BaseLayer }); + //var channels = layersAndComposite.SelectMany(x => x.Channels); + //Parallel.ForEach(channels, channel => + //{ + // channel.DecodeImageData(); + //}); + foreach (var lac in layersAndComposite) + { + foreach (var c in lac.Channels) + { + c.DecodeImageData(); + } + } + + foreach (var layer in Layers) + { + foreach (var channel in layer.Channels) + { + if (channel.ID == -2) + layer.Masks.LayerMask.ImageData = channel.ImageData; + else if (channel.ID == -3) + layer.Masks.UserMask.ImageData = channel.ImageData; + } + } + } + + /// + /// Verifies that any Additional Info layers are consistent. + /// + private void VerifyInfoLayers() + { + var infoLayersCount = AdditionalInfo.Count(x => x is InfoLayers); + if (infoLayersCount > 1) + { + throw new PsdInvalidException( + "Cannot have more than one InfoLayers in a PSD file."); + } + if ((infoLayersCount > 0) && (Layers.Count == 0)) + { + throw new PsdInvalidException( + "InfoLayers cannot exist when there are 0 layers."); + } + } + + /// + /// Verify validity of layer sections. Each start marker should have a + /// matching end marker. + /// + internal void VerifyLayerSections() + { + int depth = 0; + foreach (var layer in Enumerable.Reverse(Layers)) + { + var layerSectionInfo = layer.AdditionalInfo.SingleOrDefault( + x => x is LayerSectionInfo); + if (layerSectionInfo == null) + continue; + + var sectionInfo = (LayerSectionInfo)layerSectionInfo; + switch (sectionInfo.SectionType) + { + case LayerSectionType.OpenFolder: + case LayerSectionType.ClosedFolder: + depth++; + break; + + case LayerSectionType.SectionDivider: + depth--; + if (depth < 0) + throw new PsdInvalidException("Layer section ended without matching start marker."); + break; + + default: + throw new PsdInvalidException("Unrecognized layer section type."); + } + } + + if (depth != 0) + throw new PsdInvalidException("Layer section not closed by end marker."); + } + + /// + /// Set the VersionInfo resource on the file. + /// + public void SetVersionInfo() + { + var versionInfo = (VersionInfo)ImageResources.Get(ResourceID.VersionInfo); + if (versionInfo == null) + { + versionInfo = new VersionInfo(); + ImageResources.Set(versionInfo); + + // Get the version string. We don't use the fourth part (revision). + var assembly = System.Reflection.Assembly.GetExecutingAssembly(); + var version = assembly.GetName().Version; + var versionString = version.Major + "." + version.Minor + "." + version.Build; + + // Strings are not localized since they are not shown to the user. + versionInfo.Version = 1; + versionInfo.HasRealMergedData = true; + versionInfo.ReaderName = "Paint.NET PSD Plugin"; + versionInfo.WriterName = "Paint.NET PSD Plugin " + versionString; + versionInfo.FileVersion = 1; + } + } + + + /////////////////////////////////////////////////////////////////////////// + + byte[] m_GlobalLayerMaskData; + + private void LoadGlobalLayerMask(PsdBinaryReader reader) + { + Util.DebugMessage(reader.BaseStream, "Load, Begin, GlobalLayerMask"); + + var maskLength = reader.ReadUInt32(); + if (maskLength <= 0) + { + Util.DebugMessage(reader.BaseStream, "Load, End, GlobalLayerMask"); + return; + } + + m_GlobalLayerMaskData = reader.ReadBytes((int)maskLength); + + Util.DebugMessage(reader.BaseStream, "Load, End, GlobalLayerMask"); + } + + public byte[] globalLayerMaskData + { + get { return m_GlobalLayerMaskData; } + } + + #endregion + + /////////////////////////////////////////////////////////////////////////// + + #region Composite image + + /// + /// Represents the composite image. + /// + public Layer BaseLayer { get; set; } + + public ImageCompression ImageCompression { get; set; } + + private void LoadImage(PsdBinaryReader reader) + { + Util.DebugMessage(reader.BaseStream, "Load, Begin, Composite image"); + + ImageCompression = (ImageCompression)reader.ReadInt16(); + + // Create channels + for (Int16 i = 0; i < ChannelCount; i++) + { + Util.DebugMessage(reader.BaseStream, "Load, Begin, Channel image data"); + + var channel = new Channel(i, this.BaseLayer); + channel.ImageCompression = ImageCompression; + channel.Length = this.RowCount + * Util.BytesPerRow(BaseLayer.Rect.Size, BitDepth); + + // The composite image stores all RLE headers up-front, rather than + // with each channel. + if (ImageCompression == ImageCompression.Rle) + { + channel.RleRowLengths = new RleRowLengths(reader, RowCount, IsLargeDocument); + channel.Length = channel.RleRowLengths.Total; + } + + BaseLayer.Channels.Add(channel); + Util.DebugMessage(reader.BaseStream, "Load, End, Channel image data"); + } + + foreach (var channel in this.BaseLayer.Channels) + { + Util.DebugMessage(reader.BaseStream, "Load, Begin, Channel image data"); + Util.CheckByteArrayLength(channel.Length); + channel.ImageDataRaw = reader.ReadBytes((int)channel.Length); + Util.DebugMessage(reader.BaseStream, "Load, End, Channel image data"); + } + + // If there is exactly one more channel than we need, then it is the + // alpha channel. + if ((ColorMode != PsdColorMode.Multichannel) + && (ChannelCount == ColorMode.MinChannelCount() + 1)) + { + var alphaChannel = BaseLayer.Channels.Last(); + alphaChannel.ID = -1; + } + + Util.DebugMessage(reader.BaseStream, "Load, End, Composite image"); + } + + #endregion + } + + + /// + /// The possible Compression methods. + /// + internal enum ImageCompression + { + /// + /// Raw data + /// + Raw = 0, + /// + /// RLE compressed + /// + Rle = 1, + /// + /// ZIP without prediction. + /// + Zip = 2, + /// + /// ZIP with prediction. + /// + ZipPrediction = 3 + } +} diff --git a/Editor/PSDPlugin/PsdFile/PsdFile.cs.meta b/Editor/PSDPlugin/PsdFile/PsdFile.cs.meta index 73bfbb3..1a2cffa 100644 --- a/Editor/PSDPlugin/PsdFile/PsdFile.cs.meta +++ b/Editor/PSDPlugin/PsdFile/PsdFile.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 3de656e186ce0704e8676716fcaf733f -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 3de656e186ce0704e8676716fcaf733f +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/RleReader.cs b/Editor/PSDPlugin/PsdFile/RleReader.cs index 008d3be..67f9725 100644 --- a/Editor/PSDPlugin/PsdFile/RleReader.cs +++ b/Editor/PSDPlugin/PsdFile/RleReader.cs @@ -1,106 +1,106 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2013 Tao Yue -// -// Portions of this file are provided under the BSD 3-clause License: -// Copyright (c) 2006, Jonas Beckeman -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using System.Diagnostics; -using System.IO; - - -namespace PhotoshopFile -{ - internal class RleReader - { - private Stream stream; - - public RleReader(Stream stream) - { - this.stream = stream; - } - - /// - /// Decodes a PackBits RLE stream. - /// - /// Output buffer for decoded data. - /// Offset at which to begin writing. - /// Number of bytes to decode from the stream. - public int Read(byte[] buffer, int offset, int count) - { - if (!Util.CheckBufferBounds(buffer, offset, count)) - throw new ArgumentOutOfRangeException(); - - // Pin the entire buffer now, so that we don't keep pinning and unpinning - // for each RLE packet. - var ptrBuffer = buffer; - //fixed (byte* ptrBuffer = &buffer[0]) - { - int bytesLeft = count; - int bufferIdx = offset; - while (bytesLeft > 0) - { - // ReadByte returns an unsigned byte, but we want a signed byte. - var flagCounter = unchecked((sbyte)stream.ReadByte()); - - // Raw packet - if (flagCounter > 0) - { - var readLength = flagCounter + 1; - if (bytesLeft < readLength) - throw new RleException("Raw packet overruns the decode window."); - - stream.Read(buffer, bufferIdx, readLength); - - bufferIdx += readLength; - bytesLeft -= readLength; - } - // RLE packet - else if (flagCounter > -128) - { - var runLength = 1 - flagCounter; - var byteValue = (byte)stream.ReadByte(); - if (runLength > bytesLeft) - throw new RleException("RLE packet overruns the decode window."); - - //byte* ptr = ptrBuffer + bufferIdx; - //byte* ptrEnd = ptr + runLength; - //while (ptr < ptrEnd) - //{ - // *ptr = byteValue; - // ptr++; - //} - - int start = 0; - while (start < runLength) - { - ptrBuffer[bufferIdx + start] = byteValue; - start++; - } - - bufferIdx += runLength; - bytesLeft -= runLength; - } - else - { - // The canonical PackBits algorithm will never emit 0x80 (-128), but - // some programs do. Simply skip over the byte. - } - } - - Debug.Assert(bytesLeft == 0); - return count - bytesLeft; - } - } - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2013 Tao Yue +// +// Portions of this file are provided under the BSD 3-clause License: +// Copyright (c) 2006, Jonas Beckeman +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Diagnostics; +using System.IO; + + +namespace PhotoshopFile +{ + internal class RleReader + { + private Stream stream; + + public RleReader(Stream stream) + { + this.stream = stream; + } + + /// + /// Decodes a PackBits RLE stream. + /// + /// Output buffer for decoded data. + /// Offset at which to begin writing. + /// Number of bytes to decode from the stream. + public int Read(byte[] buffer, int offset, int count) + { + if (!Util.CheckBufferBounds(buffer, offset, count)) + throw new ArgumentOutOfRangeException(); + + // Pin the entire buffer now, so that we don't keep pinning and unpinning + // for each RLE packet. + var ptrBuffer = buffer; + //fixed (byte* ptrBuffer = &buffer[0]) + { + int bytesLeft = count; + int bufferIdx = offset; + while (bytesLeft > 0) + { + // ReadByte returns an unsigned byte, but we want a signed byte. + var flagCounter = unchecked((sbyte)stream.ReadByte()); + + // Raw packet + if (flagCounter > 0) + { + var readLength = flagCounter + 1; + if (bytesLeft < readLength) + throw new RleException("Raw packet overruns the decode window."); + + stream.Read(buffer, bufferIdx, readLength); + + bufferIdx += readLength; + bytesLeft -= readLength; + } + // RLE packet + else if (flagCounter > -128) + { + var runLength = 1 - flagCounter; + var byteValue = (byte)stream.ReadByte(); + if (runLength > bytesLeft) + throw new RleException("RLE packet overruns the decode window."); + + //byte* ptr = ptrBuffer + bufferIdx; + //byte* ptrEnd = ptr + runLength; + //while (ptr < ptrEnd) + //{ + // *ptr = byteValue; + // ptr++; + //} + + int start = 0; + while (start < runLength) + { + ptrBuffer[bufferIdx + start] = byteValue; + start++; + } + + bufferIdx += runLength; + bytesLeft -= runLength; + } + else + { + // The canonical PackBits algorithm will never emit 0x80 (-128), but + // some programs do. Simply skip over the byte. + } + } + + Debug.Assert(bytesLeft == 0); + return count - bytesLeft; + } + } + } +} diff --git a/Editor/PSDPlugin/PsdFile/RleReader.cs.meta b/Editor/PSDPlugin/PsdFile/RleReader.cs.meta index 01cfc72..eb7a81b 100644 --- a/Editor/PSDPlugin/PsdFile/RleReader.cs.meta +++ b/Editor/PSDPlugin/PsdFile/RleReader.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: f9404b28690a74b4f918e7006968dd80 -timeCreated: 1495006554 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: f9404b28690a74b4f918e7006968dd80 +timeCreated: 1495006554 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/RleRowLengths.cs b/Editor/PSDPlugin/PsdFile/RleRowLengths.cs index 4ef6c37..57dbb0f 100644 --- a/Editor/PSDPlugin/PsdFile/RleRowLengths.cs +++ b/Editor/PSDPlugin/PsdFile/RleRowLengths.cs @@ -1,50 +1,50 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2014 Tao Yue -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using System.Linq; - -namespace PhotoshopFile -{ - internal class RleRowLengths - { - public int[] Values { get; private set; } - - public long Total - { - get { return Values.Sum(x => (long)x); } - } - - public int this[int i] - { - get { return Values[i]; } - set { Values[i] = value; } - } - - public RleRowLengths(int rowCount) - { - Values = new int[rowCount]; - } - - public RleRowLengths(PsdBinaryReader reader, int rowCount, bool isLargeDocument) - : this(rowCount) - { - for (int i = 0; i < rowCount; i++) - { - Values[i] = isLargeDocument - ? reader.ReadInt32() - : reader.ReadUInt16(); - } - } - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2014 Tao Yue +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Linq; + +namespace PhotoshopFile +{ + internal class RleRowLengths + { + public int[] Values { get; private set; } + + public long Total + { + get { return Values.Sum(x => (long)x); } + } + + public int this[int i] + { + get { return Values[i]; } + set { Values[i] = value; } + } + + public RleRowLengths(int rowCount) + { + Values = new int[rowCount]; + } + + public RleRowLengths(PsdBinaryReader reader, int rowCount, bool isLargeDocument) + : this(rowCount) + { + for (int i = 0; i < rowCount; i++) + { + Values[i] = isLargeDocument + ? reader.ReadInt32() + : reader.ReadUInt16(); + } + } + } +} diff --git a/Editor/PSDPlugin/PsdFile/RleRowLengths.cs.meta b/Editor/PSDPlugin/PsdFile/RleRowLengths.cs.meta index a063a83..36bebe0 100644 --- a/Editor/PSDPlugin/PsdFile/RleRowLengths.cs.meta +++ b/Editor/PSDPlugin/PsdFile/RleRowLengths.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: ef0d2c47c58545249b479bc1706d89b7 -timeCreated: 1495006554 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: ef0d2c47c58545249b479bc1706d89b7 +timeCreated: 1495006554 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/RleWriter.cs b/Editor/PSDPlugin/PsdFile/RleWriter.cs index 11486fa..f53a768 100644 --- a/Editor/PSDPlugin/PsdFile/RleWriter.cs +++ b/Editor/PSDPlugin/PsdFile/RleWriter.cs @@ -1,230 +1,230 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2015 Tao Yue -// -// Portions of this file are provided under the BSD 3-clause License: -// Copyright (c) 2006, Jonas Beckeman -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using System.Diagnostics; -using System.IO; -using UnityEngine.Assertions; - -namespace PhotoshopFile -{ - internal class RleWriter - { - private int maxPacketLength = 128; - - // Current task - private object rleLock; - private Stream stream; - private byte[] data; - private int offset; - - // Current packet - private bool isRepeatPacket; - private int idxPacketStart; - private int packetLength; - - private byte runValue; - private int runLength; - - public RleWriter(Stream stream) - { - rleLock = new object(); - this.stream = stream; - } - - /// - /// Encodes byte data using PackBits RLE compression. - /// - /// Raw data to be encoded. - /// Offset at which to begin transferring data. - /// Number of bytes of data to transfer. - /// Number of compressed bytes written to the stream. - /// - /// There are multiple ways to encode two-byte runs: - /// 1. Apple PackBits only encodes three-byte runs as repeats. - /// 2. Adobe Photoshop encodes two-byte runs as repeats, unless preceded - /// by literals. - /// 3. TIFF PackBits recommends that two-byte runs be encoded as repeats, - /// unless preceded *and* followed by literals. - /// - /// This class adopts the Photoshop behavior, as it has slightly better - /// compression efficiency than Apple PackBits, and is easier to implement - /// than TIFF PackBits. - /// - public int Write(byte[] data, int offset, int count) - { - if (!Util.CheckBufferBounds(data, offset, count)) - throw new ArgumentOutOfRangeException(); - - // We cannot encode a count of 0, because the PackBits flag-counter byte - // uses 0 to indicate a length of 1. - if (count == 0) - { - throw new ArgumentOutOfRangeException("count"); - } - - lock (rleLock) - { - var startPosition = stream.Position; - - this.data = data; - this.offset = offset; - //fixed (byte* ptrData = &data[0]) - { - //byte* ptr = ptrData + offset; - //byte* ptrEnd = ptr + count; - //var bytesEncoded = EncodeToStream(ptr, ptrEnd); - //Debug.Assert(bytesEncoded == count, "Encoded byte count should match the argument."); - var bytesEncoded = EncodeToStream(data, offset, offset + count); - Assert.AreEqual(bytesEncoded, count, "Encoded byte count should match the argument."); - } - - return (int)(stream.Position - startPosition); - } - } - - private void ClearPacket() - { - this.isRepeatPacket = false; - this.packetLength = 0; - } - - private void WriteRepeatPacket(int length) - { - var header = unchecked((byte)(1 - length)); - stream.WriteByte(header); - stream.WriteByte(runValue); - } - - private void WriteLiteralPacket(int length) - { - var header = unchecked((byte)(length - 1)); - stream.WriteByte(header); - stream.Write(data, idxPacketStart, length); - } - - private void WritePacket() - { - if (isRepeatPacket) - WriteRepeatPacket(packetLength); - else - WriteLiteralPacket(packetLength); - } - - private void StartPacket(int count, - bool isRepeatPacket, int runLength, byte value) - { - this.isRepeatPacket = isRepeatPacket; - - this.packetLength = runLength; - this.runLength = runLength; - this.runValue = value; - - this.idxPacketStart = offset + count; - } - - private void ExtendPacketAndRun(byte value) - { - packetLength++; - runLength++; - } - - private void ExtendPacketStartNewRun(byte value) - { - packetLength++; - runLength = 1; - runValue = value; - } - - private int EncodeToStream(byte[] ptr, int start, int end /*byte* ptr, byte* ptrEnd*/) - { - // Begin the first packet. - StartPacket(0, false, 1, ptr[start]); - int numBytesEncoded = 1; - start++; - - // Loop invariant: Packet is never empty. - while (start < end) - { - var value = ptr[start]; - - if (packetLength == 1) - { - isRepeatPacket = (value == runValue); - if (isRepeatPacket) - ExtendPacketAndRun(value); - else - ExtendPacketStartNewRun(value); - } - else if (packetLength == maxPacketLength) - { - // Packet is full, so write it out and start a new one. - WritePacket(); - StartPacket(numBytesEncoded, false, 1, value); - } - else if (isRepeatPacket) - { - // Decide whether to continue the repeat packet. - if (value == runValue) - ExtendPacketAndRun(value); - else - { - // Different color, so terminate the run and start a new packet. - WriteRepeatPacket(packetLength); - StartPacket(numBytesEncoded, false, 1, value); - } - } - else - { - // Decide whether to continue the literal packet. - if (value == runValue) - { - ExtendPacketAndRun(value); - - // A 3-byte run terminates the literal and starts a new repeat - // packet. That's because the 3-byte run can be encoded as a - // 2-byte repeat. So even if the run ends at 3, we've already - // paid for the next flag-counter byte. - if (runLength == 3) - { - // The 3-byte run can come in the middle of a literal packet, - // but not at the beginning. The first 2 bytes of the run - // should've triggered a repeat packet. - Debug.Assert(packetLength > 3); - - // -2 because numBytesEncoded has not yet been incremented - WriteLiteralPacket(packetLength - 3); - StartPacket(numBytesEncoded - 2, true, 3, value); - } - } - else - { - ExtendPacketStartNewRun(value); - } - } - - start++; - numBytesEncoded++; - } - - // Loop terminates with a non-empty packet waiting to be written out. - WritePacket(); - ClearPacket(); - - return numBytesEncoded; - } - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2015 Tao Yue +// +// Portions of this file are provided under the BSD 3-clause License: +// Copyright (c) 2006, Jonas Beckeman +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Diagnostics; +using System.IO; +using UnityEngine.Assertions; + +namespace PhotoshopFile +{ + internal class RleWriter + { + private int maxPacketLength = 128; + + // Current task + private object rleLock; + private Stream stream; + private byte[] data; + private int offset; + + // Current packet + private bool isRepeatPacket; + private int idxPacketStart; + private int packetLength; + + private byte runValue; + private int runLength; + + public RleWriter(Stream stream) + { + rleLock = new object(); + this.stream = stream; + } + + /// + /// Encodes byte data using PackBits RLE compression. + /// + /// Raw data to be encoded. + /// Offset at which to begin transferring data. + /// Number of bytes of data to transfer. + /// Number of compressed bytes written to the stream. + /// + /// There are multiple ways to encode two-byte runs: + /// 1. Apple PackBits only encodes three-byte runs as repeats. + /// 2. Adobe Photoshop encodes two-byte runs as repeats, unless preceded + /// by literals. + /// 3. TIFF PackBits recommends that two-byte runs be encoded as repeats, + /// unless preceded *and* followed by literals. + /// + /// This class adopts the Photoshop behavior, as it has slightly better + /// compression efficiency than Apple PackBits, and is easier to implement + /// than TIFF PackBits. + /// + public int Write(byte[] data, int offset, int count) + { + if (!Util.CheckBufferBounds(data, offset, count)) + throw new ArgumentOutOfRangeException(); + + // We cannot encode a count of 0, because the PackBits flag-counter byte + // uses 0 to indicate a length of 1. + if (count == 0) + { + throw new ArgumentOutOfRangeException("count"); + } + + lock (rleLock) + { + var startPosition = stream.Position; + + this.data = data; + this.offset = offset; + //fixed (byte* ptrData = &data[0]) + { + //byte* ptr = ptrData + offset; + //byte* ptrEnd = ptr + count; + //var bytesEncoded = EncodeToStream(ptr, ptrEnd); + //Debug.Assert(bytesEncoded == count, "Encoded byte count should match the argument."); + var bytesEncoded = EncodeToStream(data, offset, offset + count); + Assert.AreEqual(bytesEncoded, count, "Encoded byte count should match the argument."); + } + + return (int)(stream.Position - startPosition); + } + } + + private void ClearPacket() + { + this.isRepeatPacket = false; + this.packetLength = 0; + } + + private void WriteRepeatPacket(int length) + { + var header = unchecked((byte)(1 - length)); + stream.WriteByte(header); + stream.WriteByte(runValue); + } + + private void WriteLiteralPacket(int length) + { + var header = unchecked((byte)(length - 1)); + stream.WriteByte(header); + stream.Write(data, idxPacketStart, length); + } + + private void WritePacket() + { + if (isRepeatPacket) + WriteRepeatPacket(packetLength); + else + WriteLiteralPacket(packetLength); + } + + private void StartPacket(int count, + bool isRepeatPacket, int runLength, byte value) + { + this.isRepeatPacket = isRepeatPacket; + + this.packetLength = runLength; + this.runLength = runLength; + this.runValue = value; + + this.idxPacketStart = offset + count; + } + + private void ExtendPacketAndRun(byte value) + { + packetLength++; + runLength++; + } + + private void ExtendPacketStartNewRun(byte value) + { + packetLength++; + runLength = 1; + runValue = value; + } + + private int EncodeToStream(byte[] ptr, int start, int end /*byte* ptr, byte* ptrEnd*/) + { + // Begin the first packet. + StartPacket(0, false, 1, ptr[start]); + int numBytesEncoded = 1; + start++; + + // Loop invariant: Packet is never empty. + while (start < end) + { + var value = ptr[start]; + + if (packetLength == 1) + { + isRepeatPacket = (value == runValue); + if (isRepeatPacket) + ExtendPacketAndRun(value); + else + ExtendPacketStartNewRun(value); + } + else if (packetLength == maxPacketLength) + { + // Packet is full, so write it out and start a new one. + WritePacket(); + StartPacket(numBytesEncoded, false, 1, value); + } + else if (isRepeatPacket) + { + // Decide whether to continue the repeat packet. + if (value == runValue) + ExtendPacketAndRun(value); + else + { + // Different color, so terminate the run and start a new packet. + WriteRepeatPacket(packetLength); + StartPacket(numBytesEncoded, false, 1, value); + } + } + else + { + // Decide whether to continue the literal packet. + if (value == runValue) + { + ExtendPacketAndRun(value); + + // A 3-byte run terminates the literal and starts a new repeat + // packet. That's because the 3-byte run can be encoded as a + // 2-byte repeat. So even if the run ends at 3, we've already + // paid for the next flag-counter byte. + if (runLength == 3) + { + // The 3-byte run can come in the middle of a literal packet, + // but not at the beginning. The first 2 bytes of the run + // should've triggered a repeat packet. + Debug.Assert(packetLength > 3); + + // -2 because numBytesEncoded has not yet been incremented + WriteLiteralPacket(packetLength - 3); + StartPacket(numBytesEncoded - 2, true, 3, value); + } + } + else + { + ExtendPacketStartNewRun(value); + } + } + + start++; + numBytesEncoded++; + } + + // Loop terminates with a non-empty packet waiting to be written out. + WritePacket(); + ClearPacket(); + + return numBytesEncoded; + } + } +} diff --git a/Editor/PSDPlugin/PsdFile/RleWriter.cs.meta b/Editor/PSDPlugin/PsdFile/RleWriter.cs.meta index e5878f0..109b125 100644 --- a/Editor/PSDPlugin/PsdFile/RleWriter.cs.meta +++ b/Editor/PSDPlugin/PsdFile/RleWriter.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 6fcbb5d3e3f3adf479ac8a933b929a8a -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 6fcbb5d3e3f3adf479ac8a933b929a8a +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdFile/Util.cs b/Editor/PSDPlugin/PsdFile/Util.cs index c6fadc7..e33ab26 100644 --- a/Editor/PSDPlugin/PsdFile/Util.cs +++ b/Editor/PSDPlugin/PsdFile/Util.cs @@ -1,390 +1,390 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Photoshop PSD FileType Plugin for Paint.NET -// http://psdplugin.codeplex.com/ -// -// This software is provided under the MIT License: -// Copyright (c) 2006-2007 Frank Blumenberg -// Copyright (c) 2010-2016 Tao Yue -// -// See LICENSE.txt for complete licensing and attribution information. -// -///////////////////////////////////////////////////////////////////////////////// - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using PDNWrapper; -using System.IO; -using System.Linq; -using System.Text; -using Unity.Collections; - -namespace PhotoshopFile -{ - internal static class Util - { - [DebuggerDisplay("Top = {Top}, Bottom = {Bottom}, Left = {Left}, Right = {Right}")] - internal struct RectanglePosition - { - public int Top { get; set; } - public int Bottom { get; set; } - public int Left { get; set; } - public int Right { get; set; } - } - - public static Rectangle IntersectWith( - this Rectangle thisRect, Rectangle rect) - { - thisRect.Intersect(rect); - return thisRect; - } - - /////////////////////////////////////////////////////////////////////////// - - /// - /// Fills a buffer with a byte value. - /// - static public void Fill(byte[] ptr, int start, int end, byte value) - { - while (start < end) - { - ptr[start] = value; - start++; - } - } - - static public void Invert(byte[] ptr, int ptrStart, int ptrEnd) - { - while (ptrStart < ptrEnd) - { - ptr[ptrStart] = (byte)(ptr[ptrStart] ^ 0xff); - ptrStart++; - } - } - - /// - /// Fills a buffer with a byte value. - /// - static public void Fill(NativeArray ptr, int start, int end, byte value) - { - while (start < end) - { - ptr[start] = value; - start++; - } - } - - static public void Invert(NativeArray ptr, int ptrStart, int ptrEnd) - { - while (ptrStart < ptrEnd) - { - ptr[ptrStart] = (byte)(ptr[ptrStart] ^ 0xff); - ptrStart++; - } - } - - /////////////////////////////////////////////////////////////////////////// - - /// - /// Reverses the endianness of a 2-byte word. - /// - static public void SwapBytes2(byte[] ptr, int start) - { - byte byte0 = ptr[start]; - ptr[start] = ptr[start + 1]; - ptr[start + 1] = byte0; - } - - /////////////////////////////////////////////////////////////////////////// - - /// - /// Reverses the endianness of a 4-byte word. - /// - static public void SwapBytes4(byte[] ptr, int start) - { - byte byte0 = ptr[start]; - byte byte1 = ptr[start + 1]; - - ptr[start] = ptr[start + 3]; - ptr[start + 1] = ptr[start + 2]; - ptr[start + 2] = byte1; - ptr[start + 3] = byte0; - } - - /// - /// Reverses the endianness of a word of arbitrary length. - /// - static public void SwapBytes(byte[] ptr, int start, int nLength) - { - for (long i = 0; i < nLength / 2; ++i) - { - byte t = ptr[start + i]; - ptr[start + i] = ptr[start + nLength - i - 1]; - ptr[start + nLength - i - 1] = t; - } - } - - /////////////////////////////////////////////////////////////////////////// - - public static void SwapByteArray(int bitDepth, - byte[] byteArray, int startIdx, int count) - { - switch (bitDepth) - { - case 1: - case 8: - break; - - case 16: - SwapByteArray2(byteArray, startIdx, count); - break; - - case 32: - SwapByteArray4(byteArray, startIdx, count); - break; - - default: - throw new Exception( - "Byte-swapping implemented only for 16-bit and 32-bit depths."); - } - } - - /// - /// Reverses the endianness of 2-byte words in a byte array. - /// - /// Byte array containing the sequence on which to swap endianness - /// Byte index of the first word to swap - /// Number of words to swap - public static void SwapByteArray2(byte[] byteArray, int startIdx, int count) - { - int endIdx = startIdx + count * 2; - if (byteArray.Length < endIdx) - throw new IndexOutOfRangeException(); - - - { - //fixed (byte* arrayPtr = &byteArray[0]) - { - //byte* ptr = arrayPtr + startIdx; - //byte* endPtr = arrayPtr + endIdx; - while (startIdx < endIdx) - { - SwapBytes2(byteArray, startIdx); - startIdx += 2; - } - } - } - } - - /// - /// Reverses the endianness of 4-byte words in a byte array. - /// - /// Byte array containing the sequence on which to swap endianness - /// Byte index of the first word to swap - /// Number of words to swap - public static void SwapByteArray4(byte[] byteArray, int startIdx, int count) - { - int endIdx = startIdx + count * 4; - if (byteArray.Length < endIdx) - throw new IndexOutOfRangeException(); - - - { - //fixed (byte* arrayPtr = &byteArray[0]) - { - //byte* ptr = arrayPtr + startIdx; - //byte* endPtr = arrayPtr + endIdx; - while (startIdx < endIdx) - { - SwapBytes4(byteArray, startIdx); - startIdx += 4; - } - } - } - } - - /////////////////////////////////////////////////////////////////////////// - - /// - /// Calculates the number of bytes required to store a row of an image - /// with the specified bit depth. - /// - /// The size of the image in pixels. - /// The bit depth of the image. - /// The number of bytes needed to store a row of the image. - public static int BytesPerRow(Size size, int bitDepth) - { - switch (bitDepth) - { - case 1: - return (size.Width + 7) / 8; - default: - return size.Width * BytesFromBitDepth(bitDepth); - } - } - - /// - /// Round the integer to a multiple. - /// - public static int RoundUp(int value, int multiple) - { - if (value == 0) - return 0; - - if (Math.Sign(value) != Math.Sign(multiple)) - { - throw new ArgumentException( - "value and multiple cannot have opposite signs."); - } - - var remainder = value % multiple; - if (remainder > 0) - { - value += (multiple - remainder); - } - return value; - } - - /// - /// Get number of bytes required to pad to the specified multiple. - /// - public static int GetPadding(int length, int padMultiple) - { - if ((length < 0) || (padMultiple < 0)) - throw new ArgumentException(); - - var remainder = length % padMultiple; - if (remainder == 0) - return 0; - - var padding = padMultiple - remainder; - return padding; - } - - /// - /// Returns the number of bytes needed to store a single pixel of the - /// specified bit depth. - /// - public static int BytesFromBitDepth(int depth) - { - switch (depth) - { - case 1: - case 8: - return 1; - case 16: - return 2; - case 32: - return 4; - default: - throw new ArgumentException("Invalid bit depth."); - } - } - - public static short MinChannelCount(this PsdColorMode colorMode) - { - switch (colorMode) - { - case PsdColorMode.Bitmap: - case PsdColorMode.Duotone: - case PsdColorMode.Grayscale: - case PsdColorMode.Indexed: - case PsdColorMode.Multichannel: - return 1; - case PsdColorMode.Lab: - case PsdColorMode.RGB: - return 3; - case PsdColorMode.CMYK: - return 4; - } - - throw new ArgumentException("Unknown color mode."); - } - - /// - /// Verify that the offset and count will remain within the bounds of the - /// buffer. - /// - /// True if in bounds, false if out of bounds. - public static bool CheckBufferBounds(byte[] data, int offset, int count) - { - if (offset < 0) - return false; - if (count < 0) - return false; - if (offset + count > data.Length) - return false; - - return true; - } - - public static void CheckByteArrayLength(long length) - { - if (length < 0) - { - throw new Exception("Byte array cannot have a negative length."); - } - if (length > 0x7fffffc7) - { - throw new OutOfMemoryException( - "Byte array cannot exceed 2,147,483,591 in length."); - } - } - - /// - /// Writes a message to the debug console, indicating the current position - /// in the stream in both decimal and hexadecimal formats. - /// - [Conditional("DEBUG")] - public static void DebugMessage(Stream stream, string message, - params object[] args) - { - //var formattedMessage = String.Format(message, args); - //Debug.WriteLine("0x{0:x}, {0}, {1}", - //stream.Position, formattedMessage); - } - } - - /// - /// Fixed-point decimal, with 16-bit integer and 16-bit fraction. - /// - internal class UFixed16_16 - { - public UInt16 Integer { get; set; } - public UInt16 Fraction { get; set; } - - public UFixed16_16(UInt16 integer, UInt16 fraction) - { - Integer = integer; - Fraction = fraction; - } - - /// - /// Split the high and low words of a 32-bit unsigned integer into a - /// fixed-point number. - /// - public UFixed16_16(UInt32 value) - { - Integer = (UInt16)(value >> 16); - Fraction = (UInt16)(value & 0x0000ffff); - } - - public UFixed16_16(double value) - { - if (value >= 65536.0) throw new OverflowException(); - if (value < 0) throw new OverflowException(); - - Integer = (UInt16)value; - - // Round instead of truncate, because doubles may not represent the - // fraction exactly. - Fraction = (UInt16)((value - Integer) * 65536 + 0.5); - } - - public static implicit operator double(UFixed16_16 value) - { - return (double)value.Integer + value.Fraction / 65536.0; - } - } -} +///////////////////////////////////////////////////////////////////////////////// +// +// Photoshop PSD FileType Plugin for Paint.NET +// http://psdplugin.codeplex.com/ +// +// This software is provided under the MIT License: +// Copyright (c) 2006-2007 Frank Blumenberg +// Copyright (c) 2010-2016 Tao Yue +// +// See LICENSE.txt for complete licensing and attribution information. +// +///////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using PDNWrapper; +using System.IO; +using System.Linq; +using System.Text; +using Unity.Collections; + +namespace PhotoshopFile +{ + internal static class Util + { + [DebuggerDisplay("Top = {Top}, Bottom = {Bottom}, Left = {Left}, Right = {Right}")] + internal struct RectanglePosition + { + public int Top { get; set; } + public int Bottom { get; set; } + public int Left { get; set; } + public int Right { get; set; } + } + + public static Rectangle IntersectWith( + this Rectangle thisRect, Rectangle rect) + { + thisRect.Intersect(rect); + return thisRect; + } + + /////////////////////////////////////////////////////////////////////////// + + /// + /// Fills a buffer with a byte value. + /// + static public void Fill(byte[] ptr, int start, int end, byte value) + { + while (start < end) + { + ptr[start] = value; + start++; + } + } + + static public void Invert(byte[] ptr, int ptrStart, int ptrEnd) + { + while (ptrStart < ptrEnd) + { + ptr[ptrStart] = (byte)(ptr[ptrStart] ^ 0xff); + ptrStart++; + } + } + + /// + /// Fills a buffer with a byte value. + /// + static public void Fill(NativeArray ptr, int start, int end, byte value) + { + while (start < end) + { + ptr[start] = value; + start++; + } + } + + static public void Invert(NativeArray ptr, int ptrStart, int ptrEnd) + { + while (ptrStart < ptrEnd) + { + ptr[ptrStart] = (byte)(ptr[ptrStart] ^ 0xff); + ptrStart++; + } + } + + /////////////////////////////////////////////////////////////////////////// + + /// + /// Reverses the endianness of a 2-byte word. + /// + static public void SwapBytes2(byte[] ptr, int start) + { + byte byte0 = ptr[start]; + ptr[start] = ptr[start + 1]; + ptr[start + 1] = byte0; + } + + /////////////////////////////////////////////////////////////////////////// + + /// + /// Reverses the endianness of a 4-byte word. + /// + static public void SwapBytes4(byte[] ptr, int start) + { + byte byte0 = ptr[start]; + byte byte1 = ptr[start + 1]; + + ptr[start] = ptr[start + 3]; + ptr[start + 1] = ptr[start + 2]; + ptr[start + 2] = byte1; + ptr[start + 3] = byte0; + } + + /// + /// Reverses the endianness of a word of arbitrary length. + /// + static public void SwapBytes(byte[] ptr, int start, int nLength) + { + for (long i = 0; i < nLength / 2; ++i) + { + byte t = ptr[start + i]; + ptr[start + i] = ptr[start + nLength - i - 1]; + ptr[start + nLength - i - 1] = t; + } + } + + /////////////////////////////////////////////////////////////////////////// + + public static void SwapByteArray(int bitDepth, + byte[] byteArray, int startIdx, int count) + { + switch (bitDepth) + { + case 1: + case 8: + break; + + case 16: + SwapByteArray2(byteArray, startIdx, count); + break; + + case 32: + SwapByteArray4(byteArray, startIdx, count); + break; + + default: + throw new Exception( + "Byte-swapping implemented only for 16-bit and 32-bit depths."); + } + } + + /// + /// Reverses the endianness of 2-byte words in a byte array. + /// + /// Byte array containing the sequence on which to swap endianness + /// Byte index of the first word to swap + /// Number of words to swap + public static void SwapByteArray2(byte[] byteArray, int startIdx, int count) + { + int endIdx = startIdx + count * 2; + if (byteArray.Length < endIdx) + throw new IndexOutOfRangeException(); + + + { + //fixed (byte* arrayPtr = &byteArray[0]) + { + //byte* ptr = arrayPtr + startIdx; + //byte* endPtr = arrayPtr + endIdx; + while (startIdx < endIdx) + { + SwapBytes2(byteArray, startIdx); + startIdx += 2; + } + } + } + } + + /// + /// Reverses the endianness of 4-byte words in a byte array. + /// + /// Byte array containing the sequence on which to swap endianness + /// Byte index of the first word to swap + /// Number of words to swap + public static void SwapByteArray4(byte[] byteArray, int startIdx, int count) + { + int endIdx = startIdx + count * 4; + if (byteArray.Length < endIdx) + throw new IndexOutOfRangeException(); + + + { + //fixed (byte* arrayPtr = &byteArray[0]) + { + //byte* ptr = arrayPtr + startIdx; + //byte* endPtr = arrayPtr + endIdx; + while (startIdx < endIdx) + { + SwapBytes4(byteArray, startIdx); + startIdx += 4; + } + } + } + } + + /////////////////////////////////////////////////////////////////////////// + + /// + /// Calculates the number of bytes required to store a row of an image + /// with the specified bit depth. + /// + /// The size of the image in pixels. + /// The bit depth of the image. + /// The number of bytes needed to store a row of the image. + public static int BytesPerRow(Size size, int bitDepth) + { + switch (bitDepth) + { + case 1: + return (size.Width + 7) / 8; + default: + return size.Width * BytesFromBitDepth(bitDepth); + } + } + + /// + /// Round the integer to a multiple. + /// + public static int RoundUp(int value, int multiple) + { + if (value == 0) + return 0; + + if (Math.Sign(value) != Math.Sign(multiple)) + { + throw new ArgumentException( + "value and multiple cannot have opposite signs."); + } + + var remainder = value % multiple; + if (remainder > 0) + { + value += (multiple - remainder); + } + return value; + } + + /// + /// Get number of bytes required to pad to the specified multiple. + /// + public static int GetPadding(int length, int padMultiple) + { + if ((length < 0) || (padMultiple < 0)) + throw new ArgumentException(); + + var remainder = length % padMultiple; + if (remainder == 0) + return 0; + + var padding = padMultiple - remainder; + return padding; + } + + /// + /// Returns the number of bytes needed to store a single pixel of the + /// specified bit depth. + /// + public static int BytesFromBitDepth(int depth) + { + switch (depth) + { + case 1: + case 8: + return 1; + case 16: + return 2; + case 32: + return 4; + default: + throw new ArgumentException("Invalid bit depth."); + } + } + + public static short MinChannelCount(this PsdColorMode colorMode) + { + switch (colorMode) + { + case PsdColorMode.Bitmap: + case PsdColorMode.Duotone: + case PsdColorMode.Grayscale: + case PsdColorMode.Indexed: + case PsdColorMode.Multichannel: + return 1; + case PsdColorMode.Lab: + case PsdColorMode.RGB: + return 3; + case PsdColorMode.CMYK: + return 4; + } + + throw new ArgumentException("Unknown color mode."); + } + + /// + /// Verify that the offset and count will remain within the bounds of the + /// buffer. + /// + /// True if in bounds, false if out of bounds. + public static bool CheckBufferBounds(byte[] data, int offset, int count) + { + if (offset < 0) + return false; + if (count < 0) + return false; + if (offset + count > data.Length) + return false; + + return true; + } + + public static void CheckByteArrayLength(long length) + { + if (length < 0) + { + throw new Exception("Byte array cannot have a negative length."); + } + if (length > 0x7fffffc7) + { + throw new OutOfMemoryException( + "Byte array cannot exceed 2,147,483,591 in length."); + } + } + + /// + /// Writes a message to the debug console, indicating the current position + /// in the stream in both decimal and hexadecimal formats. + /// + [Conditional("DEBUG")] + public static void DebugMessage(Stream stream, string message, + params object[] args) + { + //var formattedMessage = String.Format(message, args); + //Debug.WriteLine("0x{0:x}, {0}, {1}", + //stream.Position, formattedMessage); + } + } + + /// + /// Fixed-point decimal, with 16-bit integer and 16-bit fraction. + /// + internal class UFixed16_16 + { + public UInt16 Integer { get; set; } + public UInt16 Fraction { get; set; } + + public UFixed16_16(UInt16 integer, UInt16 fraction) + { + Integer = integer; + Fraction = fraction; + } + + /// + /// Split the high and low words of a 32-bit unsigned integer into a + /// fixed-point number. + /// + public UFixed16_16(UInt32 value) + { + Integer = (UInt16)(value >> 16); + Fraction = (UInt16)(value & 0x0000ffff); + } + + public UFixed16_16(double value) + { + if (value >= 65536.0) throw new OverflowException(); + if (value < 0) throw new OverflowException(); + + Integer = (UInt16)value; + + // Round instead of truncate, because doubles may not represent the + // fraction exactly. + Fraction = (UInt16)((value - Integer) * 65536 + 0.5); + } + + public static implicit operator double(UFixed16_16 value) + { + return (double)value.Integer + value.Fraction / 65536.0; + } + } +} diff --git a/Editor/PSDPlugin/PsdFile/Util.cs.meta b/Editor/PSDPlugin/PsdFile/Util.cs.meta index de257f9..96ce21e 100644 --- a/Editor/PSDPlugin/PsdFile/Util.cs.meta +++ b/Editor/PSDPlugin/PsdFile/Util.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 2bab0d96ebe77084d97602af7f3fd124 -timeCreated: 1495006553 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 2bab0d96ebe77084d97602af7f3fd124 +timeCreated: 1495006553 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDPlugin/PsdPlugin.asmdef b/Editor/PSDPlugin/PsdPlugin.asmdef index 7ae1f06..f415b4e 100644 --- a/Editor/PSDPlugin/PsdPlugin.asmdef +++ b/Editor/PSDPlugin/PsdPlugin.asmdef @@ -1,9 +1,9 @@ -{ - "name": "PsdPlugin", - "optionalUnityReferences": [], - "includePlatforms": [ - "Editor" - ], - "excludePlatforms": [], - "allowUnsafeCode": true -} +{ + "name": "PsdPlugin", + "optionalUnityReferences": [], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": true +} diff --git a/Editor/PSDPlugin/PsdPlugin.asmdef.meta b/Editor/PSDPlugin/PsdPlugin.asmdef.meta index bbeb791..66a0138 100644 --- a/Editor/PSDPlugin/PsdPlugin.asmdef.meta +++ b/Editor/PSDPlugin/PsdPlugin.asmdef.meta @@ -1,7 +1,7 @@ -fileFormatVersion: 2 -guid: 73a61a380edacb34795f31a3ec21c2ef -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 73a61a380edacb34795f31a3ec21c2ef +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/SpriteData.cs b/Editor/SpriteData.cs index 3ceeb2b..92a7191 100644 --- a/Editor/SpriteData.cs +++ b/Editor/SpriteData.cs @@ -1,94 +1,94 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEditor.U2D.Sprites; -using UnityEngine; -using UnityEngine.U2D; - -namespace UnityEditor.U2D.PSD -{ - [Serializable] - internal class SpriteMetaData : SpriteRect - { - public List spriteBone; - public List spriteOutline; - public List vertices; - public List spritePhysicsOutline; - public int[] indices; - public Vector2Int[] edges; - public float tessellationDetail; - public int parentGroupIndex = -1; - public Vector2Int uvTransform = Vector2Int.zero; - - public SpriteMetaData() {} - - public SpriteMetaData(SpriteRect sr) - { - alignment = sr.alignment; - border = sr.border; - name = sr.name; - pivot = GetPivotValue(sr.alignment, sr.pivot); - rect = sr.rect; - spriteID = sr.spriteID; - } - - public static GUID GetGUIDFromSerializedProperty(SerializedProperty sp) - { - return new GUID(sp.FindPropertyRelative("m_SpriteID").stringValue); - } - - public static Vector2 GetPivotValue(SpriteAlignment alignment, Vector2 customOffset) - { - switch (alignment) - { - case SpriteAlignment.BottomLeft: - return new Vector2(0f, 0f); - case SpriteAlignment.BottomCenter: - return new Vector2(0.5f, 0f); - case SpriteAlignment.BottomRight: - return new Vector2(1f, 0f); - - case SpriteAlignment.LeftCenter: - return new Vector2(0f, 0.5f); - case SpriteAlignment.Center: - return new Vector2(0.5f, 0.5f); - case SpriteAlignment.RightCenter: - return new Vector2(1f, 0.5f); - - case SpriteAlignment.TopLeft: - return new Vector2(0f, 1f); - case SpriteAlignment.TopCenter: - return new Vector2(0.5f, 1f); - case SpriteAlignment.TopRight: - return new Vector2(1f, 1f); - - case SpriteAlignment.Custom: - return customOffset; - } - return Vector2.zero; - } - - public static implicit operator UnityEditor.Experimental.AssetImporters.SpriteImportData(SpriteMetaData value) - { - var output = new UnityEditor.Experimental.AssetImporters.SpriteImportData(); - output.name = value.name; - output.alignment = value.alignment; - output.rect = value.rect; - output.border = value.border; - output.pivot = value.pivot; - output.tessellationDetail = value.tessellationDetail; - output.spriteID = value.spriteID.ToString(); - if (value.spriteOutline != null) - output.outline = value.spriteOutline.Select(x => x.outline).ToList(); - - return output; - } - } - - [Serializable] - internal class SpriteOutline - { - [SerializeField] - public Vector2[] outline; - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor.U2D.Sprites; +using UnityEngine; +using UnityEngine.U2D; + +namespace UnityEditor.U2D.PSD +{ + [Serializable] + internal class SpriteMetaData : SpriteRect + { + public List spriteBone; + public List spriteOutline; + public List vertices; + public List spritePhysicsOutline; + public int[] indices; + public Vector2Int[] edges; + public float tessellationDetail; + public int parentGroupIndex = -1; + public Vector2Int uvTransform = Vector2Int.zero; + + public SpriteMetaData() {} + + public SpriteMetaData(SpriteRect sr) + { + alignment = sr.alignment; + border = sr.border; + name = sr.name; + pivot = GetPivotValue(sr.alignment, sr.pivot); + rect = sr.rect; + spriteID = sr.spriteID; + } + + public static GUID GetGUIDFromSerializedProperty(SerializedProperty sp) + { + return new GUID(sp.FindPropertyRelative("m_SpriteID").stringValue); + } + + public static Vector2 GetPivotValue(SpriteAlignment alignment, Vector2 customOffset) + { + switch (alignment) + { + case SpriteAlignment.BottomLeft: + return new Vector2(0f, 0f); + case SpriteAlignment.BottomCenter: + return new Vector2(0.5f, 0f); + case SpriteAlignment.BottomRight: + return new Vector2(1f, 0f); + + case SpriteAlignment.LeftCenter: + return new Vector2(0f, 0.5f); + case SpriteAlignment.Center: + return new Vector2(0.5f, 0.5f); + case SpriteAlignment.RightCenter: + return new Vector2(1f, 0.5f); + + case SpriteAlignment.TopLeft: + return new Vector2(0f, 1f); + case SpriteAlignment.TopCenter: + return new Vector2(0.5f, 1f); + case SpriteAlignment.TopRight: + return new Vector2(1f, 1f); + + case SpriteAlignment.Custom: + return customOffset; + } + return Vector2.zero; + } + + public static implicit operator UnityEditor.Experimental.AssetImporters.SpriteImportData(SpriteMetaData value) + { + var output = new UnityEditor.Experimental.AssetImporters.SpriteImportData(); + output.name = value.name; + output.alignment = value.alignment; + output.rect = value.rect; + output.border = value.border; + output.pivot = value.pivot; + output.tessellationDetail = value.tessellationDetail; + output.spriteID = value.spriteID.ToString(); + if (value.spriteOutline != null) + output.outline = value.spriteOutline.Select(x => x.outline).ToList(); + + return output; + } + } + + [Serializable] + internal class SpriteOutline + { + [SerializeField] + public Vector2[] outline; + } +} diff --git a/Editor/SpriteData.cs.meta b/Editor/SpriteData.cs.meta index 2ab203e..48bd934 100644 --- a/Editor/SpriteData.cs.meta +++ b/Editor/SpriteData.cs.meta @@ -1,13 +1,13 @@ -fileFormatVersion: 2 -guid: 74fa967f55c32124c86b5f4f945e92f7 -timeCreated: 1502357841 -licenseType: Pro -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 74fa967f55c32124c86b5f4f945e92f7 +timeCreated: 1502357841 +licenseType: Pro +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tasks.meta b/Editor/Tasks.meta index 555c7d9..84d9667 100644 --- a/Editor/Tasks.meta +++ b/Editor/Tasks.meta @@ -1,8 +1,8 @@ -fileFormatVersion: 2 -guid: b1575b7a6ef047c4ab65d2fc455e5e22 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: b1575b7a6ef047c4ab65d2fc455e5e22 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tasks/ExtractLayerTask.cs b/Editor/Tasks/ExtractLayerTask.cs index 24c0c0b..6fb3154 100644 --- a/Editor/Tasks/ExtractLayerTask.cs +++ b/Editor/Tasks/ExtractLayerTask.cs @@ -1,103 +1,103 @@ -using System; -using System.Collections.Generic; -using PDNWrapper; -using UnityEngine; -using Unity.Collections; -using Unity.Collections.LowLevel.Unsafe; -using Unity.Jobs; - -namespace UnityEditor.U2D.PSD -{ - class ExtractLayerTask - { - struct ConvertBufferJob : IJobParallelFor - { - [ReadOnly] - [DeallocateOnJobCompletion] - public NativeArray original; - [ReadOnly] - [DeallocateOnJobCompletion] - public NativeArray width; - [ReadOnly] - [DeallocateOnJobCompletion] - public NativeArray height; - - [DeallocateOnJobCompletion] - public NativeArray output; - public unsafe void Execute(int index) - { - Color32* originalColor = (Color32*)original[index]; - Color32* otuputColor = (Color32*)output[index]; - for (int i = 0; i < height[index]; ++i) - { - int originalYOffset = i * width[index]; - int outputYOffset = (height[index] - i - 1) * width[index]; - for (int j = 0; j < width[index]; ++j) - { - otuputColor[j + outputYOffset] = originalColor[j + originalYOffset]; - } - } - } - } - - public static unsafe void Execute(List extractedLayer, List layers, bool importHiddenLayer) - { - UnityEngine.Profiling.Profiler.BeginSample("ExtractLayer_PrepareJob"); - var tempExtractLayer = new List(); - int layerWithBuffer = ExtractLayer(tempExtractLayer, layers, importHiddenLayer); - if (layerWithBuffer == 0) - return; - var job = new ConvertBufferJob(); - job.original = new NativeArray(layerWithBuffer, Allocator.TempJob); - job.output = new NativeArray(layerWithBuffer, Allocator.TempJob); - job.width = new NativeArray(layerWithBuffer, Allocator.TempJob); - job.height = new NativeArray(layerWithBuffer, Allocator.TempJob); - for (int i = 0, jobIndex = 0; i < tempExtractLayer.Count; ++i) - { - var el = tempExtractLayer[i]; - if (el.texture.Length == 0 || el.width == 0 || el.height == 0) - { - extractedLayer.Add(el); - continue; - } - - job.original[jobIndex] = new IntPtr(el.texture.GetUnsafeReadOnlyPtr()); - el.texture = new NativeArray(el.texture.Length, Allocator.Persistent); - extractedLayer.Add(el); - job.output[jobIndex] = new IntPtr(el.texture.GetUnsafePtr()); - job.width[jobIndex] = el.width; - job.height[jobIndex] = el.height; - ++jobIndex; - } - - var jobsPerThread = layerWithBuffer / (SystemInfo.processorCount == 0 ? 8 : SystemInfo.processorCount); - jobsPerThread = Mathf.Max(jobsPerThread, 1); - var handle = job.Schedule(layerWithBuffer, jobsPerThread); - UnityEngine.Profiling.Profiler.EndSample(); - handle.Complete(); - } - - static int ExtractLayer(List extractedLayer, List layers, bool importHiddenLayer) - { - // parent is the previous element in extracedLayer - int parentGroupIndex = extractedLayer.Count - 1; - int actualLayerWithBuffer = 0; - foreach (var l in layers) - { - if (!importHiddenLayer && !l.Visible) - continue; - if (l.IsGroup) - { - extractedLayer.Add(new PSDLayer(new NativeArray(0, Allocator.Persistent), parentGroupIndex, l.IsGroup, l.Name, 0, 0, l.LayerID)); - actualLayerWithBuffer += ExtractLayer(extractedLayer, l.ChildLayer, importHiddenLayer); - } - else - { - extractedLayer.Add(new PSDLayer(l.Surface.color, parentGroupIndex, l.IsGroup, l.Name, l.Surface.width, l.Surface.height, l.LayerID)); - ++actualLayerWithBuffer; - } - } - return actualLayerWithBuffer; - } - } -} +using System; +using System.Collections.Generic; +using PDNWrapper; +using UnityEngine; +using Unity.Collections; +using Unity.Collections.LowLevel.Unsafe; +using Unity.Jobs; + +namespace UnityEditor.U2D.PSD +{ + class ExtractLayerTask + { + struct ConvertBufferJob : IJobParallelFor + { + [ReadOnly] + [DeallocateOnJobCompletion] + public NativeArray original; + [ReadOnly] + [DeallocateOnJobCompletion] + public NativeArray width; + [ReadOnly] + [DeallocateOnJobCompletion] + public NativeArray height; + + [DeallocateOnJobCompletion] + public NativeArray output; + public unsafe void Execute(int index) + { + Color32* originalColor = (Color32*)original[index]; + Color32* otuputColor = (Color32*)output[index]; + for (int i = 0; i < height[index]; ++i) + { + int originalYOffset = i * width[index]; + int outputYOffset = (height[index] - i - 1) * width[index]; + for (int j = 0; j < width[index]; ++j) + { + otuputColor[j + outputYOffset] = originalColor[j + originalYOffset]; + } + } + } + } + + public static unsafe void Execute(List extractedLayer, List layers, bool importHiddenLayer) + { + UnityEngine.Profiling.Profiler.BeginSample("ExtractLayer_PrepareJob"); + var tempExtractLayer = new List(); + int layerWithBuffer = ExtractLayer(tempExtractLayer, layers, importHiddenLayer); + if (layerWithBuffer == 0) + return; + var job = new ConvertBufferJob(); + job.original = new NativeArray(layerWithBuffer, Allocator.TempJob); + job.output = new NativeArray(layerWithBuffer, Allocator.TempJob); + job.width = new NativeArray(layerWithBuffer, Allocator.TempJob); + job.height = new NativeArray(layerWithBuffer, Allocator.TempJob); + for (int i = 0, jobIndex = 0; i < tempExtractLayer.Count; ++i) + { + var el = tempExtractLayer[i]; + if (el.texture.Length == 0 || el.width == 0 || el.height == 0) + { + extractedLayer.Add(el); + continue; + } + + job.original[jobIndex] = new IntPtr(el.texture.GetUnsafeReadOnlyPtr()); + el.texture = new NativeArray(el.texture.Length, Allocator.Persistent); + extractedLayer.Add(el); + job.output[jobIndex] = new IntPtr(el.texture.GetUnsafePtr()); + job.width[jobIndex] = el.width; + job.height[jobIndex] = el.height; + ++jobIndex; + } + + var jobsPerThread = layerWithBuffer / (SystemInfo.processorCount == 0 ? 8 : SystemInfo.processorCount); + jobsPerThread = Mathf.Max(jobsPerThread, 1); + var handle = job.Schedule(layerWithBuffer, jobsPerThread); + UnityEngine.Profiling.Profiler.EndSample(); + handle.Complete(); + } + + static int ExtractLayer(List extractedLayer, List layers, bool importHiddenLayer) + { + // parent is the previous element in extracedLayer + int parentGroupIndex = extractedLayer.Count - 1; + int actualLayerWithBuffer = 0; + foreach (var l in layers) + { + if (!importHiddenLayer && !l.Visible) + continue; + if (l.IsGroup) + { + extractedLayer.Add(new PSDLayer(new NativeArray(0, Allocator.Persistent), parentGroupIndex, l.IsGroup, l.Name, 0, 0, l.LayerID)); + actualLayerWithBuffer += ExtractLayer(extractedLayer, l.ChildLayer, importHiddenLayer); + } + else + { + extractedLayer.Add(new PSDLayer(l.Surface.color, parentGroupIndex, l.IsGroup, l.Name, l.Surface.width, l.Surface.height, l.LayerID)); + ++actualLayerWithBuffer; + } + } + return actualLayerWithBuffer; + } + } +} diff --git a/Editor/Tasks/ExtractLayerTask.cs.meta b/Editor/Tasks/ExtractLayerTask.cs.meta index 9dbfe19..fbaa404 100644 --- a/Editor/Tasks/ExtractLayerTask.cs.meta +++ b/Editor/Tasks/ExtractLayerTask.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 16af8882f4d64f641925549e4262327c -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 16af8882f4d64f641925549e4262327c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tasks/FlattenImageTask.cs b/Editor/Tasks/FlattenImageTask.cs index aa69bed..434dc05 100644 --- a/Editor/Tasks/FlattenImageTask.cs +++ b/Editor/Tasks/FlattenImageTask.cs @@ -1,125 +1,125 @@ -using System; -using System.Collections.Generic; -using PDNWrapper; -using UnityEngine; -using Unity.Collections; -using Unity.Collections.LowLevel.Unsafe; -using Unity.Jobs; - -namespace UnityEditor.U2D.PSD -{ - static class FlattenImageTask - { - static unsafe public void Execute(List layer, bool importHiddenLayer, int width, int height, NativeArray output) - { - UnityEngine.Profiling.Profiler.BeginSample("FlattenImage"); - List buffers = new List(); - for (int i = layer.Count - 1; i >= 0; --i) - { - GetBuffersToMergeFromLayer(layer[i], importHiddenLayer, buffers); - } - - if (buffers.Count == 0) - return; - - var layersPerJob = buffers.Count / (SystemInfo.processorCount == 0 ? 8 : SystemInfo.processorCount); - layersPerJob = Mathf.Max(layersPerJob, 1); - - var job = new FlattenImageInternalJob(); - var combineJob = new FlattenImageInternalJob(); - - job.buffers = new NativeArray(buffers.ToArray(), Allocator.TempJob); - for (int i = 0; i < buffers.Count; ++i) - job.buffers[i] = buffers[i]; - - combineJob.width = job.width = width; - combineJob.height = job.height = height; - - job.layersPerJob = layersPerJob; - job.flipY = false; - combineJob.flipY = true; - - int jobCount = buffers.Count / layersPerJob + (buffers.Count % layersPerJob > 0 ? 1 : 0); - combineJob.layersPerJob = jobCount; - - NativeArray[] premergedBuffer = new NativeArray[jobCount]; - job.output = new NativeArray(jobCount, Allocator.TempJob); - combineJob.buffers = new NativeArray(jobCount, Allocator.TempJob); - - for (int i = 0; i < jobCount; ++i) - { - premergedBuffer[i] = new NativeArray(width * height * 4, Allocator.TempJob); - job.output[i] = new IntPtr(premergedBuffer[i].GetUnsafePtr()); - combineJob.buffers[i] = new IntPtr(premergedBuffer[i].GetUnsafeReadOnlyPtr()); - } - combineJob.output = new NativeArray(new[] {new IntPtr(output.GetUnsafePtr()), }, Allocator.TempJob); - - var handle = job.Schedule(jobCount, 1); - combineJob.Schedule(1, 1, handle).Complete(); - foreach (var b in premergedBuffer) - { - if (b.IsCreated) - b.Dispose(); - } - UnityEngine.Profiling.Profiler.EndSample(); - } - - static unsafe void GetBuffersToMergeFromLayer(BitmapLayer layer, bool importHiddenLayer, List buffers) - { - if (!layer.Visible && importHiddenLayer == false) - return; - if (layer.IsGroup) - { - for (int i = layer.ChildLayer.Count - 1; i >= 0; --i) - GetBuffersToMergeFromLayer(layer.ChildLayer[i], importHiddenLayer, buffers); - } - if (layer.Surface != null) - buffers.Add(new IntPtr(layer.Surface.color.GetUnsafeReadOnlyPtr())); - else - Debug.LogWarning(string.Format("Layer {0} has no color buffer", layer.Name)); - } - - struct FlattenImageInternalJob : IJobParallelFor - { - [ReadOnly] - [DeallocateOnJobCompletion] - public NativeArray buffers; - [ReadOnly] - public int layersPerJob; - [ReadOnly] - public int width; - [ReadOnly] - public int height; - [ReadOnly] - public bool flipY; - [DeallocateOnJobCompletion] - public NativeArray output; - - public unsafe void Execute(int index) - { - var premerge = (Color32*)output[index].ToPointer(); - for (int layerIndex = index * layersPerJob; layerIndex < (index * layersPerJob) + layersPerJob; ++layerIndex) - { - if (buffers.Length <= layerIndex) - break; - var buffer = (Color32*)buffers[layerIndex].ToPointer(); - for (int i = 0; i < height; ++i) - { - int sourceYIndex = i * width; - int destYIndex = flipY ? (height - 1 - i) * width : sourceYIndex; - for (int j = 0; j < width; ++j) - { - int sourceIndex = sourceYIndex + j; - int destIndex = destYIndex + j; - float alpha = buffer[sourceIndex].a / 255.0f; - premerge[destIndex].r = (byte)(alpha * (float)(buffer[sourceIndex].r) + (float)((1.0f - alpha) * (float)premerge[destIndex].r)); - premerge[destIndex].g = (byte)(alpha * (float)(buffer[sourceIndex].g) + (float)((1.0f - alpha) * (float)premerge[destIndex].g)); - premerge[destIndex].b = (byte)(alpha * (float)(buffer[sourceIndex].b) + (float)((1.0f - alpha) * (float)premerge[destIndex].b)); - premerge[destIndex].a = (byte)(alpha * (float)(buffer[sourceIndex].a) + (float)((1.0f - alpha) * (float)premerge[destIndex].a)); - } - } - } - } - } - } -} +using System; +using System.Collections.Generic; +using PDNWrapper; +using UnityEngine; +using Unity.Collections; +using Unity.Collections.LowLevel.Unsafe; +using Unity.Jobs; + +namespace UnityEditor.U2D.PSD +{ + static class FlattenImageTask + { + static unsafe public void Execute(List layer, bool importHiddenLayer, int width, int height, NativeArray output) + { + UnityEngine.Profiling.Profiler.BeginSample("FlattenImage"); + List buffers = new List(); + for (int i = layer.Count - 1; i >= 0; --i) + { + GetBuffersToMergeFromLayer(layer[i], importHiddenLayer, buffers); + } + + if (buffers.Count == 0) + return; + + var layersPerJob = buffers.Count / (SystemInfo.processorCount == 0 ? 8 : SystemInfo.processorCount); + layersPerJob = Mathf.Max(layersPerJob, 1); + + var job = new FlattenImageInternalJob(); + var combineJob = new FlattenImageInternalJob(); + + job.buffers = new NativeArray(buffers.ToArray(), Allocator.TempJob); + for (int i = 0; i < buffers.Count; ++i) + job.buffers[i] = buffers[i]; + + combineJob.width = job.width = width; + combineJob.height = job.height = height; + + job.layersPerJob = layersPerJob; + job.flipY = false; + combineJob.flipY = true; + + int jobCount = buffers.Count / layersPerJob + (buffers.Count % layersPerJob > 0 ? 1 : 0); + combineJob.layersPerJob = jobCount; + + NativeArray[] premergedBuffer = new NativeArray[jobCount]; + job.output = new NativeArray(jobCount, Allocator.TempJob); + combineJob.buffers = new NativeArray(jobCount, Allocator.TempJob); + + for (int i = 0; i < jobCount; ++i) + { + premergedBuffer[i] = new NativeArray(width * height * 4, Allocator.TempJob); + job.output[i] = new IntPtr(premergedBuffer[i].GetUnsafePtr()); + combineJob.buffers[i] = new IntPtr(premergedBuffer[i].GetUnsafeReadOnlyPtr()); + } + combineJob.output = new NativeArray(new[] {new IntPtr(output.GetUnsafePtr()), }, Allocator.TempJob); + + var handle = job.Schedule(jobCount, 1); + combineJob.Schedule(1, 1, handle).Complete(); + foreach (var b in premergedBuffer) + { + if (b.IsCreated) + b.Dispose(); + } + UnityEngine.Profiling.Profiler.EndSample(); + } + + static unsafe void GetBuffersToMergeFromLayer(BitmapLayer layer, bool importHiddenLayer, List buffers) + { + if (!layer.Visible && importHiddenLayer == false) + return; + if (layer.IsGroup) + { + for (int i = layer.ChildLayer.Count - 1; i >= 0; --i) + GetBuffersToMergeFromLayer(layer.ChildLayer[i], importHiddenLayer, buffers); + } + if (layer.Surface != null) + buffers.Add(new IntPtr(layer.Surface.color.GetUnsafeReadOnlyPtr())); + else + Debug.LogWarning(string.Format("Layer {0} has no color buffer", layer.Name)); + } + + struct FlattenImageInternalJob : IJobParallelFor + { + [ReadOnly] + [DeallocateOnJobCompletion] + public NativeArray buffers; + [ReadOnly] + public int layersPerJob; + [ReadOnly] + public int width; + [ReadOnly] + public int height; + [ReadOnly] + public bool flipY; + [DeallocateOnJobCompletion] + public NativeArray output; + + public unsafe void Execute(int index) + { + var premerge = (Color32*)output[index].ToPointer(); + for (int layerIndex = index * layersPerJob; layerIndex < (index * layersPerJob) + layersPerJob; ++layerIndex) + { + if (buffers.Length <= layerIndex) + break; + var buffer = (Color32*)buffers[layerIndex].ToPointer(); + for (int i = 0; i < height; ++i) + { + int sourceYIndex = i * width; + int destYIndex = flipY ? (height - 1 - i) * width : sourceYIndex; + for (int j = 0; j < width; ++j) + { + int sourceIndex = sourceYIndex + j; + int destIndex = destYIndex + j; + float alpha = buffer[sourceIndex].a / 255.0f; + premerge[destIndex].r = (byte)(alpha * (float)(buffer[sourceIndex].r) + (float)((1.0f - alpha) * (float)premerge[destIndex].r)); + premerge[destIndex].g = (byte)(alpha * (float)(buffer[sourceIndex].g) + (float)((1.0f - alpha) * (float)premerge[destIndex].g)); + premerge[destIndex].b = (byte)(alpha * (float)(buffer[sourceIndex].b) + (float)((1.0f - alpha) * (float)premerge[destIndex].b)); + premerge[destIndex].a = (byte)(alpha * (float)(buffer[sourceIndex].a) + (float)((1.0f - alpha) * (float)premerge[destIndex].a)); + } + } + } + } + } + } +} diff --git a/Editor/Tasks/FlattenImageTask.cs.meta b/Editor/Tasks/FlattenImageTask.cs.meta index 6ff52fd..d9e8428 100644 --- a/Editor/Tasks/FlattenImageTask.cs.meta +++ b/Editor/Tasks/FlattenImageTask.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 91006214ab79ae444b7ae4f0e018beb8 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 91006214ab79ae444b7ae4f0e018beb8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/TexturePlatformSettingsController.cs b/Editor/TexturePlatformSettingsController.cs index 9fd01e5..4fbdee8 100644 --- a/Editor/TexturePlatformSettingsController.cs +++ b/Editor/TexturePlatformSettingsController.cs @@ -1,254 +1,254 @@ -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.Assertions; - -namespace UnityEditor.U2D.PSD -{ - internal class TexturePlatformSettingsController - { - public bool HandleDefaultSettings(List platformSettings, TexturePlatformSettingsView view) - { - Assert.IsTrue(platformSettings.Count > 0, "At least 1 platform setting is needed to display the texture platform setting UI."); - - int allSize = platformSettings[0].maxTextureSize; - TextureImporterCompression allCompression = platformSettings[0].textureCompression; - bool allUseCrunchedCompression = platformSettings[0].crunchedCompression; - int allCompressionQuality = platformSettings[0].compressionQuality; - TextureResizeAlgorithm allResizeAlgorithm = platformSettings[0].resizeAlgorithm; - - var newSize = allSize; - var newCompression = allCompression; - var newUseCrunchedCompression = allUseCrunchedCompression; - var newCompressionQuality = allCompressionQuality; - var newResizeAlgorithm = allResizeAlgorithm; - - bool mixedSize = false; - bool mixedCompression = false; - bool mixedUseCrunchedCompression = false; - bool mixedCompressionQuality = false; - bool mixedResizeAlgorithm = false; - - bool sizeChanged = false; - bool compressionChanged = false; - bool useCrunchedCompressionChanged = false; - bool compressionQualityChanged = false; - bool resizedChanged = false; - - for (var i = 1; i < platformSettings.Count; ++i) - { - var settings = platformSettings[i]; - if (settings.maxTextureSize != allSize) - mixedSize = true; - if (settings.textureCompression != allCompression) - mixedCompression = true; - if (settings.crunchedCompression != allUseCrunchedCompression) - mixedUseCrunchedCompression = true; - if (settings.compressionQuality != allCompressionQuality) - mixedCompressionQuality = true; - if (settings.resizeAlgorithm != allResizeAlgorithm) - mixedResizeAlgorithm = true; - } - - EditorGUI.indentLevel++; - newSize = view.DrawMaxSize(allSize, mixedSize, false, out sizeChanged); - newResizeAlgorithm = view.DrawResizeAlgorithm(allResizeAlgorithm, mixedResizeAlgorithm, false, out resizedChanged); - newCompression = view.DrawCompression(allCompression, mixedCompression, out compressionChanged); - if (!mixedCompression && allCompression != TextureImporterCompression.Uncompressed) - { - newUseCrunchedCompression = view.DrawUseCrunchedCompression(allUseCrunchedCompression, mixedUseCrunchedCompression, out useCrunchedCompressionChanged); - - if (!mixedUseCrunchedCompression && allUseCrunchedCompression) - { - newCompressionQuality = view.DrawCompressionQualitySlider(allCompressionQuality, mixedCompressionQuality, out compressionQualityChanged); - } - } - EditorGUI.indentLevel--; - - if (sizeChanged || compressionChanged || useCrunchedCompressionChanged || compressionQualityChanged || resizedChanged) - { - for (var i = 0; i < platformSettings.Count; ++i) - { - if (sizeChanged) - platformSettings[i].maxTextureSize = newSize; - if (compressionChanged) - platformSettings[i].textureCompression = newCompression; - if (useCrunchedCompressionChanged) - platformSettings[i].crunchedCompression = newUseCrunchedCompression; - if (compressionQualityChanged) - platformSettings[i].compressionQuality = newCompressionQuality; - if (resizedChanged) - platformSettings[i].resizeAlgorithm = newResizeAlgorithm; - } - return true; - } - else - return false; - } - - public bool HandlePlatformSettings(BuildTarget buildTarget, List platformSettings, TexturePlatformSettingsView view) - { - if (buildTarget == BuildTarget.NoTarget) - { - return HandleDefaultSettings(platformSettings, view); - } - Assert.IsTrue(platformSettings.Count > 0, "At least 1 platform setting is needed to display the texture platform setting UI."); - - bool allOverride = platformSettings[0].overridden; - int allSize = platformSettings[0].maxTextureSize; - TextureImporterFormat allFormat = platformSettings[0].format; - int allCompressionQuality = platformSettings[0].compressionQuality; - TextureResizeAlgorithm allResizeAlgorithm = platformSettings[0].resizeAlgorithm; - var newResizeAlgorithm = allResizeAlgorithm; - - var newOverride = allOverride; - var newSize = allSize; - var newFormat = allFormat; - var newCompressionQuality = allCompressionQuality; - - bool mixedOverride = false; - bool mixedSize = false; - bool mixedFormat = false; - bool mixedCompression = false; - bool mixedResizeAlgorithm = false; - - bool overrideChanged = false; - bool sizeChanged = false; - bool formatChanged = false; - bool compressionChanged = false; - bool resizedChanged = false; - - for (var i = 1; i < platformSettings.Count; ++i) - { - var settings = platformSettings[i]; - if (settings.overridden != allOverride) - mixedOverride = true; - if (settings.maxTextureSize != allSize) - mixedSize = true; - if (settings.format != allFormat) - mixedFormat = true; - if (settings.compressionQuality != allCompressionQuality) - mixedCompression = true; - if (settings.resizeAlgorithm != allResizeAlgorithm) - mixedResizeAlgorithm = true; - } - - EditorGUI.indentLevel++; - newOverride = view.DrawOverride(allOverride, mixedOverride, out overrideChanged); - newResizeAlgorithm = view.DrawResizeAlgorithm(allResizeAlgorithm, mixedResizeAlgorithm, mixedOverride || !allOverride, out resizedChanged); - newSize = view.DrawMaxSize(allSize, mixedSize, mixedOverride || !allOverride, out sizeChanged); - - int[] formatValues = null; - string[] formatStrings = null; - AcquireTextureFormatValuesAndStrings(buildTarget, out formatValues, out formatStrings); - - newFormat = view.DrawFormat(allFormat, formatValues, formatStrings, mixedFormat, mixedOverride || !allOverride, out formatChanged); - - - if (!mixedFormat && !mixedOverride && allOverride && IsFormatRequireCompressionSetting(allFormat)) - { - bool showAsEnum = - buildTarget == BuildTarget.iOS || - buildTarget == BuildTarget.tvOS || - buildTarget == BuildTarget.Android - ; - - if (showAsEnum) - { - int compressionMode = 1; - if (allCompressionQuality == (int)TextureCompressionQuality.Fast) - compressionMode = 0; - else if (allCompressionQuality == (int)TextureCompressionQuality.Best) - compressionMode = 2; - - var returnValue = view.DrawCompressionQualityPopup(compressionMode, mixedCompression, out compressionChanged); - - if (compressionChanged) - { - switch (returnValue) - { - case 0: - newCompressionQuality = (int)TextureCompressionQuality.Fast; - break; - case 1: - newCompressionQuality = (int)TextureCompressionQuality.Normal; - break; - case 2: - newCompressionQuality = (int)TextureCompressionQuality.Best; - break; - - default: - Assert.IsTrue(false, "ITexturePlatformSettingsView.DrawCompressionQualityPopup should never return compression option value that's not 0, 1 or 2."); - break; - } - } - } - else - { - newCompressionQuality = view.DrawCompressionQualitySlider(allCompressionQuality, mixedCompression, out compressionChanged); - } - } - EditorGUI.indentLevel--; - - if (overrideChanged || sizeChanged || formatChanged || compressionChanged || resizedChanged) - { - for (var i = 0; i < platformSettings.Count; ++i) - { - if (overrideChanged) - platformSettings[i].overridden = newOverride; - if (sizeChanged) - platformSettings[i].maxTextureSize = newSize; - if (formatChanged) - platformSettings[i].format = newFormat; - if (compressionChanged) - platformSettings[i].compressionQuality = newCompressionQuality; - if (resizedChanged) - platformSettings[i].resizeAlgorithm = newResizeAlgorithm; - } - - return true; - } - else - return false; - } - - public void AcquireTextureFormatValuesAndStrings(BuildTarget buildTarget, out int[] formatValues, out string[] formatStrings) - { - if (IsGLESMobileTargetPlatform(buildTarget)) - { - if (buildTarget == BuildTarget.iOS || buildTarget == BuildTarget.tvOS) - { - formatValues = TexturePlatformSettingsModal.kTextureFormatsValueApplePVR; - formatStrings = TexturePlatformSettingsModal.s_TextureFormatStringsApplePVR; - } - else - { - formatValues = TexturePlatformSettingsModal.kTextureFormatsValueAndroid; - formatStrings = TexturePlatformSettingsModal.s_TextureFormatStringsAndroid; - } - } - else - { - if (buildTarget == BuildTarget.WebGL) - { - formatValues = TexturePlatformSettingsModal.kTextureFormatsValueWebGL; - formatStrings = TexturePlatformSettingsModal.s_TextureFormatStringsWebGL; - } - else - { - formatValues = TexturePlatformSettingsModal.kTextureFormatsValueDefault; - formatStrings = TexturePlatformSettingsModal.s_TextureFormatStringsDefault; - } - } - } - - internal static bool IsFormatRequireCompressionSetting(TextureImporterFormat format) - { - return ArrayUtility.Contains(TexturePlatformSettingsModal.kFormatsWithCompressionSettings, format); - } - - internal static bool IsGLESMobileTargetPlatform(BuildTarget target) - { - return target == BuildTarget.iOS || target == BuildTarget.tvOS || target == BuildTarget.Android; - } - } -} +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Assertions; + +namespace UnityEditor.U2D.PSD +{ + internal class TexturePlatformSettingsController + { + public bool HandleDefaultSettings(List platformSettings, TexturePlatformSettingsView view) + { + Assert.IsTrue(platformSettings.Count > 0, "At least 1 platform setting is needed to display the texture platform setting UI."); + + int allSize = platformSettings[0].maxTextureSize; + TextureImporterCompression allCompression = platformSettings[0].textureCompression; + bool allUseCrunchedCompression = platformSettings[0].crunchedCompression; + int allCompressionQuality = platformSettings[0].compressionQuality; + TextureResizeAlgorithm allResizeAlgorithm = platformSettings[0].resizeAlgorithm; + + var newSize = allSize; + var newCompression = allCompression; + var newUseCrunchedCompression = allUseCrunchedCompression; + var newCompressionQuality = allCompressionQuality; + var newResizeAlgorithm = allResizeAlgorithm; + + bool mixedSize = false; + bool mixedCompression = false; + bool mixedUseCrunchedCompression = false; + bool mixedCompressionQuality = false; + bool mixedResizeAlgorithm = false; + + bool sizeChanged = false; + bool compressionChanged = false; + bool useCrunchedCompressionChanged = false; + bool compressionQualityChanged = false; + bool resizedChanged = false; + + for (var i = 1; i < platformSettings.Count; ++i) + { + var settings = platformSettings[i]; + if (settings.maxTextureSize != allSize) + mixedSize = true; + if (settings.textureCompression != allCompression) + mixedCompression = true; + if (settings.crunchedCompression != allUseCrunchedCompression) + mixedUseCrunchedCompression = true; + if (settings.compressionQuality != allCompressionQuality) + mixedCompressionQuality = true; + if (settings.resizeAlgorithm != allResizeAlgorithm) + mixedResizeAlgorithm = true; + } + + EditorGUI.indentLevel++; + newSize = view.DrawMaxSize(allSize, mixedSize, false, out sizeChanged); + newResizeAlgorithm = view.DrawResizeAlgorithm(allResizeAlgorithm, mixedResizeAlgorithm, false, out resizedChanged); + newCompression = view.DrawCompression(allCompression, mixedCompression, out compressionChanged); + if (!mixedCompression && allCompression != TextureImporterCompression.Uncompressed) + { + newUseCrunchedCompression = view.DrawUseCrunchedCompression(allUseCrunchedCompression, mixedUseCrunchedCompression, out useCrunchedCompressionChanged); + + if (!mixedUseCrunchedCompression && allUseCrunchedCompression) + { + newCompressionQuality = view.DrawCompressionQualitySlider(allCompressionQuality, mixedCompressionQuality, out compressionQualityChanged); + } + } + EditorGUI.indentLevel--; + + if (sizeChanged || compressionChanged || useCrunchedCompressionChanged || compressionQualityChanged || resizedChanged) + { + for (var i = 0; i < platformSettings.Count; ++i) + { + if (sizeChanged) + platformSettings[i].maxTextureSize = newSize; + if (compressionChanged) + platformSettings[i].textureCompression = newCompression; + if (useCrunchedCompressionChanged) + platformSettings[i].crunchedCompression = newUseCrunchedCompression; + if (compressionQualityChanged) + platformSettings[i].compressionQuality = newCompressionQuality; + if (resizedChanged) + platformSettings[i].resizeAlgorithm = newResizeAlgorithm; + } + return true; + } + else + return false; + } + + public bool HandlePlatformSettings(BuildTarget buildTarget, List platformSettings, TexturePlatformSettingsView view) + { + if (buildTarget == BuildTarget.NoTarget) + { + return HandleDefaultSettings(platformSettings, view); + } + Assert.IsTrue(platformSettings.Count > 0, "At least 1 platform setting is needed to display the texture platform setting UI."); + + bool allOverride = platformSettings[0].overridden; + int allSize = platformSettings[0].maxTextureSize; + TextureImporterFormat allFormat = platformSettings[0].format; + int allCompressionQuality = platformSettings[0].compressionQuality; + TextureResizeAlgorithm allResizeAlgorithm = platformSettings[0].resizeAlgorithm; + var newResizeAlgorithm = allResizeAlgorithm; + + var newOverride = allOverride; + var newSize = allSize; + var newFormat = allFormat; + var newCompressionQuality = allCompressionQuality; + + bool mixedOverride = false; + bool mixedSize = false; + bool mixedFormat = false; + bool mixedCompression = false; + bool mixedResizeAlgorithm = false; + + bool overrideChanged = false; + bool sizeChanged = false; + bool formatChanged = false; + bool compressionChanged = false; + bool resizedChanged = false; + + for (var i = 1; i < platformSettings.Count; ++i) + { + var settings = platformSettings[i]; + if (settings.overridden != allOverride) + mixedOverride = true; + if (settings.maxTextureSize != allSize) + mixedSize = true; + if (settings.format != allFormat) + mixedFormat = true; + if (settings.compressionQuality != allCompressionQuality) + mixedCompression = true; + if (settings.resizeAlgorithm != allResizeAlgorithm) + mixedResizeAlgorithm = true; + } + + EditorGUI.indentLevel++; + newOverride = view.DrawOverride(allOverride, mixedOverride, out overrideChanged); + newResizeAlgorithm = view.DrawResizeAlgorithm(allResizeAlgorithm, mixedResizeAlgorithm, mixedOverride || !allOverride, out resizedChanged); + newSize = view.DrawMaxSize(allSize, mixedSize, mixedOverride || !allOverride, out sizeChanged); + + int[] formatValues = null; + string[] formatStrings = null; + AcquireTextureFormatValuesAndStrings(buildTarget, out formatValues, out formatStrings); + + newFormat = view.DrawFormat(allFormat, formatValues, formatStrings, mixedFormat, mixedOverride || !allOverride, out formatChanged); + + + if (!mixedFormat && !mixedOverride && allOverride && IsFormatRequireCompressionSetting(allFormat)) + { + bool showAsEnum = + buildTarget == BuildTarget.iOS || + buildTarget == BuildTarget.tvOS || + buildTarget == BuildTarget.Android + ; + + if (showAsEnum) + { + int compressionMode = 1; + if (allCompressionQuality == (int)TextureCompressionQuality.Fast) + compressionMode = 0; + else if (allCompressionQuality == (int)TextureCompressionQuality.Best) + compressionMode = 2; + + var returnValue = view.DrawCompressionQualityPopup(compressionMode, mixedCompression, out compressionChanged); + + if (compressionChanged) + { + switch (returnValue) + { + case 0: + newCompressionQuality = (int)TextureCompressionQuality.Fast; + break; + case 1: + newCompressionQuality = (int)TextureCompressionQuality.Normal; + break; + case 2: + newCompressionQuality = (int)TextureCompressionQuality.Best; + break; + + default: + Assert.IsTrue(false, "ITexturePlatformSettingsView.DrawCompressionQualityPopup should never return compression option value that's not 0, 1 or 2."); + break; + } + } + } + else + { + newCompressionQuality = view.DrawCompressionQualitySlider(allCompressionQuality, mixedCompression, out compressionChanged); + } + } + EditorGUI.indentLevel--; + + if (overrideChanged || sizeChanged || formatChanged || compressionChanged || resizedChanged) + { + for (var i = 0; i < platformSettings.Count; ++i) + { + if (overrideChanged) + platformSettings[i].overridden = newOverride; + if (sizeChanged) + platformSettings[i].maxTextureSize = newSize; + if (formatChanged) + platformSettings[i].format = newFormat; + if (compressionChanged) + platformSettings[i].compressionQuality = newCompressionQuality; + if (resizedChanged) + platformSettings[i].resizeAlgorithm = newResizeAlgorithm; + } + + return true; + } + else + return false; + } + + public void AcquireTextureFormatValuesAndStrings(BuildTarget buildTarget, out int[] formatValues, out string[] formatStrings) + { + if (IsGLESMobileTargetPlatform(buildTarget)) + { + if (buildTarget == BuildTarget.iOS || buildTarget == BuildTarget.tvOS) + { + formatValues = TexturePlatformSettingsModal.kTextureFormatsValueApplePVR; + formatStrings = TexturePlatformSettingsModal.s_TextureFormatStringsApplePVR; + } + else + { + formatValues = TexturePlatformSettingsModal.kTextureFormatsValueAndroid; + formatStrings = TexturePlatformSettingsModal.s_TextureFormatStringsAndroid; + } + } + else + { + if (buildTarget == BuildTarget.WebGL) + { + formatValues = TexturePlatformSettingsModal.kTextureFormatsValueWebGL; + formatStrings = TexturePlatformSettingsModal.s_TextureFormatStringsWebGL; + } + else + { + formatValues = TexturePlatformSettingsModal.kTextureFormatsValueDefault; + formatStrings = TexturePlatformSettingsModal.s_TextureFormatStringsDefault; + } + } + } + + internal static bool IsFormatRequireCompressionSetting(TextureImporterFormat format) + { + return ArrayUtility.Contains(TexturePlatformSettingsModal.kFormatsWithCompressionSettings, format); + } + + internal static bool IsGLESMobileTargetPlatform(BuildTarget target) + { + return target == BuildTarget.iOS || target == BuildTarget.tvOS || target == BuildTarget.Android; + } + } +} diff --git a/Editor/TexturePlatformSettingsController.cs.meta b/Editor/TexturePlatformSettingsController.cs.meta index 0dc44b0..e5a594e 100644 --- a/Editor/TexturePlatformSettingsController.cs.meta +++ b/Editor/TexturePlatformSettingsController.cs.meta @@ -1,13 +1,13 @@ -fileFormatVersion: 2 -guid: bec0ba5e646aab9419f2d0e88304dbd0 -timeCreated: 1502357294 -licenseType: Pro -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: bec0ba5e646aab9419f2d0e88304dbd0 +timeCreated: 1502357294 +licenseType: Pro +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/TexturePlatformSettingsModal.cs b/Editor/TexturePlatformSettingsModal.cs index 563bf61..bdb8573 100644 --- a/Editor/TexturePlatformSettingsModal.cs +++ b/Editor/TexturePlatformSettingsModal.cs @@ -1,380 +1,380 @@ -namespace UnityEditor.U2D.PSD -{ - internal static class TexturePlatformSettingsModal - { - public static readonly TextureImporterFormat[] kFormatsWithCompressionSettings = - { - TextureImporterFormat.PVRTC_RGB2, - TextureImporterFormat.PVRTC_RGB4, - TextureImporterFormat.PVRTC_RGBA2, - TextureImporterFormat.PVRTC_RGBA4, - TextureImporterFormat.ETC_RGB4, - TextureImporterFormat.ETC2_RGBA8, - TextureImporterFormat.ETC_RGB4, - TextureImporterFormat.ETC2_RGB4, - TextureImporterFormat.ETC2_RGB4_PUNCHTHROUGH_ALPHA, - TextureImporterFormat.ETC2_RGBA8, -#if UNITY_2019_1_OR_NEWER - TextureImporterFormat.ASTC_4x4, - TextureImporterFormat.ASTC_5x5, - TextureImporterFormat.ASTC_6x6, - TextureImporterFormat.ASTC_8x8, - TextureImporterFormat.ASTC_10x10, - TextureImporterFormat.ASTC_12x12, -#else - TextureImporterFormat.ASTC_RGB_4x4, - TextureImporterFormat.ASTC_RGB_5x5, - TextureImporterFormat.ASTC_RGB_6x6, - TextureImporterFormat.ASTC_RGB_8x8, - TextureImporterFormat.ASTC_RGB_10x10, - TextureImporterFormat.ASTC_RGB_12x12, - TextureImporterFormat.ASTC_RGBA_4x4, - TextureImporterFormat.ASTC_RGBA_5x5, - TextureImporterFormat.ASTC_RGBA_6x6, - TextureImporterFormat.ASTC_RGBA_8x8, - TextureImporterFormat.ASTC_RGBA_10x10, - TextureImporterFormat.ASTC_RGBA_12x12 - #endif - }; - - public struct BuildPlatformData - { - public string buildTargetName; - public TextureImporterFormat defaultTextureFormat; - public BuildTarget[] buildTarget; - } - - // Add new platforms here - public static readonly BuildPlatformData[] kValidBuildPlatform = new BuildPlatformData[] - { - new BuildPlatformData() - { - buildTargetName = "Default", - defaultTextureFormat = TextureImporterFormat.Automatic, - buildTarget = new[] - { - BuildTarget.NoTarget - } - }, - - new BuildPlatformData() - { - buildTargetName = "PC, Mac & Linux Standalone", - defaultTextureFormat = TextureImporterFormat.RGBA32, - buildTarget = new[] - { - BuildTarget.StandaloneWindows, - BuildTarget.StandaloneWindows64, - BuildTarget.StandaloneLinux64, - BuildTarget.StandaloneOSX, - } - }, - new BuildPlatformData() - { - buildTargetName = "iOS", - defaultTextureFormat = TextureImporterFormat.RGBA32, - buildTarget = new[] { BuildTarget.iOS } - }, - new BuildPlatformData() - { - buildTargetName = "tvOS", - defaultTextureFormat = TextureImporterFormat.RGBA32, - buildTarget = new[] { BuildTarget.tvOS } - }, - new BuildPlatformData() - { - buildTargetName = "Android", - defaultTextureFormat = TextureImporterFormat.RGBA32, - buildTarget = new[] { BuildTarget.Android } - }, - new BuildPlatformData() - { - buildTargetName = "Universal Windows Platform", - defaultTextureFormat = TextureImporterFormat.RGBA32, - buildTarget = new[] { BuildTarget.WSAPlayer } - }, - }; - - public static readonly int[] kTextureFormatsValueApplePVR = - { - (int)TextureImporterFormat.PVRTC_RGB2, - (int)TextureImporterFormat.PVRTC_RGBA2, - (int)TextureImporterFormat.PVRTC_RGB4, - (int)TextureImporterFormat.PVRTC_RGBA4, - -#if UNITY_2019_1_OR_NEWER - (int)TextureImporterFormat.ASTC_4x4, - (int)TextureImporterFormat.ASTC_5x5, - (int)TextureImporterFormat.ASTC_6x6, - (int)TextureImporterFormat.ASTC_8x8, - (int)TextureImporterFormat.ASTC_10x10, - (int)TextureImporterFormat.ASTC_12x12, -#else - (int)TextureImporterFormat.ASTC_RGB_4x4, - (int)TextureImporterFormat.ASTC_RGB_5x5, - (int)TextureImporterFormat.ASTC_RGB_6x6, - (int)TextureImporterFormat.ASTC_RGB_8x8, - (int)TextureImporterFormat.ASTC_RGB_10x10, - (int)TextureImporterFormat.ASTC_RGB_12x12, - (int)TextureImporterFormat.ASTC_RGBA_4x4, - (int)TextureImporterFormat.ASTC_RGBA_5x5, - (int)TextureImporterFormat.ASTC_RGBA_6x6, - (int)TextureImporterFormat.ASTC_RGBA_8x8, - (int)TextureImporterFormat.ASTC_RGBA_10x10, - (int)TextureImporterFormat.ASTC_RGBA_12x12, -#endif - - (int)TextureImporterFormat.RGB16, - (int)TextureImporterFormat.RGB24, - (int)TextureImporterFormat.Alpha8, - (int)TextureImporterFormat.RGBA16, - (int)TextureImporterFormat.RGBA32 - }; - - public static readonly int[] kTextureFormatsValueAndroid = - { - (int)TextureImporterFormat.DXT1, - (int)TextureImporterFormat.DXT5, -#if ENABLE_CRUNCH_TEXTURE_COMPRESSION - (int)TextureImporterFormat.DXT1Crunched, - (int)TextureImporterFormat.DXT5Crunched, -#endif - - (int)TextureImporterFormat.ETC_RGB4, - - (int)TextureImporterFormat.ETC2_RGB4, - (int)TextureImporterFormat.ETC2_RGB4_PUNCHTHROUGH_ALPHA, - (int)TextureImporterFormat.ETC2_RGBA8, - - - (int)TextureImporterFormat.PVRTC_RGB2, - (int)TextureImporterFormat.PVRTC_RGBA2, - (int)TextureImporterFormat.PVRTC_RGB4, - (int)TextureImporterFormat.PVRTC_RGBA4, - - (int)TextureImporterFormat.ETC_RGB4, - (int)TextureImporterFormat.ETC2_RGBA8, - -#if UNITY_2019_1_OR_NEWER - (int)TextureImporterFormat.ASTC_4x4, - (int)TextureImporterFormat.ASTC_5x5, - (int)TextureImporterFormat.ASTC_6x6, - (int)TextureImporterFormat.ASTC_8x8, - (int)TextureImporterFormat.ASTC_10x10, - (int)TextureImporterFormat.ASTC_12x12, -#else - (int)TextureImporterFormat.ASTC_RGB_4x4, - (int)TextureImporterFormat.ASTC_RGB_5x5, - (int)TextureImporterFormat.ASTC_RGB_6x6, - (int)TextureImporterFormat.ASTC_RGB_8x8, - (int)TextureImporterFormat.ASTC_RGB_10x10, - (int)TextureImporterFormat.ASTC_RGB_12x12, - (int)TextureImporterFormat.ASTC_RGBA_4x4, - (int)TextureImporterFormat.ASTC_RGBA_5x5, - (int)TextureImporterFormat.ASTC_RGBA_6x6, - (int)TextureImporterFormat.ASTC_RGBA_8x8, - (int)TextureImporterFormat.ASTC_RGBA_10x10, - (int)TextureImporterFormat.ASTC_RGBA_12x12, -#endif - - (int)TextureImporterFormat.RGB16, - (int)TextureImporterFormat.RGB24, - (int)TextureImporterFormat.Alpha8, - (int)TextureImporterFormat.RGBA16, - (int)TextureImporterFormat.RGBA32 - }; - - public static readonly int[] kTextureFormatsValueSTV = - { - (int)TextureImporterFormat.ETC_RGB4, - - (int)TextureImporterFormat.RGB16, - (int)TextureImporterFormat.RGB24, - (int)TextureImporterFormat.Alpha8, - (int)TextureImporterFormat.RGBA16, - (int)TextureImporterFormat.RGBA32, - }; - - public static readonly int[] kTextureFormatsValueWebGL = - { - (int)TextureImporterFormat.DXT1, - (int)TextureImporterFormat.DXT5, -#if ENABLE_CRUNCH_TEXTURE_COMPRESSION - (int)TextureImporterFormat.DXT1Crunched, - (int)TextureImporterFormat.DXT5Crunched, -#endif - (int)TextureImporterFormat.RGB16, - (int)TextureImporterFormat.RGB24, - (int)TextureImporterFormat.Alpha8, - (int)TextureImporterFormat.ARGB16, - (int)TextureImporterFormat.RGBA32 - }; - - public static readonly int[] kNormalFormatsValueDefault = - { - (int)TextureImporterFormat.BC5, - (int)TextureImporterFormat.BC7, - (int)TextureImporterFormat.DXT5, -#if ENABLE_CRUNCH_TEXTURE_COMPRESSION - (int)TextureImporterFormat.DXT5Crunched, -#endif - (int)TextureImporterFormat.ARGB16, - (int)TextureImporterFormat.RGBA32, - }; - public static readonly int[] kTextureFormatsValueDefault = - { - (int)TextureImporterFormat.DXT1, - (int)TextureImporterFormat.DXT5, -#if ENABLE_CRUNCH_TEXTURE_COMPRESSION - (int)TextureImporterFormat.DXT1Crunched, - (int)TextureImporterFormat.DXT5Crunched, -#endif - (int)TextureImporterFormat.RGB16, - (int)TextureImporterFormat.RGB24, - (int)TextureImporterFormat.Alpha8, - (int)TextureImporterFormat.ARGB16, - (int)TextureImporterFormat.RGBA32, - (int)TextureImporterFormat.RGBAHalf, - (int)TextureImporterFormat.BC4, - (int)TextureImporterFormat.BC5, - (int)TextureImporterFormat.BC6H, - (int)TextureImporterFormat.BC7, - }; - public static readonly int[] kTextureFormatsValueSingleChannel = - { - (int)TextureImporterFormat.Alpha8, - (int)TextureImporterFormat.BC4, - }; - - internal static string[] s_TextureFormatStringsWebGL; - internal static string[] s_TextureFormatStringsApplePVR; - internal static string[] s_TextureFormatStringsAndroid; - internal static string[] s_TextureFormatStringsSTV; - internal static string[] s_TextureFormatStringsSingleChannel; - internal static string[] s_TextureFormatStringsDefault; - - static TexturePlatformSettingsModal() - { - s_TextureFormatStringsApplePVR = BuildTextureStrings(kTextureFormatsValueApplePVR); - s_TextureFormatStringsAndroid = BuildTextureStrings(kTextureFormatsValueAndroid); - s_TextureFormatStringsSTV = BuildTextureStrings(kTextureFormatsValueSTV); - s_TextureFormatStringsWebGL = BuildTextureStrings(kTextureFormatsValueWebGL); - s_TextureFormatStringsDefault = BuildTextureStrings(kTextureFormatsValueDefault); - s_TextureFormatStringsSingleChannel = BuildTextureStrings(kTextureFormatsValueSingleChannel); - } - - internal static string[] BuildTextureStrings(int[] texFormatValues) - { - string[] retval = new string[texFormatValues.Length]; - for (int i = 0; i < texFormatValues.Length; i++) - { - int val = texFormatValues[i]; - retval[i] = GetTextureFormatString((TextureImporterFormat)val); - } - return retval; - } - - static string GetTextureFormatString(TextureImporterFormat format) - { - switch (format) - { - case TextureImporterFormat.DXT1: - return "RGB Crunched DTX1"; - case TextureImporterFormat.DXT5: - return "RGB Crunched DTX5"; - case TextureImporterFormat.RGB16: - return "RGB 16 bit"; - case TextureImporterFormat.RGB24: - return "RGB 24 bit"; - case TextureImporterFormat.Alpha8: - return "Alpha 8"; - case TextureImporterFormat.ARGB16: - return "ARGB 16 bit"; - case TextureImporterFormat.RGBA32: - return "RGBA 32 bit"; - case TextureImporterFormat.ARGB32: - return "ARGB 32 bit"; - case TextureImporterFormat.RGBA16: - return "RGBA 16 bit"; - case TextureImporterFormat.RGBAHalf: - return "RGBA Half"; - - case TextureImporterFormat.BC4: - return "R Compressed BC4"; - case TextureImporterFormat.BC5: - return "RG Compressed BC5"; - case TextureImporterFormat.BC6H: - return "RGB HDR Compressed BC6H"; - case TextureImporterFormat.BC7: - return "RGB(A) Compressed BC7"; - case TextureImporterFormat.PVRTC_RGB2: - return "RGB Compressed PVRTC 2 bits"; - case TextureImporterFormat.PVRTC_RGBA2: - return "RGBA Compressed PVRTC 2 bits"; - case TextureImporterFormat.PVRTC_RGB4: - return "RGB Compressed PVRTC 4 bits"; - case TextureImporterFormat.PVRTC_RGBA4: - return "RGBA Compressed PVRTC 4 bits"; - case TextureImporterFormat.ETC_RGB4: - return "RGB Compressed ETC 4 bits"; - - case TextureImporterFormat.EAC_R: - return "11-bit R Compressed EAC 4 bit"; - case TextureImporterFormat.EAC_R_SIGNED: - return "11-bit signed R Compressed EAC 4 bit"; - case TextureImporterFormat.EAC_RG: - return "11-bit RG Compressed EAC 8 bit"; - case TextureImporterFormat.EAC_RG_SIGNED: - return "11-bit signed RG Compressed EAC 8 bit"; - - case TextureImporterFormat.ETC2_RGB4: - return "RGB Compressed ETC2 4 bits"; - case TextureImporterFormat.ETC2_RGB4_PUNCHTHROUGH_ALPHA: - return "RGB + 1-bit Alpha Compressed ETC2 4 bits"; - case TextureImporterFormat.ETC2_RGBA8: - return "RGBA Compressed ETC2 8 bits"; - -#if UNITY_2019_1_OR_NEWER - case TextureImporterFormat.ASTC_4x4: - return "RGB(A) Compressed ASTC 4 x 4 block"; - case TextureImporterFormat.ASTC_5x5: - return "RGB(A) Compressed ASTC 5 x 5 block"; - case TextureImporterFormat.ASTC_6x6: - return "RGB(A) Compressed ASTC 6 x 6 block"; - case TextureImporterFormat.ASTC_8x8: - return "RGB(A) Compressed ASTC 8 x 8 block"; - case TextureImporterFormat.ASTC_10x10: - return "RGB(A) Compressed ASTC 10 x 10 block"; - case TextureImporterFormat.ASTC_12x12: - return "RGB(A) Compressed ASTC 12 x 12 block"; -#else - case TextureImporterFormat.ASTC_RGB_4x4: - return "RGB Compressed ASTC 4 x 4 block"; - case TextureImporterFormat.ASTC_RGB_5x5: - return "RGB Compressed ASTC 5 x 5 block"; - case TextureImporterFormat.ASTC_RGB_6x6: - return "RGB Compressed ASTC 6 x 6 block"; - case TextureImporterFormat.ASTC_RGB_8x8: - return "RGB Compressed ASTC 8 x 8 block"; - case TextureImporterFormat.ASTC_RGB_10x10: - return "RGB Compressed ASTC 10 x 10 block"; - case TextureImporterFormat.ASTC_RGB_12x12: - return "RGB Compressed ASTC 12 x 12 block"; - case TextureImporterFormat.ASTC_RGBA_4x4: - return "RGBA Compressed ASTC 4 x 4 block"; - case TextureImporterFormat.ASTC_RGBA_5x5: - return "RGBA Compressed ASTC 5 x 5 block"; - case TextureImporterFormat.ASTC_RGBA_6x6: - return "RGBA Compressed ASTC 6 x 6 block"; - case TextureImporterFormat.ASTC_RGBA_8x8: - return "RGBA Compressed ASTC 8 x 8 block"; - case TextureImporterFormat.ASTC_RGBA_10x10: - return "RGBA Compressed ASTC 10 x 10 block"; - case TextureImporterFormat.ASTC_RGBA_12x12: - return "RGBA Compressed ASTC 12 x 12 block"; -#endif - } - return "Unsupported"; - } - } -} +namespace UnityEditor.U2D.PSD +{ + internal static class TexturePlatformSettingsModal + { + public static readonly TextureImporterFormat[] kFormatsWithCompressionSettings = + { + TextureImporterFormat.PVRTC_RGB2, + TextureImporterFormat.PVRTC_RGB4, + TextureImporterFormat.PVRTC_RGBA2, + TextureImporterFormat.PVRTC_RGBA4, + TextureImporterFormat.ETC_RGB4, + TextureImporterFormat.ETC2_RGBA8, + TextureImporterFormat.ETC_RGB4, + TextureImporterFormat.ETC2_RGB4, + TextureImporterFormat.ETC2_RGB4_PUNCHTHROUGH_ALPHA, + TextureImporterFormat.ETC2_RGBA8, +#if UNITY_2019_1_OR_NEWER + TextureImporterFormat.ASTC_4x4, + TextureImporterFormat.ASTC_5x5, + TextureImporterFormat.ASTC_6x6, + TextureImporterFormat.ASTC_8x8, + TextureImporterFormat.ASTC_10x10, + TextureImporterFormat.ASTC_12x12, +#else + TextureImporterFormat.ASTC_RGB_4x4, + TextureImporterFormat.ASTC_RGB_5x5, + TextureImporterFormat.ASTC_RGB_6x6, + TextureImporterFormat.ASTC_RGB_8x8, + TextureImporterFormat.ASTC_RGB_10x10, + TextureImporterFormat.ASTC_RGB_12x12, + TextureImporterFormat.ASTC_RGBA_4x4, + TextureImporterFormat.ASTC_RGBA_5x5, + TextureImporterFormat.ASTC_RGBA_6x6, + TextureImporterFormat.ASTC_RGBA_8x8, + TextureImporterFormat.ASTC_RGBA_10x10, + TextureImporterFormat.ASTC_RGBA_12x12 + #endif + }; + + public struct BuildPlatformData + { + public string buildTargetName; + public TextureImporterFormat defaultTextureFormat; + public BuildTarget[] buildTarget; + } + + // Add new platforms here + public static readonly BuildPlatformData[] kValidBuildPlatform = new BuildPlatformData[] + { + new BuildPlatformData() + { + buildTargetName = "Default", + defaultTextureFormat = TextureImporterFormat.Automatic, + buildTarget = new[] + { + BuildTarget.NoTarget + } + }, + + new BuildPlatformData() + { + buildTargetName = "PC, Mac & Linux Standalone", + defaultTextureFormat = TextureImporterFormat.RGBA32, + buildTarget = new[] + { + BuildTarget.StandaloneWindows, + BuildTarget.StandaloneWindows64, + BuildTarget.StandaloneLinux64, + BuildTarget.StandaloneOSX, + } + }, + new BuildPlatformData() + { + buildTargetName = "iOS", + defaultTextureFormat = TextureImporterFormat.RGBA32, + buildTarget = new[] { BuildTarget.iOS } + }, + new BuildPlatformData() + { + buildTargetName = "tvOS", + defaultTextureFormat = TextureImporterFormat.RGBA32, + buildTarget = new[] { BuildTarget.tvOS } + }, + new BuildPlatformData() + { + buildTargetName = "Android", + defaultTextureFormat = TextureImporterFormat.RGBA32, + buildTarget = new[] { BuildTarget.Android } + }, + new BuildPlatformData() + { + buildTargetName = "Universal Windows Platform", + defaultTextureFormat = TextureImporterFormat.RGBA32, + buildTarget = new[] { BuildTarget.WSAPlayer } + }, + }; + + public static readonly int[] kTextureFormatsValueApplePVR = + { + (int)TextureImporterFormat.PVRTC_RGB2, + (int)TextureImporterFormat.PVRTC_RGBA2, + (int)TextureImporterFormat.PVRTC_RGB4, + (int)TextureImporterFormat.PVRTC_RGBA4, + +#if UNITY_2019_1_OR_NEWER + (int)TextureImporterFormat.ASTC_4x4, + (int)TextureImporterFormat.ASTC_5x5, + (int)TextureImporterFormat.ASTC_6x6, + (int)TextureImporterFormat.ASTC_8x8, + (int)TextureImporterFormat.ASTC_10x10, + (int)TextureImporterFormat.ASTC_12x12, +#else + (int)TextureImporterFormat.ASTC_RGB_4x4, + (int)TextureImporterFormat.ASTC_RGB_5x5, + (int)TextureImporterFormat.ASTC_RGB_6x6, + (int)TextureImporterFormat.ASTC_RGB_8x8, + (int)TextureImporterFormat.ASTC_RGB_10x10, + (int)TextureImporterFormat.ASTC_RGB_12x12, + (int)TextureImporterFormat.ASTC_RGBA_4x4, + (int)TextureImporterFormat.ASTC_RGBA_5x5, + (int)TextureImporterFormat.ASTC_RGBA_6x6, + (int)TextureImporterFormat.ASTC_RGBA_8x8, + (int)TextureImporterFormat.ASTC_RGBA_10x10, + (int)TextureImporterFormat.ASTC_RGBA_12x12, +#endif + + (int)TextureImporterFormat.RGB16, + (int)TextureImporterFormat.RGB24, + (int)TextureImporterFormat.Alpha8, + (int)TextureImporterFormat.RGBA16, + (int)TextureImporterFormat.RGBA32 + }; + + public static readonly int[] kTextureFormatsValueAndroid = + { + (int)TextureImporterFormat.DXT1, + (int)TextureImporterFormat.DXT5, +#if ENABLE_CRUNCH_TEXTURE_COMPRESSION + (int)TextureImporterFormat.DXT1Crunched, + (int)TextureImporterFormat.DXT5Crunched, +#endif + + (int)TextureImporterFormat.ETC_RGB4, + + (int)TextureImporterFormat.ETC2_RGB4, + (int)TextureImporterFormat.ETC2_RGB4_PUNCHTHROUGH_ALPHA, + (int)TextureImporterFormat.ETC2_RGBA8, + + + (int)TextureImporterFormat.PVRTC_RGB2, + (int)TextureImporterFormat.PVRTC_RGBA2, + (int)TextureImporterFormat.PVRTC_RGB4, + (int)TextureImporterFormat.PVRTC_RGBA4, + + (int)TextureImporterFormat.ETC_RGB4, + (int)TextureImporterFormat.ETC2_RGBA8, + +#if UNITY_2019_1_OR_NEWER + (int)TextureImporterFormat.ASTC_4x4, + (int)TextureImporterFormat.ASTC_5x5, + (int)TextureImporterFormat.ASTC_6x6, + (int)TextureImporterFormat.ASTC_8x8, + (int)TextureImporterFormat.ASTC_10x10, + (int)TextureImporterFormat.ASTC_12x12, +#else + (int)TextureImporterFormat.ASTC_RGB_4x4, + (int)TextureImporterFormat.ASTC_RGB_5x5, + (int)TextureImporterFormat.ASTC_RGB_6x6, + (int)TextureImporterFormat.ASTC_RGB_8x8, + (int)TextureImporterFormat.ASTC_RGB_10x10, + (int)TextureImporterFormat.ASTC_RGB_12x12, + (int)TextureImporterFormat.ASTC_RGBA_4x4, + (int)TextureImporterFormat.ASTC_RGBA_5x5, + (int)TextureImporterFormat.ASTC_RGBA_6x6, + (int)TextureImporterFormat.ASTC_RGBA_8x8, + (int)TextureImporterFormat.ASTC_RGBA_10x10, + (int)TextureImporterFormat.ASTC_RGBA_12x12, +#endif + + (int)TextureImporterFormat.RGB16, + (int)TextureImporterFormat.RGB24, + (int)TextureImporterFormat.Alpha8, + (int)TextureImporterFormat.RGBA16, + (int)TextureImporterFormat.RGBA32 + }; + + public static readonly int[] kTextureFormatsValueSTV = + { + (int)TextureImporterFormat.ETC_RGB4, + + (int)TextureImporterFormat.RGB16, + (int)TextureImporterFormat.RGB24, + (int)TextureImporterFormat.Alpha8, + (int)TextureImporterFormat.RGBA16, + (int)TextureImporterFormat.RGBA32, + }; + + public static readonly int[] kTextureFormatsValueWebGL = + { + (int)TextureImporterFormat.DXT1, + (int)TextureImporterFormat.DXT5, +#if ENABLE_CRUNCH_TEXTURE_COMPRESSION + (int)TextureImporterFormat.DXT1Crunched, + (int)TextureImporterFormat.DXT5Crunched, +#endif + (int)TextureImporterFormat.RGB16, + (int)TextureImporterFormat.RGB24, + (int)TextureImporterFormat.Alpha8, + (int)TextureImporterFormat.ARGB16, + (int)TextureImporterFormat.RGBA32 + }; + + public static readonly int[] kNormalFormatsValueDefault = + { + (int)TextureImporterFormat.BC5, + (int)TextureImporterFormat.BC7, + (int)TextureImporterFormat.DXT5, +#if ENABLE_CRUNCH_TEXTURE_COMPRESSION + (int)TextureImporterFormat.DXT5Crunched, +#endif + (int)TextureImporterFormat.ARGB16, + (int)TextureImporterFormat.RGBA32, + }; + public static readonly int[] kTextureFormatsValueDefault = + { + (int)TextureImporterFormat.DXT1, + (int)TextureImporterFormat.DXT5, +#if ENABLE_CRUNCH_TEXTURE_COMPRESSION + (int)TextureImporterFormat.DXT1Crunched, + (int)TextureImporterFormat.DXT5Crunched, +#endif + (int)TextureImporterFormat.RGB16, + (int)TextureImporterFormat.RGB24, + (int)TextureImporterFormat.Alpha8, + (int)TextureImporterFormat.ARGB16, + (int)TextureImporterFormat.RGBA32, + (int)TextureImporterFormat.RGBAHalf, + (int)TextureImporterFormat.BC4, + (int)TextureImporterFormat.BC5, + (int)TextureImporterFormat.BC6H, + (int)TextureImporterFormat.BC7, + }; + public static readonly int[] kTextureFormatsValueSingleChannel = + { + (int)TextureImporterFormat.Alpha8, + (int)TextureImporterFormat.BC4, + }; + + internal static string[] s_TextureFormatStringsWebGL; + internal static string[] s_TextureFormatStringsApplePVR; + internal static string[] s_TextureFormatStringsAndroid; + internal static string[] s_TextureFormatStringsSTV; + internal static string[] s_TextureFormatStringsSingleChannel; + internal static string[] s_TextureFormatStringsDefault; + + static TexturePlatformSettingsModal() + { + s_TextureFormatStringsApplePVR = BuildTextureStrings(kTextureFormatsValueApplePVR); + s_TextureFormatStringsAndroid = BuildTextureStrings(kTextureFormatsValueAndroid); + s_TextureFormatStringsSTV = BuildTextureStrings(kTextureFormatsValueSTV); + s_TextureFormatStringsWebGL = BuildTextureStrings(kTextureFormatsValueWebGL); + s_TextureFormatStringsDefault = BuildTextureStrings(kTextureFormatsValueDefault); + s_TextureFormatStringsSingleChannel = BuildTextureStrings(kTextureFormatsValueSingleChannel); + } + + internal static string[] BuildTextureStrings(int[] texFormatValues) + { + string[] retval = new string[texFormatValues.Length]; + for (int i = 0; i < texFormatValues.Length; i++) + { + int val = texFormatValues[i]; + retval[i] = GetTextureFormatString((TextureImporterFormat)val); + } + return retval; + } + + static string GetTextureFormatString(TextureImporterFormat format) + { + switch (format) + { + case TextureImporterFormat.DXT1: + return "RGB Crunched DTX1"; + case TextureImporterFormat.DXT5: + return "RGB Crunched DTX5"; + case TextureImporterFormat.RGB16: + return "RGB 16 bit"; + case TextureImporterFormat.RGB24: + return "RGB 24 bit"; + case TextureImporterFormat.Alpha8: + return "Alpha 8"; + case TextureImporterFormat.ARGB16: + return "ARGB 16 bit"; + case TextureImporterFormat.RGBA32: + return "RGBA 32 bit"; + case TextureImporterFormat.ARGB32: + return "ARGB 32 bit"; + case TextureImporterFormat.RGBA16: + return "RGBA 16 bit"; + case TextureImporterFormat.RGBAHalf: + return "RGBA Half"; + + case TextureImporterFormat.BC4: + return "R Compressed BC4"; + case TextureImporterFormat.BC5: + return "RG Compressed BC5"; + case TextureImporterFormat.BC6H: + return "RGB HDR Compressed BC6H"; + case TextureImporterFormat.BC7: + return "RGB(A) Compressed BC7"; + case TextureImporterFormat.PVRTC_RGB2: + return "RGB Compressed PVRTC 2 bits"; + case TextureImporterFormat.PVRTC_RGBA2: + return "RGBA Compressed PVRTC 2 bits"; + case TextureImporterFormat.PVRTC_RGB4: + return "RGB Compressed PVRTC 4 bits"; + case TextureImporterFormat.PVRTC_RGBA4: + return "RGBA Compressed PVRTC 4 bits"; + case TextureImporterFormat.ETC_RGB4: + return "RGB Compressed ETC 4 bits"; + + case TextureImporterFormat.EAC_R: + return "11-bit R Compressed EAC 4 bit"; + case TextureImporterFormat.EAC_R_SIGNED: + return "11-bit signed R Compressed EAC 4 bit"; + case TextureImporterFormat.EAC_RG: + return "11-bit RG Compressed EAC 8 bit"; + case TextureImporterFormat.EAC_RG_SIGNED: + return "11-bit signed RG Compressed EAC 8 bit"; + + case TextureImporterFormat.ETC2_RGB4: + return "RGB Compressed ETC2 4 bits"; + case TextureImporterFormat.ETC2_RGB4_PUNCHTHROUGH_ALPHA: + return "RGB + 1-bit Alpha Compressed ETC2 4 bits"; + case TextureImporterFormat.ETC2_RGBA8: + return "RGBA Compressed ETC2 8 bits"; + +#if UNITY_2019_1_OR_NEWER + case TextureImporterFormat.ASTC_4x4: + return "RGB(A) Compressed ASTC 4 x 4 block"; + case TextureImporterFormat.ASTC_5x5: + return "RGB(A) Compressed ASTC 5 x 5 block"; + case TextureImporterFormat.ASTC_6x6: + return "RGB(A) Compressed ASTC 6 x 6 block"; + case TextureImporterFormat.ASTC_8x8: + return "RGB(A) Compressed ASTC 8 x 8 block"; + case TextureImporterFormat.ASTC_10x10: + return "RGB(A) Compressed ASTC 10 x 10 block"; + case TextureImporterFormat.ASTC_12x12: + return "RGB(A) Compressed ASTC 12 x 12 block"; +#else + case TextureImporterFormat.ASTC_RGB_4x4: + return "RGB Compressed ASTC 4 x 4 block"; + case TextureImporterFormat.ASTC_RGB_5x5: + return "RGB Compressed ASTC 5 x 5 block"; + case TextureImporterFormat.ASTC_RGB_6x6: + return "RGB Compressed ASTC 6 x 6 block"; + case TextureImporterFormat.ASTC_RGB_8x8: + return "RGB Compressed ASTC 8 x 8 block"; + case TextureImporterFormat.ASTC_RGB_10x10: + return "RGB Compressed ASTC 10 x 10 block"; + case TextureImporterFormat.ASTC_RGB_12x12: + return "RGB Compressed ASTC 12 x 12 block"; + case TextureImporterFormat.ASTC_RGBA_4x4: + return "RGBA Compressed ASTC 4 x 4 block"; + case TextureImporterFormat.ASTC_RGBA_5x5: + return "RGBA Compressed ASTC 5 x 5 block"; + case TextureImporterFormat.ASTC_RGBA_6x6: + return "RGBA Compressed ASTC 6 x 6 block"; + case TextureImporterFormat.ASTC_RGBA_8x8: + return "RGBA Compressed ASTC 8 x 8 block"; + case TextureImporterFormat.ASTC_RGBA_10x10: + return "RGBA Compressed ASTC 10 x 10 block"; + case TextureImporterFormat.ASTC_RGBA_12x12: + return "RGBA Compressed ASTC 12 x 12 block"; +#endif + } + return "Unsupported"; + } + } +} diff --git a/Editor/TexturePlatformSettingsModal.cs.meta b/Editor/TexturePlatformSettingsModal.cs.meta index bb86804..769299e 100644 --- a/Editor/TexturePlatformSettingsModal.cs.meta +++ b/Editor/TexturePlatformSettingsModal.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 82b98efb927566943b71cfb089627aa4 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 82b98efb927566943b71cfb089627aa4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/TexturePlatformSettingsView.cs b/Editor/TexturePlatformSettingsView.cs index 3bda239..1c1cac9 100644 --- a/Editor/TexturePlatformSettingsView.cs +++ b/Editor/TexturePlatformSettingsView.cs @@ -1,155 +1,155 @@ -using UnityEngine; - -namespace UnityEditor.U2D.PSD -{ - internal class TexturePlatformSettingsView - { - class Styles - { - public readonly GUIContent textureFormatLabel = new GUIContent("Format"); - public readonly GUIContent maxTextureSizeLabel = new GUIContent("Max Texture Size", "Maximum size of the packed texture."); - public readonly GUIContent compressionLabel = new GUIContent("Compression", "How will this texture be compressed?"); - public readonly GUIContent resizeAlgorithmLabel = new GUIContent("Resize", "Algorithm to use when resizing texture"); - public readonly GUIContent useCrunchedCompressionLabel = new GUIContent("Use Crunch Compression", "Texture is crunch-compressed to save space on disk when applicable."); - public readonly GUIContent compressionQualityLabel = new GUIContent("Compressor Quality"); - public readonly GUIContent compressionQualitySliderLabel = new GUIContent("Compressor Quality", "Use the slider to adjust compression quality from 0 (Fastest) to 100 (Best)"); - - public readonly int[] kMaxTextureSizeValues = { 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192 }; - public readonly GUIContent[] kMaxTextureSizeStrings; - - public readonly GUIContent[] kTextureCompressionOptions = - { - new GUIContent("None", "Texture is not compressed."), - new GUIContent("Low Quality", "Texture compressed with low quality but high performance, high compression format."), - new GUIContent("Normal Quality", "Texture is compressed with a standard format."), - new GUIContent("High Quality", "Texture compressed with a high quality format."), - }; - - public readonly GUIContent[] kResizeAlgoritmOptions = - { - new GUIContent(TextureResizeAlgorithm.Mitchell.ToString()), - new GUIContent(TextureResizeAlgorithm.Bilinear.ToString()), - }; - - public readonly int[] kTextureCompressionValues = - { - (int)TextureImporterCompression.Uncompressed, - (int)TextureImporterCompression.CompressedLQ, - (int)TextureImporterCompression.Compressed, - (int)TextureImporterCompression.CompressedHQ - }; - - public readonly GUIContent[] kMobileCompressionQualityOptions = - { - new GUIContent("Fast"), - new GUIContent("Normal"), - new GUIContent("Best") - }; - - public Styles() - { - kMaxTextureSizeStrings = new GUIContent[kMaxTextureSizeValues.Length]; - for (var i = 0; i < kMaxTextureSizeValues.Length; ++i) - kMaxTextureSizeStrings[i] = new GUIContent(string.Format("{0}", kMaxTextureSizeValues[i])); - } - } - - private static Styles s_Styles; - - public string buildPlatformTitle { get; set; } - - internal TexturePlatformSettingsView() - { - s_Styles = s_Styles ?? new Styles(); - } - - public virtual TextureResizeAlgorithm DrawResizeAlgorithm(TextureResizeAlgorithm defaultValue, bool isMixedValue, bool isDisabled, out bool changed) - { - using (new EditorGUI.DisabledScope(isDisabled)) - { - EditorGUI.BeginChangeCheck(); - EditorGUI.showMixedValue = isMixedValue; - defaultValue = (TextureResizeAlgorithm)EditorGUILayout.EnumPopup(s_Styles.resizeAlgorithmLabel, defaultValue); - EditorGUI.showMixedValue = false; - changed = EditorGUI.EndChangeCheck(); - } - return defaultValue; - } - - public virtual TextureImporterCompression DrawCompression(TextureImporterCompression defaultValue, bool isMixedValue, out bool changed) - { - EditorGUI.BeginChangeCheck(); - EditorGUI.showMixedValue = isMixedValue; - defaultValue = (TextureImporterCompression)EditorGUILayout.IntPopup(s_Styles.compressionLabel, (int)defaultValue, s_Styles.kTextureCompressionOptions, s_Styles.kTextureCompressionValues); - EditorGUI.showMixedValue = false; - changed = EditorGUI.EndChangeCheck(); - return defaultValue; - } - - public virtual bool DrawUseCrunchedCompression(bool defaultValue, bool isMixedValue, out bool changed) - { - EditorGUI.BeginChangeCheck(); - EditorGUI.showMixedValue = isMixedValue; - defaultValue = EditorGUILayout.Toggle(s_Styles.useCrunchedCompressionLabel, defaultValue); - EditorGUI.showMixedValue = false; - changed = EditorGUI.EndChangeCheck(); - return defaultValue; - } - - public virtual bool DrawOverride(bool defaultValue, bool isMixedValue, out bool changed) - { - EditorGUI.BeginChangeCheck(); - EditorGUI.showMixedValue = isMixedValue; - defaultValue = EditorGUILayout.ToggleLeft(new GUIContent("Override"), defaultValue); - EditorGUI.showMixedValue = false; - changed = EditorGUI.EndChangeCheck(); - return defaultValue; - } - - public virtual int DrawMaxSize(int defaultValue, bool isMixedValue, bool isDisabled, out bool changed) - { - using (new EditorGUI.DisabledScope(isDisabled)) - { - EditorGUI.BeginChangeCheck(); - EditorGUI.showMixedValue = isMixedValue; - defaultValue = EditorGUILayout.IntPopup(s_Styles.maxTextureSizeLabel, defaultValue, s_Styles.kMaxTextureSizeStrings, s_Styles.kMaxTextureSizeValues); - EditorGUI.showMixedValue = false; - changed = EditorGUI.EndChangeCheck(); - return defaultValue; - } - } - - public virtual TextureImporterFormat DrawFormat(TextureImporterFormat defaultValue, int[] displayValues, string[] displayStrings, bool isMixedValue, bool isDisabled, out bool changed) - { - using (new EditorGUI.DisabledScope(isDisabled)) - { - EditorGUI.BeginChangeCheck(); - EditorGUI.showMixedValue = isMixedValue; - defaultValue = (TextureImporterFormat)EditorGUILayout.IntPopup(s_Styles.textureFormatLabel.text, (int)defaultValue, displayStrings, displayValues); - EditorGUI.showMixedValue = false; - changed = EditorGUI.EndChangeCheck(); - return defaultValue; - } - } - - public virtual int DrawCompressionQualityPopup(int defaultValue, bool isMixedValue, out bool changed) - { - EditorGUI.BeginChangeCheck(); - EditorGUI.showMixedValue = isMixedValue; - defaultValue = EditorGUILayout.Popup(s_Styles.compressionQualityLabel, defaultValue, s_Styles.kMobileCompressionQualityOptions); - EditorGUI.showMixedValue = false; - changed = EditorGUI.EndChangeCheck(); - return defaultValue; - } - - public virtual int DrawCompressionQualitySlider(int defaultValue, bool isMixedValue, out bool changed) - { - EditorGUI.BeginChangeCheck(); - EditorGUI.showMixedValue = isMixedValue; - defaultValue = EditorGUILayout.IntSlider(s_Styles.compressionQualitySliderLabel, defaultValue, 0, 100); - EditorGUI.showMixedValue = false; - changed = EditorGUI.EndChangeCheck(); - return defaultValue; - } - } -} +using UnityEngine; + +namespace UnityEditor.U2D.PSD +{ + internal class TexturePlatformSettingsView + { + class Styles + { + public readonly GUIContent textureFormatLabel = new GUIContent("Format"); + public readonly GUIContent maxTextureSizeLabel = new GUIContent("Max Texture Size", "Maximum size of the packed texture."); + public readonly GUIContent compressionLabel = new GUIContent("Compression", "How will this texture be compressed?"); + public readonly GUIContent resizeAlgorithmLabel = new GUIContent("Resize", "Algorithm to use when resizing texture"); + public readonly GUIContent useCrunchedCompressionLabel = new GUIContent("Use Crunch Compression", "Texture is crunch-compressed to save space on disk when applicable."); + public readonly GUIContent compressionQualityLabel = new GUIContent("Compressor Quality"); + public readonly GUIContent compressionQualitySliderLabel = new GUIContent("Compressor Quality", "Use the slider to adjust compression quality from 0 (Fastest) to 100 (Best)"); + + public readonly int[] kMaxTextureSizeValues = { 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192 }; + public readonly GUIContent[] kMaxTextureSizeStrings; + + public readonly GUIContent[] kTextureCompressionOptions = + { + new GUIContent("None", "Texture is not compressed."), + new GUIContent("Low Quality", "Texture compressed with low quality but high performance, high compression format."), + new GUIContent("Normal Quality", "Texture is compressed with a standard format."), + new GUIContent("High Quality", "Texture compressed with a high quality format."), + }; + + public readonly GUIContent[] kResizeAlgoritmOptions = + { + new GUIContent(TextureResizeAlgorithm.Mitchell.ToString()), + new GUIContent(TextureResizeAlgorithm.Bilinear.ToString()), + }; + + public readonly int[] kTextureCompressionValues = + { + (int)TextureImporterCompression.Uncompressed, + (int)TextureImporterCompression.CompressedLQ, + (int)TextureImporterCompression.Compressed, + (int)TextureImporterCompression.CompressedHQ + }; + + public readonly GUIContent[] kMobileCompressionQualityOptions = + { + new GUIContent("Fast"), + new GUIContent("Normal"), + new GUIContent("Best") + }; + + public Styles() + { + kMaxTextureSizeStrings = new GUIContent[kMaxTextureSizeValues.Length]; + for (var i = 0; i < kMaxTextureSizeValues.Length; ++i) + kMaxTextureSizeStrings[i] = new GUIContent(string.Format("{0}", kMaxTextureSizeValues[i])); + } + } + + private static Styles s_Styles; + + public string buildPlatformTitle { get; set; } + + internal TexturePlatformSettingsView() + { + s_Styles = s_Styles ?? new Styles(); + } + + public virtual TextureResizeAlgorithm DrawResizeAlgorithm(TextureResizeAlgorithm defaultValue, bool isMixedValue, bool isDisabled, out bool changed) + { + using (new EditorGUI.DisabledScope(isDisabled)) + { + EditorGUI.BeginChangeCheck(); + EditorGUI.showMixedValue = isMixedValue; + defaultValue = (TextureResizeAlgorithm)EditorGUILayout.EnumPopup(s_Styles.resizeAlgorithmLabel, defaultValue); + EditorGUI.showMixedValue = false; + changed = EditorGUI.EndChangeCheck(); + } + return defaultValue; + } + + public virtual TextureImporterCompression DrawCompression(TextureImporterCompression defaultValue, bool isMixedValue, out bool changed) + { + EditorGUI.BeginChangeCheck(); + EditorGUI.showMixedValue = isMixedValue; + defaultValue = (TextureImporterCompression)EditorGUILayout.IntPopup(s_Styles.compressionLabel, (int)defaultValue, s_Styles.kTextureCompressionOptions, s_Styles.kTextureCompressionValues); + EditorGUI.showMixedValue = false; + changed = EditorGUI.EndChangeCheck(); + return defaultValue; + } + + public virtual bool DrawUseCrunchedCompression(bool defaultValue, bool isMixedValue, out bool changed) + { + EditorGUI.BeginChangeCheck(); + EditorGUI.showMixedValue = isMixedValue; + defaultValue = EditorGUILayout.Toggle(s_Styles.useCrunchedCompressionLabel, defaultValue); + EditorGUI.showMixedValue = false; + changed = EditorGUI.EndChangeCheck(); + return defaultValue; + } + + public virtual bool DrawOverride(bool defaultValue, bool isMixedValue, out bool changed) + { + EditorGUI.BeginChangeCheck(); + EditorGUI.showMixedValue = isMixedValue; + defaultValue = EditorGUILayout.ToggleLeft(new GUIContent("Override"), defaultValue); + EditorGUI.showMixedValue = false; + changed = EditorGUI.EndChangeCheck(); + return defaultValue; + } + + public virtual int DrawMaxSize(int defaultValue, bool isMixedValue, bool isDisabled, out bool changed) + { + using (new EditorGUI.DisabledScope(isDisabled)) + { + EditorGUI.BeginChangeCheck(); + EditorGUI.showMixedValue = isMixedValue; + defaultValue = EditorGUILayout.IntPopup(s_Styles.maxTextureSizeLabel, defaultValue, s_Styles.kMaxTextureSizeStrings, s_Styles.kMaxTextureSizeValues); + EditorGUI.showMixedValue = false; + changed = EditorGUI.EndChangeCheck(); + return defaultValue; + } + } + + public virtual TextureImporterFormat DrawFormat(TextureImporterFormat defaultValue, int[] displayValues, string[] displayStrings, bool isMixedValue, bool isDisabled, out bool changed) + { + using (new EditorGUI.DisabledScope(isDisabled)) + { + EditorGUI.BeginChangeCheck(); + EditorGUI.showMixedValue = isMixedValue; + defaultValue = (TextureImporterFormat)EditorGUILayout.IntPopup(s_Styles.textureFormatLabel.text, (int)defaultValue, displayStrings, displayValues); + EditorGUI.showMixedValue = false; + changed = EditorGUI.EndChangeCheck(); + return defaultValue; + } + } + + public virtual int DrawCompressionQualityPopup(int defaultValue, bool isMixedValue, out bool changed) + { + EditorGUI.BeginChangeCheck(); + EditorGUI.showMixedValue = isMixedValue; + defaultValue = EditorGUILayout.Popup(s_Styles.compressionQualityLabel, defaultValue, s_Styles.kMobileCompressionQualityOptions); + EditorGUI.showMixedValue = false; + changed = EditorGUI.EndChangeCheck(); + return defaultValue; + } + + public virtual int DrawCompressionQualitySlider(int defaultValue, bool isMixedValue, out bool changed) + { + EditorGUI.BeginChangeCheck(); + EditorGUI.showMixedValue = isMixedValue; + defaultValue = EditorGUILayout.IntSlider(s_Styles.compressionQualitySliderLabel, defaultValue, 0, 100); + EditorGUI.showMixedValue = false; + changed = EditorGUI.EndChangeCheck(); + return defaultValue; + } + } +} diff --git a/Editor/TexturePlatformSettingsView.cs.meta b/Editor/TexturePlatformSettingsView.cs.meta index d649936..1599f27 100644 --- a/Editor/TexturePlatformSettingsView.cs.meta +++ b/Editor/TexturePlatformSettingsView.cs.meta @@ -1,13 +1,13 @@ -fileFormatVersion: 2 -guid: 6ba7b4ee1b04b5845a1bc6fbb53cf7bc -timeCreated: 1502357266 -licenseType: Pro -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 6ba7b4ee1b04b5845a1bc6fbb53cf7bc +timeCreated: 1502357266 +licenseType: Pro +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/TextureSettingsGUI.cs b/Editor/TextureSettingsGUI.cs index cb2cc8c..a26f3ff 100644 --- a/Editor/TextureSettingsGUI.cs +++ b/Editor/TextureSettingsGUI.cs @@ -1,383 +1,383 @@ -//using System; -//using System.Collections; -//using System.Collections.Generic; -//using UnityEditor; -//using UnityEngine; - -//namespace UnityEditor.U2D -//{ -// public class TextureSettingsGUI -// { -// public SerializedProperty colorTexture; -// public SerializedProperty readable; -// public SerializedProperty npotScale; -// public SerializedProperty filterMode; -// public SerializedProperty aniso; -// public SerializedProperty enablePostProcessor; - -// readonly int[] m_FilterModeOptions = (int[])(Enum.GetValues(typeof(FilterMode))); -// public TextureSettingsGUI(SerializedProperty sp) -// { -// colorTexture = sp.FindPropertyRelative("m_ColorTexture"); -// readable = sp.FindPropertyRelative("m_Readable"); -// npotScale = sp.FindPropertyRelative("m_NPOTScale"); -// filterMode = sp.FindPropertyRelative("m_FilterMode"); -// aniso = sp.FindPropertyRelative("m_Aniso"); -// enablePostProcessor = sp.FindPropertyRelative("m_EnablePostProcessor"); -// } - -// public void OnInspectorGUI(bool isPOT, bool isNormalMap, bool hasMipMap, bool isCubeMap, bool hasMipmapFadeout) -// { - -// TextureSettingsGUIUtils.ToggleFromInt(colorTexture, TextureSettingsGUIUtils.s_Styles.sRGBTexture); -// TextureSettingsGUIUtils.ToggleFromInt(readable, TextureSettingsGUIUtils.s_Styles.readWrite); -// using (new EditorGUI.DisabledScope(isPOT)) -// { -// TextureSettingsGUIUtils.EnumPopup(npotScale, typeof(TextureImporterNPOTScale), TextureSettingsGUIUtils.s_Styles.npot); -// } - -// EditorGUI.BeginChangeCheck(); -// // Filter mode -// EditorGUI.showMixedValue = filterMode.hasMultipleDifferentValues; -// FilterMode filter = (FilterMode)filterMode.intValue; -// if ((int)filter == -1) -// { -// if (hasMipmapFadeout || isNormalMap) -// filter = FilterMode.Trilinear; -// else -// filter = FilterMode.Bilinear; -// } -// filter = (FilterMode)EditorGUILayout.IntPopup(TextureSettingsGUIUtils.s_Styles.filterMode, (int)filter, TextureSettingsGUIUtils.s_Styles.filterModeOptions, m_FilterModeOptions); -// EditorGUI.showMixedValue = false; -// if (EditorGUI.EndChangeCheck()) -// filterMode.intValue = (int)filter; - -// // Aniso -// bool showAniso = (FilterMode)filter != FilterMode.Point && hasMipMap && isCubeMap; -// using (new EditorGUI.DisabledScope(!showAniso)) -// { -// EditorGUI.BeginChangeCheck(); -// EditorGUI.showMixedValue = aniso.hasMultipleDifferentValues; -// int anisoValue = aniso.intValue; -// if (anisoValue == -1) -// anisoValue = 1; -// //aniso = EditorGUILayout.IntSlider("Aniso Level", aniso, 0, 16); -// EditorGUI.showMixedValue = false; -// if (EditorGUI.EndChangeCheck()) -// aniso.intValue = anisoValue; - -// if (anisoValue > 1) -// { -// if (QualitySettings.anisotropicFiltering == AnisotropicFiltering.Disable) -// EditorGUILayout.HelpBox("Anisotropic filtering is disabled for all textures in Quality Settings.", MessageType.Info); -// else if (QualitySettings.anisotropicFiltering == AnisotropicFiltering.ForceEnable) -// EditorGUILayout.HelpBox("Anisotropic filtering is enabled for all textures in Quality Settings.", MessageType.Info); -// } -// } -// } -// } - -// public class TextureSpriteSettingsGUI -// { -// public SerializedProperty packingTag; -// public SerializedProperty ppu; -// public SerializedProperty meshType; -// public SerializedProperty extrudeEdges; - -// public TextureSpriteSettingsGUI(SerializedProperty sp) -// { -// packingTag = sp.FindPropertyRelative("m_PackingTag"); -// ppu = sp.FindPropertyRelative("m_PixelsPerUnit"); -// meshType = sp.FindPropertyRelative("m_MeshType"); -// extrudeEdges = sp.FindPropertyRelative("m_ExtrudeEdges"); -// } - -// public void OnInspectorGUI() -// { -// //// Show generic attributes -// //if (m_SpriteMode.intValue != 0) -// //{ -// // EditorGUILayout.PropertyField(m_SpritePackingTag, s_Styles.spritePackingTag); -// // EditorGUILayout.PropertyField(m_SpritePixelsToUnits, s_Styles.spritePixelsPerUnit); - -// // if (m_SpriteMode.intValue != (int)SpriteImportMode.Polygon && !m_SpriteMode.hasMultipleDifferentValues) -// // { -// // EditorGUILayout.IntPopup(m_SpriteMeshType, s_Styles.spriteMeshTypeOptions, new[] { 0, 1 }, s_Styles.spriteMeshType); -// // } -// // EditorGUILayout.EndFadeGroup(); - -// // EditorGUILayout.IntSlider(m_SpriteExtrude, 0, 32, s_Styles.spriteExtrude); - -// // if (m_SpriteMode.intValue == 1) -// // { -// // EditorGUILayout.IntPopup(m_Alignment, s_Styles.spriteAlignmentOptions, new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, s_Styles.spriteAlignment); - -// // if (m_Alignment.intValue == (int)SpriteAlignment.Custom) -// // { -// // GUILayout.BeginHorizontal(); -// // EditorGUILayout.PropertyField(m_SpritePivot, new GUIContent()); -// // GUILayout.EndHorizontal(); -// // } -// // } -// //} -// } -// } - -// public class TextureWrapSettingsGUI -// { -// public SerializedProperty wrapMode; -// public SerializedProperty wrapModeU; -// public SerializedProperty wrapModeV; -// public SerializedProperty wrapModeW; - -// public TextureWrapSettingsGUI(SerializedProperty sp) -// { -// wrapMode = sp.FindPropertyRelative("m_WrapMode"); -// wrapModeU = sp.FindPropertyRelative("m_WrapModeU"); -// wrapModeV = sp.FindPropertyRelative("m_WrapModeV"); -// wrapModeW = sp.FindPropertyRelative("m_WrapModeW"); -// } - -// public void OnInspectorGUI() -// { - -// } -// } - - -// public class TextureAlphaSettingsGUI -// { -// public SerializedProperty tolerance; -// public SerializedProperty source; - -// public TextureAlphaSettingsGUI(SerializedProperty sp) -// { -// tolerance = sp.FindPropertyRelative("m_AlphaTolerance"); -// source = sp.FindPropertyRelative("m_AlphaSource"); -// } - -// public void OnInspectorGUI() -// { - -// } -// } - -// public class TextureMipmapSettingsGUI -// { -// public SerializedProperty filter; -// public SerializedProperty borderMipmap; -// public SerializedProperty fadeout; -// public SerializedProperty preserveCoverage; -// public SerializedProperty fadeDistanceStart; -// public SerializedProperty fadeDistanceEnd; - -// public TextureMipmapSettingsGUI(SerializedProperty sp) -// { -// filter = sp.FindPropertyRelative("m_Filter"); -// borderMipmap = sp.FindPropertyRelative("m_BorderMipmap"); -// fadeout = sp.FindPropertyRelative("m_Fadeout"); -// preserveCoverage = sp.FindPropertyRelative("m_PreserveCoverage"); -// fadeDistanceStart = sp.FindPropertyRelative("m_FadeDistanceStart"); -// fadeDistanceEnd = sp.FindPropertyRelative("m_FadeDistanceEnd"); -// } - -// public void OnInspectorGUI() -// { - -// } -// } - -// public class TextureNormalSettingsGUI -// { -// public SerializedProperty filter; -// public SerializedProperty generateFromGrayScale; -// public SerializedProperty bumpiness; - -// public TextureNormalSettingsGUI(SerializedProperty sp) -// { -// filter = sp.FindPropertyRelative("m_Filter"); -// generateFromGrayScale = sp.FindPropertyRelative("m_GenerateFromGrayScale"); -// bumpiness = sp.FindPropertyRelative("m_Bumpiness"); -// } - -// public void OnInspectorGUI() -// { - -// } -// } - - -// public class TextureCubemapSettingsGUI -// { -// public SerializedProperty convolution; -// public SerializedProperty mode; -// public SerializedProperty seamless; - -// public TextureCubemapSettingsGUI(SerializedProperty sp) -// { -// convolution = sp.FindPropertyRelative("m_Convolution"); -// mode = sp.FindPropertyRelative("m_Mode"); -// seamless = sp.FindPropertyRelative("m_Seamless"); -// } - -// public void OnInspectorGUI() -// { - -// } -// } - - -// static class TextureSettingsGUIUtils -// { -// public static void ToggleFromInt(SerializedProperty property, GUIContent label) -// { -// EditorGUI.BeginChangeCheck(); -// EditorGUI.showMixedValue = property.hasMultipleDifferentValues; -// int value = EditorGUILayout.Toggle(label, property.intValue > 0) ? 1 : 0; -// EditorGUI.showMixedValue = false; -// if (EditorGUI.EndChangeCheck()) -// property.intValue = value; -// } - -// public static void EnumPopup(SerializedProperty property, System.Type type, GUIContent label) -// { -// EditorGUILayout.IntPopup(label.text, property.intValue, -// System.Enum.GetNames(type), -// System.Enum.GetValues(type) as int[]); -// } - -// internal class Styles -// { -// public readonly GUIContent textureTypeTitle = new GUIContent("Texture Type", "What will this texture be used for?"); -// public readonly GUIContent[] textureTypeOptions = -// { -// new GUIContent("Default", "Texture is a normal image such as a diffuse texture or other."), -// new GUIContent("Sprite (2D and UI)", "Texture is used for a sprite."), -// }; -// public readonly int[] textureTypeValues = -// { -// (int)TextureImporterType.Default, -// (int)TextureImporterType.Sprite, -// }; - -// public readonly GUIContent textureShape = new GUIContent("Texture Shape", "What shape is this texture?"); -// private readonly GUIContent textureShape2D = new GUIContent("2D, Texture is 2D."); -// private readonly GUIContent textureShapeCube = new GUIContent("Cube", "Texture is a Cubemap."); -// public readonly Dictionary textureShapeOptionsDictionnary = new Dictionary(); -// public readonly Dictionary textureShapeValuesDictionnary = new Dictionary(); - - -// public readonly GUIContent filterMode = new GUIContent("Filter Mode"); -// public readonly GUIContent[] filterModeOptions = -// { -// new GUIContent("Point (no filter)"), -// new GUIContent("Bilinear"), -// new GUIContent("Trilinear") -// }; - -// public readonly GUIContent textureFormat = new GUIContent("Format"); - -// public readonly GUIContent defaultPlatform = new GUIContent("Default"); -// public readonly GUIContent mipmapFadeOutToggle = new GUIContent("Fadeout Mip Maps"); -// public readonly GUIContent mipmapFadeOut = new GUIContent("Fade Range"); -// public readonly GUIContent readWrite = new GUIContent("Read/Write Enabled", "Enable to be able to access the raw pixel data from code."); - -// public readonly GUIContent alphaSource = new GUIContent("Alpha Source", "How is the alpha generated for the imported texture."); -// public readonly GUIContent[] alphaSourceOptions = -// { -// new GUIContent("None", "No Alpha will be used."), -// new GUIContent("Input Texture Alpha", "Use Alpha from the input texture if one is provided."), -// new GUIContent("From Gray Scale", "Generate Alpha from image gray scale."), -// }; -// public readonly int[] alphaSourceValues = -// { -// (int)TextureImporterAlphaSource.None, -// (int)TextureImporterAlphaSource.FromInput, -// (int)TextureImporterAlphaSource.FromGrayScale, -// }; - -// public readonly GUIContent generateMipMaps = new GUIContent("Generate Mip Maps"); -// public readonly GUIContent sRGBTexture = new GUIContent("sRGB (Color Texture)", "Texture content is stored in gamma space. Non-HDR color textures should enable this flag (except if used for IMGUI)."); -// public readonly GUIContent borderMipMaps = new GUIContent("Border Mip Maps"); -// public readonly GUIContent mipMapsPreserveCoverage = new GUIContent("Mip Maps Preserve Coverage", "The alpha channel of generated Mip Maps will preserve coverage during the alpha test."); -// public readonly GUIContent alphaTestReferenceValue = new GUIContent("Alpha Cutoff Value", "The reference value used during the alpha test. Controls Mip Map coverage."); -// public readonly GUIContent mipMapFilter = new GUIContent("Mip Map Filtering"); -// public readonly GUIContent[] mipMapFilterOptions = -// { -// new GUIContent("Box"), -// new GUIContent("Kaiser"), -// }; -// public readonly GUIContent npot = new GUIContent("Non Power of 2", "How non-power-of-two textures are scaled on import."); - -// public readonly GUIContent compressionQuality = new GUIContent("Compressor Quality"); -// public readonly GUIContent compressionQualitySlider = new GUIContent("Compressor Quality", "Use the slider to adjust compression quality from 0 (Fastest) to 100 (Best)"); -// public readonly GUIContent[] mobileCompressionQualityOptions = -// { -// new GUIContent("Fast"), -// new GUIContent("Normal"), -// new GUIContent("Best") -// }; - -// public readonly GUIContent spriteMode = new GUIContent("Sprite Mode"); -// public readonly GUIContent[] spriteModeOptions = -// { -// new GUIContent("Single"), -// new GUIContent("Multiple"), -// new GUIContent("Polygon"), -// }; -// public readonly GUIContent[] spriteMeshTypeOptions = -// { -// new GUIContent("Full Rect"), -// new GUIContent("Tight"), -// }; - -// public readonly GUIContent spritePackingTag = new GUIContent("Packing Tag", "Tag for the Sprite Packing system."); -// public readonly GUIContent spritePixelsPerUnit = new GUIContent("Pixels Per Unit", "How many pixels in the sprite correspond to one unit in the world."); -// public readonly GUIContent spriteExtrude = new GUIContent("Extrude Edges", "How much empty area to leave around the sprite in the generated mesh."); -// public readonly GUIContent spriteMeshType = new GUIContent("Mesh Type", "Type of sprite mesh to generate."); -// public readonly GUIContent spriteAlignment = new GUIContent("Pivot", "Sprite pivot point in its localspace. May be used for syncing animation frames of different sizes."); -// public readonly GUIContent[] spriteAlignmentOptions = -// { -// new GUIContent("Center"), -// new GUIContent("Top Left"), -// new GUIContent("Top"), -// new GUIContent("Top Right"), -// new GUIContent("Left"), -// new GUIContent("Right"), -// new GUIContent("Bottom Left"), -// new GUIContent("Bottom"), -// new GUIContent("Bottom Right"), -// new GUIContent("Custom"), -// }; - -// public readonly GUIContent alphaIsTransparency = new GUIContent("Alpha Is Transparency", "If the provided alpha channel is transparency, enable this to pre-filter the color to avoid texture filtering artifacts. This is not supported for HDR textures."); -// public readonly GUIContent etc1Compression = new GUIContent("Compress using ETC1 (split alpha channel)|Alpha for this texture will be preserved by splitting the alpha channel to another texture, and both resulting textures will be compressed using ETC1."); - -// public readonly GUIContent crunchedCompression = new GUIContent("Use Crunch Compression", "Texture is crunch-compressed to save space on disk when applicable."); - -// public readonly GUIContent showAdvanced = new GUIContent("Advanced", "Show advanced settings."); - -// public Styles() -// { -// // This is far from ideal, but it's better than having tons of logic in the GUI code itself. -// // The combination should not grow too much anyway since only Texture3D will be added later. -// GUIContent[] s2D_Options = { textureShape2D }; -// GUIContent[] sCube_Options = { textureShapeCube }; -// GUIContent[] s2D_Cube_Options = { textureShape2D, textureShapeCube }; -// textureShapeOptionsDictionnary.Add(TextureImporterShape.Texture2D, s2D_Options); -// textureShapeOptionsDictionnary.Add(TextureImporterShape.TextureCube, sCube_Options); -// textureShapeOptionsDictionnary.Add(TextureImporterShape.Texture2D | TextureImporterShape.TextureCube, s2D_Cube_Options); - -// int[] s2D_Values = { (int)TextureImporterShape.Texture2D }; -// int[] sCube_Values = { (int)TextureImporterShape.TextureCube }; -// int[] s2D_Cube_Values = { (int)TextureImporterShape.Texture2D, (int)TextureImporterShape.TextureCube }; -// textureShapeValuesDictionnary.Add(TextureImporterShape.Texture2D, s2D_Values); -// textureShapeValuesDictionnary.Add(TextureImporterShape.TextureCube, sCube_Values); -// textureShapeValuesDictionnary.Add(TextureImporterShape.Texture2D | TextureImporterShape.TextureCube, s2D_Cube_Values); - -// } -// } - -// internal static Styles s_Styles; -// } -//} +//using System; +//using System.Collections; +//using System.Collections.Generic; +//using UnityEditor; +//using UnityEngine; + +//namespace UnityEditor.U2D +//{ +// public class TextureSettingsGUI +// { +// public SerializedProperty colorTexture; +// public SerializedProperty readable; +// public SerializedProperty npotScale; +// public SerializedProperty filterMode; +// public SerializedProperty aniso; +// public SerializedProperty enablePostProcessor; + +// readonly int[] m_FilterModeOptions = (int[])(Enum.GetValues(typeof(FilterMode))); +// public TextureSettingsGUI(SerializedProperty sp) +// { +// colorTexture = sp.FindPropertyRelative("m_ColorTexture"); +// readable = sp.FindPropertyRelative("m_Readable"); +// npotScale = sp.FindPropertyRelative("m_NPOTScale"); +// filterMode = sp.FindPropertyRelative("m_FilterMode"); +// aniso = sp.FindPropertyRelative("m_Aniso"); +// enablePostProcessor = sp.FindPropertyRelative("m_EnablePostProcessor"); +// } + +// public void OnInspectorGUI(bool isPOT, bool isNormalMap, bool hasMipMap, bool isCubeMap, bool hasMipmapFadeout) +// { + +// TextureSettingsGUIUtils.ToggleFromInt(colorTexture, TextureSettingsGUIUtils.s_Styles.sRGBTexture); +// TextureSettingsGUIUtils.ToggleFromInt(readable, TextureSettingsGUIUtils.s_Styles.readWrite); +// using (new EditorGUI.DisabledScope(isPOT)) +// { +// TextureSettingsGUIUtils.EnumPopup(npotScale, typeof(TextureImporterNPOTScale), TextureSettingsGUIUtils.s_Styles.npot); +// } + +// EditorGUI.BeginChangeCheck(); +// // Filter mode +// EditorGUI.showMixedValue = filterMode.hasMultipleDifferentValues; +// FilterMode filter = (FilterMode)filterMode.intValue; +// if ((int)filter == -1) +// { +// if (hasMipmapFadeout || isNormalMap) +// filter = FilterMode.Trilinear; +// else +// filter = FilterMode.Bilinear; +// } +// filter = (FilterMode)EditorGUILayout.IntPopup(TextureSettingsGUIUtils.s_Styles.filterMode, (int)filter, TextureSettingsGUIUtils.s_Styles.filterModeOptions, m_FilterModeOptions); +// EditorGUI.showMixedValue = false; +// if (EditorGUI.EndChangeCheck()) +// filterMode.intValue = (int)filter; + +// // Aniso +// bool showAniso = (FilterMode)filter != FilterMode.Point && hasMipMap && isCubeMap; +// using (new EditorGUI.DisabledScope(!showAniso)) +// { +// EditorGUI.BeginChangeCheck(); +// EditorGUI.showMixedValue = aniso.hasMultipleDifferentValues; +// int anisoValue = aniso.intValue; +// if (anisoValue == -1) +// anisoValue = 1; +// //aniso = EditorGUILayout.IntSlider("Aniso Level", aniso, 0, 16); +// EditorGUI.showMixedValue = false; +// if (EditorGUI.EndChangeCheck()) +// aniso.intValue = anisoValue; + +// if (anisoValue > 1) +// { +// if (QualitySettings.anisotropicFiltering == AnisotropicFiltering.Disable) +// EditorGUILayout.HelpBox("Anisotropic filtering is disabled for all textures in Quality Settings.", MessageType.Info); +// else if (QualitySettings.anisotropicFiltering == AnisotropicFiltering.ForceEnable) +// EditorGUILayout.HelpBox("Anisotropic filtering is enabled for all textures in Quality Settings.", MessageType.Info); +// } +// } +// } +// } + +// public class TextureSpriteSettingsGUI +// { +// public SerializedProperty packingTag; +// public SerializedProperty ppu; +// public SerializedProperty meshType; +// public SerializedProperty extrudeEdges; + +// public TextureSpriteSettingsGUI(SerializedProperty sp) +// { +// packingTag = sp.FindPropertyRelative("m_PackingTag"); +// ppu = sp.FindPropertyRelative("m_PixelsPerUnit"); +// meshType = sp.FindPropertyRelative("m_MeshType"); +// extrudeEdges = sp.FindPropertyRelative("m_ExtrudeEdges"); +// } + +// public void OnInspectorGUI() +// { +// //// Show generic attributes +// //if (m_SpriteMode.intValue != 0) +// //{ +// // EditorGUILayout.PropertyField(m_SpritePackingTag, s_Styles.spritePackingTag); +// // EditorGUILayout.PropertyField(m_SpritePixelsToUnits, s_Styles.spritePixelsPerUnit); + +// // if (m_SpriteMode.intValue != (int)SpriteImportMode.Polygon && !m_SpriteMode.hasMultipleDifferentValues) +// // { +// // EditorGUILayout.IntPopup(m_SpriteMeshType, s_Styles.spriteMeshTypeOptions, new[] { 0, 1 }, s_Styles.spriteMeshType); +// // } +// // EditorGUILayout.EndFadeGroup(); + +// // EditorGUILayout.IntSlider(m_SpriteExtrude, 0, 32, s_Styles.spriteExtrude); + +// // if (m_SpriteMode.intValue == 1) +// // { +// // EditorGUILayout.IntPopup(m_Alignment, s_Styles.spriteAlignmentOptions, new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, s_Styles.spriteAlignment); + +// // if (m_Alignment.intValue == (int)SpriteAlignment.Custom) +// // { +// // GUILayout.BeginHorizontal(); +// // EditorGUILayout.PropertyField(m_SpritePivot, new GUIContent()); +// // GUILayout.EndHorizontal(); +// // } +// // } +// //} +// } +// } + +// public class TextureWrapSettingsGUI +// { +// public SerializedProperty wrapMode; +// public SerializedProperty wrapModeU; +// public SerializedProperty wrapModeV; +// public SerializedProperty wrapModeW; + +// public TextureWrapSettingsGUI(SerializedProperty sp) +// { +// wrapMode = sp.FindPropertyRelative("m_WrapMode"); +// wrapModeU = sp.FindPropertyRelative("m_WrapModeU"); +// wrapModeV = sp.FindPropertyRelative("m_WrapModeV"); +// wrapModeW = sp.FindPropertyRelative("m_WrapModeW"); +// } + +// public void OnInspectorGUI() +// { + +// } +// } + + +// public class TextureAlphaSettingsGUI +// { +// public SerializedProperty tolerance; +// public SerializedProperty source; + +// public TextureAlphaSettingsGUI(SerializedProperty sp) +// { +// tolerance = sp.FindPropertyRelative("m_AlphaTolerance"); +// source = sp.FindPropertyRelative("m_AlphaSource"); +// } + +// public void OnInspectorGUI() +// { + +// } +// } + +// public class TextureMipmapSettingsGUI +// { +// public SerializedProperty filter; +// public SerializedProperty borderMipmap; +// public SerializedProperty fadeout; +// public SerializedProperty preserveCoverage; +// public SerializedProperty fadeDistanceStart; +// public SerializedProperty fadeDistanceEnd; + +// public TextureMipmapSettingsGUI(SerializedProperty sp) +// { +// filter = sp.FindPropertyRelative("m_Filter"); +// borderMipmap = sp.FindPropertyRelative("m_BorderMipmap"); +// fadeout = sp.FindPropertyRelative("m_Fadeout"); +// preserveCoverage = sp.FindPropertyRelative("m_PreserveCoverage"); +// fadeDistanceStart = sp.FindPropertyRelative("m_FadeDistanceStart"); +// fadeDistanceEnd = sp.FindPropertyRelative("m_FadeDistanceEnd"); +// } + +// public void OnInspectorGUI() +// { + +// } +// } + +// public class TextureNormalSettingsGUI +// { +// public SerializedProperty filter; +// public SerializedProperty generateFromGrayScale; +// public SerializedProperty bumpiness; + +// public TextureNormalSettingsGUI(SerializedProperty sp) +// { +// filter = sp.FindPropertyRelative("m_Filter"); +// generateFromGrayScale = sp.FindPropertyRelative("m_GenerateFromGrayScale"); +// bumpiness = sp.FindPropertyRelative("m_Bumpiness"); +// } + +// public void OnInspectorGUI() +// { + +// } +// } + + +// public class TextureCubemapSettingsGUI +// { +// public SerializedProperty convolution; +// public SerializedProperty mode; +// public SerializedProperty seamless; + +// public TextureCubemapSettingsGUI(SerializedProperty sp) +// { +// convolution = sp.FindPropertyRelative("m_Convolution"); +// mode = sp.FindPropertyRelative("m_Mode"); +// seamless = sp.FindPropertyRelative("m_Seamless"); +// } + +// public void OnInspectorGUI() +// { + +// } +// } + + +// static class TextureSettingsGUIUtils +// { +// public static void ToggleFromInt(SerializedProperty property, GUIContent label) +// { +// EditorGUI.BeginChangeCheck(); +// EditorGUI.showMixedValue = property.hasMultipleDifferentValues; +// int value = EditorGUILayout.Toggle(label, property.intValue > 0) ? 1 : 0; +// EditorGUI.showMixedValue = false; +// if (EditorGUI.EndChangeCheck()) +// property.intValue = value; +// } + +// public static void EnumPopup(SerializedProperty property, System.Type type, GUIContent label) +// { +// EditorGUILayout.IntPopup(label.text, property.intValue, +// System.Enum.GetNames(type), +// System.Enum.GetValues(type) as int[]); +// } + +// internal class Styles +// { +// public readonly GUIContent textureTypeTitle = new GUIContent("Texture Type", "What will this texture be used for?"); +// public readonly GUIContent[] textureTypeOptions = +// { +// new GUIContent("Default", "Texture is a normal image such as a diffuse texture or other."), +// new GUIContent("Sprite (2D and UI)", "Texture is used for a sprite."), +// }; +// public readonly int[] textureTypeValues = +// { +// (int)TextureImporterType.Default, +// (int)TextureImporterType.Sprite, +// }; + +// public readonly GUIContent textureShape = new GUIContent("Texture Shape", "What shape is this texture?"); +// private readonly GUIContent textureShape2D = new GUIContent("2D, Texture is 2D."); +// private readonly GUIContent textureShapeCube = new GUIContent("Cube", "Texture is a Cubemap."); +// public readonly Dictionary textureShapeOptionsDictionnary = new Dictionary(); +// public readonly Dictionary textureShapeValuesDictionnary = new Dictionary(); + + +// public readonly GUIContent filterMode = new GUIContent("Filter Mode"); +// public readonly GUIContent[] filterModeOptions = +// { +// new GUIContent("Point (no filter)"), +// new GUIContent("Bilinear"), +// new GUIContent("Trilinear") +// }; + +// public readonly GUIContent textureFormat = new GUIContent("Format"); + +// public readonly GUIContent defaultPlatform = new GUIContent("Default"); +// public readonly GUIContent mipmapFadeOutToggle = new GUIContent("Fadeout Mip Maps"); +// public readonly GUIContent mipmapFadeOut = new GUIContent("Fade Range"); +// public readonly GUIContent readWrite = new GUIContent("Read/Write Enabled", "Enable to be able to access the raw pixel data from code."); + +// public readonly GUIContent alphaSource = new GUIContent("Alpha Source", "How is the alpha generated for the imported texture."); +// public readonly GUIContent[] alphaSourceOptions = +// { +// new GUIContent("None", "No Alpha will be used."), +// new GUIContent("Input Texture Alpha", "Use Alpha from the input texture if one is provided."), +// new GUIContent("From Gray Scale", "Generate Alpha from image gray scale."), +// }; +// public readonly int[] alphaSourceValues = +// { +// (int)TextureImporterAlphaSource.None, +// (int)TextureImporterAlphaSource.FromInput, +// (int)TextureImporterAlphaSource.FromGrayScale, +// }; + +// public readonly GUIContent generateMipMaps = new GUIContent("Generate Mip Maps"); +// public readonly GUIContent sRGBTexture = new GUIContent("sRGB (Color Texture)", "Texture content is stored in gamma space. Non-HDR color textures should enable this flag (except if used for IMGUI)."); +// public readonly GUIContent borderMipMaps = new GUIContent("Border Mip Maps"); +// public readonly GUIContent mipMapsPreserveCoverage = new GUIContent("Mip Maps Preserve Coverage", "The alpha channel of generated Mip Maps will preserve coverage during the alpha test."); +// public readonly GUIContent alphaTestReferenceValue = new GUIContent("Alpha Cutoff Value", "The reference value used during the alpha test. Controls Mip Map coverage."); +// public readonly GUIContent mipMapFilter = new GUIContent("Mip Map Filtering"); +// public readonly GUIContent[] mipMapFilterOptions = +// { +// new GUIContent("Box"), +// new GUIContent("Kaiser"), +// }; +// public readonly GUIContent npot = new GUIContent("Non Power of 2", "How non-power-of-two textures are scaled on import."); + +// public readonly GUIContent compressionQuality = new GUIContent("Compressor Quality"); +// public readonly GUIContent compressionQualitySlider = new GUIContent("Compressor Quality", "Use the slider to adjust compression quality from 0 (Fastest) to 100 (Best)"); +// public readonly GUIContent[] mobileCompressionQualityOptions = +// { +// new GUIContent("Fast"), +// new GUIContent("Normal"), +// new GUIContent("Best") +// }; + +// public readonly GUIContent spriteMode = new GUIContent("Sprite Mode"); +// public readonly GUIContent[] spriteModeOptions = +// { +// new GUIContent("Single"), +// new GUIContent("Multiple"), +// new GUIContent("Polygon"), +// }; +// public readonly GUIContent[] spriteMeshTypeOptions = +// { +// new GUIContent("Full Rect"), +// new GUIContent("Tight"), +// }; + +// public readonly GUIContent spritePackingTag = new GUIContent("Packing Tag", "Tag for the Sprite Packing system."); +// public readonly GUIContent spritePixelsPerUnit = new GUIContent("Pixels Per Unit", "How many pixels in the sprite correspond to one unit in the world."); +// public readonly GUIContent spriteExtrude = new GUIContent("Extrude Edges", "How much empty area to leave around the sprite in the generated mesh."); +// public readonly GUIContent spriteMeshType = new GUIContent("Mesh Type", "Type of sprite mesh to generate."); +// public readonly GUIContent spriteAlignment = new GUIContent("Pivot", "Sprite pivot point in its localspace. May be used for syncing animation frames of different sizes."); +// public readonly GUIContent[] spriteAlignmentOptions = +// { +// new GUIContent("Center"), +// new GUIContent("Top Left"), +// new GUIContent("Top"), +// new GUIContent("Top Right"), +// new GUIContent("Left"), +// new GUIContent("Right"), +// new GUIContent("Bottom Left"), +// new GUIContent("Bottom"), +// new GUIContent("Bottom Right"), +// new GUIContent("Custom"), +// }; + +// public readonly GUIContent alphaIsTransparency = new GUIContent("Alpha Is Transparency", "If the provided alpha channel is transparency, enable this to pre-filter the color to avoid texture filtering artifacts. This is not supported for HDR textures."); +// public readonly GUIContent etc1Compression = new GUIContent("Compress using ETC1 (split alpha channel)|Alpha for this texture will be preserved by splitting the alpha channel to another texture, and both resulting textures will be compressed using ETC1."); + +// public readonly GUIContent crunchedCompression = new GUIContent("Use Crunch Compression", "Texture is crunch-compressed to save space on disk when applicable."); + +// public readonly GUIContent showAdvanced = new GUIContent("Advanced", "Show advanced settings."); + +// public Styles() +// { +// // This is far from ideal, but it's better than having tons of logic in the GUI code itself. +// // The combination should not grow too much anyway since only Texture3D will be added later. +// GUIContent[] s2D_Options = { textureShape2D }; +// GUIContent[] sCube_Options = { textureShapeCube }; +// GUIContent[] s2D_Cube_Options = { textureShape2D, textureShapeCube }; +// textureShapeOptionsDictionnary.Add(TextureImporterShape.Texture2D, s2D_Options); +// textureShapeOptionsDictionnary.Add(TextureImporterShape.TextureCube, sCube_Options); +// textureShapeOptionsDictionnary.Add(TextureImporterShape.Texture2D | TextureImporterShape.TextureCube, s2D_Cube_Options); + +// int[] s2D_Values = { (int)TextureImporterShape.Texture2D }; +// int[] sCube_Values = { (int)TextureImporterShape.TextureCube }; +// int[] s2D_Cube_Values = { (int)TextureImporterShape.Texture2D, (int)TextureImporterShape.TextureCube }; +// textureShapeValuesDictionnary.Add(TextureImporterShape.Texture2D, s2D_Values); +// textureShapeValuesDictionnary.Add(TextureImporterShape.TextureCube, sCube_Values); +// textureShapeValuesDictionnary.Add(TextureImporterShape.Texture2D | TextureImporterShape.TextureCube, s2D_Cube_Values); + +// } +// } + +// internal static Styles s_Styles; +// } +//} diff --git a/Editor/TextureSettingsGUI.cs.meta b/Editor/TextureSettingsGUI.cs.meta index 8edd893..a5df299 100644 --- a/Editor/TextureSettingsGUI.cs.meta +++ b/Editor/TextureSettingsGUI.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 5fb78a2b3c5f4dc4394919dd6de6322b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 5fb78a2b3c5f4dc4394919dd6de6322b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Unity.2D.Psdimporter.Editor.asmdef b/Editor/Unity.2D.Psdimporter.Editor.asmdef index 7be878c..595e8b8 100644 --- a/Editor/Unity.2D.Psdimporter.Editor.asmdef +++ b/Editor/Unity.2D.Psdimporter.Editor.asmdef @@ -1,22 +1,22 @@ -{ - "name": "Unity.2D.Psdimporter.Editor", - "references": [ - "PsdPlugin", - "Unity.InternalAPIEditorBridge.001", - "Unity.2D.Common.Editor", - "Unity.2D.Animation.Editor", - "Unity.2D.Animation.Runtime", - "Unity.2D.Sprite.Editor" - ], - "optionalUnityReferences": [], - "includePlatforms": [ - "Editor" - ], - "excludePlatforms": [], - "allowUnsafeCode": true, - "overrideReferences": false, - "precompiledReferences": [], - "autoReferenced": true, - "defineConstraints": [], - "versionDefines": [] +{ + "name": "Unity.2D.Psdimporter.Editor", + "references": [ + "PsdPlugin", + "Unity.InternalAPIEditorBridge.001", + "Unity.2D.Common.Editor", + "Unity.2D.Animation.Editor", + "Unity.2D.Animation.Runtime", + "Unity.2D.Sprite.Editor" + ], + "optionalUnityReferences": [], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": true, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [] } \ No newline at end of file diff --git a/Editor/Unity.2D.Psdimporter.Editor.asmdef.meta b/Editor/Unity.2D.Psdimporter.Editor.asmdef.meta index 140311e..8de13e1 100644 --- a/Editor/Unity.2D.Psdimporter.Editor.asmdef.meta +++ b/Editor/Unity.2D.Psdimporter.Editor.asmdef.meta @@ -1,7 +1,7 @@ -fileFormatVersion: 2 -guid: bcb706ca0f6dd48449aa27a93faa899c -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: bcb706ca0f6dd48449aa27a93faa899c +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/LICENSE.md b/LICENSE.md index b7dcc43..9136b8d 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,29 +1,29 @@ -com.unity.2d.psdimporter copyright © 2020 Unity Technologies ApS - -Unity hereby grants to you a worldwide, non-exclusive, no-charge, and royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute the software that is made available with this License ("**_Software_**"), subject to the following terms and conditions: - -1. *Unity Companion Use Only*. Exercise of the license granted herein is limited to exercise for the creation, use, and/or distribution of applications, software, or other content pursuant to a valid Unity development engine software license ("**_Engine License_**"). That means while use of the Software is not limited to use in the software licensed under the Engine License, the Software may not be used for any purpose other than the creation, use, and/or distribution of Engine License-dependent applications, software, or other content. No other exercise of the license granted herein is permitted. - -1. *No Modification of Engine License*. Neither this License nor any exercise of the license granted herein modifies the Engine License in any way. - -1. *Ownership & Grant Back to You*. - - 3.1. You own your content. In this License, "derivative works" means derivatives of the Software itself--works derived only from the Software by you under this License (for example, modifying the code of the Software itself to improve its efficacy); “derivative works” of the Software do not include, for example, games, apps, or content that you create using the Software. You keep all right, title, and interest to your own content. - - 3.2. Unity owns its content. While you keep all right, title, and interest to your own content per the above, as between Unity and you, Unity will own all right, title, and interest to all intellectual property rights (including patent, trademark, and copyright) in the Software and derivative works of the Software, and you hereby assign and agree to assign all such rights in those derivative works to Unity. - - 3.3. You have a license to those derivative works. Subject to this License, Unity grants to you the same worldwide, non-exclusive, no-charge, and royalty-free copyright license to derivative works of the Software you create as is granted to you for the Software under this License. - -1. *Trademarks*. You are not granted any right or license under this License to use any trademarks, service marks, trade names, products names, or branding of Unity or its affiliates ("**_Trademarks_**"). Descriptive uses of Trademarks are permitted; see, for example, Unity’s Branding Usage Guidelines at [https://unity3d.com/public-relations/brand](https://unity3d.com/public-relations/brand). - -1. *Notices & Third-Party Rights*. This License, including the copyright notice above, must be provided in all substantial portions of the Software and derivative works thereof (or, if that is impracticable, in any other location where such notices are customarily placed). Further, if the Software is accompanied by a Unity "third-party notices" or similar file, you acknowledge and agree that software identified in that file is governed by those separate license terms. - -1. *DISCLAIMER, LIMITATION OF LIABILITY*. THE SOFTWARE AND ANY DERIVATIVE WORKS THEREOF IS PROVIDED ON AN "AS IS" BASIS, AND IS PROVIDED WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND/OR NONINFRINGEMENT. IN NO EVENT SHALL ANY COPYRIGHT HOLDER OR AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES (WHETHER DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL, INCLUDING PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF USE, DATA, OR PROFITS, AND BUSINESS INTERRUPTION), OR OTHER LIABILITY WHATSOEVER, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM OR OUT OF, OR IN CONNECTION WITH, THE SOFTWARE OR ANY DERIVATIVE WORKS THEREOF OR THE USE OF OR OTHER DEALINGS IN SAME, EVEN WHERE ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -1. *USE IS ACCEPTANCE and License Versions*. Your receipt and use of the Software constitutes your acceptance of this License and its terms and conditions. Software released by Unity under this License may be modified or updated and the License with it; upon any such modification or update, you will comply with the terms of the updated License for any use of any of the Software under the updated License. - -1. *Use in Compliance with Law and Termination*. Your exercise of the license granted herein will at all times be in compliance with applicable law and will not infringe any proprietary rights (including intellectual property rights); this License will terminate immediately on any breach by you of this License. - -1. *Severability*. If any provision of this License is held to be unenforceable or invalid, that provision will be enforced to the maximum extent possible and the other provisions will remain in full force and effect. - +com.unity.2d.psdimporter copyright © 2020 Unity Technologies ApS + +Unity hereby grants to you a worldwide, non-exclusive, no-charge, and royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute the software that is made available with this License ("**_Software_**"), subject to the following terms and conditions: + +1. *Unity Companion Use Only*. Exercise of the license granted herein is limited to exercise for the creation, use, and/or distribution of applications, software, or other content pursuant to a valid Unity development engine software license ("**_Engine License_**"). That means while use of the Software is not limited to use in the software licensed under the Engine License, the Software may not be used for any purpose other than the creation, use, and/or distribution of Engine License-dependent applications, software, or other content. No other exercise of the license granted herein is permitted. + +1. *No Modification of Engine License*. Neither this License nor any exercise of the license granted herein modifies the Engine License in any way. + +1. *Ownership & Grant Back to You*. + + 3.1. You own your content. In this License, "derivative works" means derivatives of the Software itself--works derived only from the Software by you under this License (for example, modifying the code of the Software itself to improve its efficacy); “derivative works” of the Software do not include, for example, games, apps, or content that you create using the Software. You keep all right, title, and interest to your own content. + + 3.2. Unity owns its content. While you keep all right, title, and interest to your own content per the above, as between Unity and you, Unity will own all right, title, and interest to all intellectual property rights (including patent, trademark, and copyright) in the Software and derivative works of the Software, and you hereby assign and agree to assign all such rights in those derivative works to Unity. + + 3.3. You have a license to those derivative works. Subject to this License, Unity grants to you the same worldwide, non-exclusive, no-charge, and royalty-free copyright license to derivative works of the Software you create as is granted to you for the Software under this License. + +1. *Trademarks*. You are not granted any right or license under this License to use any trademarks, service marks, trade names, products names, or branding of Unity or its affiliates ("**_Trademarks_**"). Descriptive uses of Trademarks are permitted; see, for example, Unity’s Branding Usage Guidelines at [https://unity3d.com/public-relations/brand](https://unity3d.com/public-relations/brand). + +1. *Notices & Third-Party Rights*. This License, including the copyright notice above, must be provided in all substantial portions of the Software and derivative works thereof (or, if that is impracticable, in any other location where such notices are customarily placed). Further, if the Software is accompanied by a Unity "third-party notices" or similar file, you acknowledge and agree that software identified in that file is governed by those separate license terms. + +1. *DISCLAIMER, LIMITATION OF LIABILITY*. THE SOFTWARE AND ANY DERIVATIVE WORKS THEREOF IS PROVIDED ON AN "AS IS" BASIS, AND IS PROVIDED WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND/OR NONINFRINGEMENT. IN NO EVENT SHALL ANY COPYRIGHT HOLDER OR AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES (WHETHER DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL, INCLUDING PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF USE, DATA, OR PROFITS, AND BUSINESS INTERRUPTION), OR OTHER LIABILITY WHATSOEVER, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM OR OUT OF, OR IN CONNECTION WITH, THE SOFTWARE OR ANY DERIVATIVE WORKS THEREOF OR THE USE OF OR OTHER DEALINGS IN SAME, EVEN WHERE ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +1. *USE IS ACCEPTANCE and License Versions*. Your receipt and use of the Software constitutes your acceptance of this License and its terms and conditions. Software released by Unity under this License may be modified or updated and the License with it; upon any such modification or update, you will comply with the terms of the updated License for any use of any of the Software under the updated License. + +1. *Use in Compliance with Law and Termination*. Your exercise of the license granted herein will at all times be in compliance with applicable law and will not infringe any proprietary rights (including intellectual property rights); this License will terminate immediately on any breach by you of this License. + +1. *Severability*. If any provision of this License is held to be unenforceable or invalid, that provision will be enforced to the maximum extent possible and the other provisions will remain in full force and effect. + 1. *Governing Law and Venue*. This License is governed by and construed in accordance with the laws of Denmark, except for its conflict of laws rules; the United Nations Convention on Contracts for the International Sale of Goods will not apply. If you reside (or your principal place of business is) within the United States, you and Unity agree to submit to the personal and exclusive jurisdiction of and venue in the state and federal courts located in San Francisco County, California concerning any dispute arising out of this License ("**_Dispute_**"). If you reside (or your principal place of business is) outside the United States, you and Unity agree to submit to the personal and exclusive jurisdiction of and venue in the courts located in Copenhagen, Denmark concerning any Dispute. \ No newline at end of file diff --git a/LICENSE.md.meta b/LICENSE.md.meta index c7a5682..3a201dc 100644 --- a/LICENSE.md.meta +++ b/LICENSE.md.meta @@ -1,7 +1,7 @@ -fileFormatVersion: 2 -guid: 9ede9ea0212487346a6005ee7f37db0d -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 9ede9ea0212487346a6005ee7f37db0d +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/README.md b/README.md index d0de79c..243822b 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -PSB Importer - -ScriptedImporter to import Adobe Photoshop PSB file format - -Feature -- Generate texture and sprite by mosaicing layers -- Option to generate Prefab to reconstuct the image from generated Sprites -- Option to import hidden layers - +PSB Importer + +ScriptedImporter to import Adobe Photoshop PSB file format + +Feature +- Generate texture and sprite by mosaicing layers +- Option to generate Prefab to reconstuct the image from generated Sprites +- Option to import hidden layers + diff --git a/README.md.meta b/README.md.meta index 3b5ed8d..4d318ab 100644 --- a/README.md.meta +++ b/README.md.meta @@ -1,7 +1,7 @@ -fileFormatVersion: 2 -guid: bacef98d5d5167242a24ec99d7304aad -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: bacef98d5d5167242a24ec99d7304aad +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests.meta b/Tests.meta index 06d5e9b..8fcec38 100644 --- a/Tests.meta +++ b/Tests.meta @@ -1,10 +1,10 @@ -fileFormatVersion: 2 -guid: ef286a7cdaafc8141b7eaa37314b76cf -folderAsset: yes -timeCreated: 1504008884 -licenseType: Pro -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: ef286a7cdaafc8141b7eaa37314b76cf +folderAsset: yes +timeCreated: 1504008884 +licenseType: Pro +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/EditorTests.meta b/Tests/EditorTests.meta index 1eef6b7..f41aa6e 100644 --- a/Tests/EditorTests.meta +++ b/Tests/EditorTests.meta @@ -1,8 +1,8 @@ -fileFormatVersion: 2 -guid: 53e6b81c6627ce5469c38700ebbd32a7 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 53e6b81c6627ce5469c38700ebbd32a7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/EditorTests/PlaceholderTests.cs b/Tests/EditorTests/PlaceholderTests.cs index f41db98..eb98eee 100644 --- a/Tests/EditorTests/PlaceholderTests.cs +++ b/Tests/EditorTests/PlaceholderTests.cs @@ -1,14 +1,14 @@ -using NUnit.Framework; - -namespace UnityEditor.Experimental.U2D.PSDImporter.Tests -{ - internal class Placeholder - { - [Test] - public void PlaceHolderTest() - { - // Use the Assert class to test conditions. - Assert.Pass("This is a placeholder to ensure we have at least one test."); - } - } -} +using NUnit.Framework; + +namespace UnityEditor.Experimental.U2D.PSDImporter.Tests +{ + internal class Placeholder + { + [Test] + public void PlaceHolderTest() + { + // Use the Assert class to test conditions. + Assert.Pass("This is a placeholder to ensure we have at least one test."); + } + } +} diff --git a/Tests/EditorTests/PlaceholderTests.cs.meta b/Tests/EditorTests/PlaceholderTests.cs.meta index ba22654..4b56790 100644 --- a/Tests/EditorTests/PlaceholderTests.cs.meta +++ b/Tests/EditorTests/PlaceholderTests.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: e02c5dbafeee6ae488b1efd88793f456 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: e02c5dbafeee6ae488b1efd88793f456 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/EditorTests/Unity.2D.Psdimporter.EditorTests.asmdef b/Tests/EditorTests/Unity.2D.Psdimporter.EditorTests.asmdef index a604ca8..a856722 100644 --- a/Tests/EditorTests/Unity.2D.Psdimporter.EditorTests.asmdef +++ b/Tests/EditorTests/Unity.2D.Psdimporter.EditorTests.asmdef @@ -1,25 +1,25 @@ -{ - "name": "Unity.2D.Psdimporter.EditorTests", - "references": [ - "Unity.2D.Common.Editor", - "Unity.2D.Psdimporter.Editor", - "Unity.2D.Animation.Editor", - "Unity.2D.Animation.Runtime", - "Unity.2D.Sprite.Editor" - ], - "optionalUnityReferences": [ - "TestAssemblies" - ], - "includePlatforms": [ - "Editor" - ], - "excludePlatforms": [], - "allowUnsafeCode": false, - "overrideReferences": false, - "precompiledReferences": [], - "autoReferenced": true, - "defineConstraints": [ - "UNITY_INCLUDE_TESTS" - ], - "versionDefines": [] +{ + "name": "Unity.2D.Psdimporter.EditorTests", + "references": [ + "Unity.2D.Common.Editor", + "Unity.2D.Psdimporter.Editor", + "Unity.2D.Animation.Editor", + "Unity.2D.Animation.Runtime", + "Unity.2D.Sprite.Editor" + ], + "optionalUnityReferences": [ + "TestAssemblies" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [ + "UNITY_INCLUDE_TESTS" + ], + "versionDefines": [] } \ No newline at end of file diff --git a/Tests/EditorTests/Unity.2D.Psdimporter.EditorTests.asmdef.meta b/Tests/EditorTests/Unity.2D.Psdimporter.EditorTests.asmdef.meta index 59a0137..0f7ec2f 100644 --- a/Tests/EditorTests/Unity.2D.Psdimporter.EditorTests.asmdef.meta +++ b/Tests/EditorTests/Unity.2D.Psdimporter.EditorTests.asmdef.meta @@ -1,7 +1,7 @@ -fileFormatVersion: 2 -guid: 782c623a3cbd6d940be3a3bcf0d4604b -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 782c623a3cbd6d940be3a3bcf0d4604b +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Third Party Notices.md b/Third Party Notices.md index 765a311..97f84e7 100644 --- a/Third Party Notices.md +++ b/Third Party Notices.md @@ -1,72 +1,72 @@ -This package contains third-party software components governed by the license(s) indicated below: ---------- - -Component Name: Photoshop PSD FileType Plugin for Paint.NET - -License Type: MIT, BSD - -///////////////////////////////////////////////////////////////////////////////// - -Photoshop PSD FileType Plugin for Paint.NET -http://psdplugin.codeplex.com/ - -Copyright (c) 2006-2007 Frank Blumenberg -Copyright (c) 2010-2016 Tao Yue - -MIT License: http://www.opensource.org/licenses/mit-license.php - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -///////////////////////////////////////////////////////////////////////////////// - -Portions of the software have been adapted from Yet Another PSD Parser: - http://www.codeproject.com/KB/graphics/PSDParser.aspx - -These portions are provided under the BSD License: - http://www.opensource.org/licenses/BSD-3-Clause - ----- - -Copyright (c) 2006, Jonas Beckeman -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of Jonas Beckeman nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY JONAS BECKEMAN AND CONTRIBUTORS ``AS IS'' AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL JONAS BECKEMAN AND CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -///////////////////////////////////////////////////////////////////////////////// +This package contains third-party software components governed by the license(s) indicated below: +--------- + +Component Name: Photoshop PSD FileType Plugin for Paint.NET + +License Type: MIT, BSD + +///////////////////////////////////////////////////////////////////////////////// + +Photoshop PSD FileType Plugin for Paint.NET +http://psdplugin.codeplex.com/ + +Copyright (c) 2006-2007 Frank Blumenberg +Copyright (c) 2010-2016 Tao Yue + +MIT License: http://www.opensource.org/licenses/mit-license.php + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +///////////////////////////////////////////////////////////////////////////////// + +Portions of the software have been adapted from Yet Another PSD Parser: + http://www.codeproject.com/KB/graphics/PSDParser.aspx + +These portions are provided under the BSD License: + http://www.opensource.org/licenses/BSD-3-Clause + +---- + +Copyright (c) 2006, Jonas Beckeman +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Jonas Beckeman nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY JONAS BECKEMAN AND CONTRIBUTORS ``AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL JONAS BECKEMAN AND CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +///////////////////////////////////////////////////////////////////////////////// diff --git a/Third Party Notices.md.meta b/Third Party Notices.md.meta index 3094c4d..f3be39e 100644 --- a/Third Party Notices.md.meta +++ b/Third Party Notices.md.meta @@ -1,7 +1,7 @@ -fileFormatVersion: 2 -guid: 9a0bf89d9a6d719479a816944f579291 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 9a0bf89d9a6d719479a816944f579291 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/package.json b/package.json index 3136e85..aaf699b 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "com.unity.2d.psdimporter", - "version": "3.1.4", - "unity": "2020.1", - "unityRelease": "0a10", + "version": "4.0.0", + "unity": "2020.2", + "unityRelease": "0a14", "displayName": "2D PSD Importer", "description": "A ScriptedImporter for importing Adobe Photoshop PSB (Photoshop Big) file format. The ScriptedImporter is currently targeted for users who wants to create multi Sprite character animation using Unity 2D Animation Package.", "keywords": [ @@ -12,19 +12,19 @@ ], "category": "2D", "dependencies": { - "com.unity.2d.common": "3.0.0", - "com.unity.2d.animation": "4.2.2", + "com.unity.2d.common": "4.0.0", + "com.unity.2d.animation": "5.0.0", "com.unity.2d.sprite": "1.0.0" }, "relatedPackages": { - "com.unity.2d.psdimporter.tests": "3.1.4" + "com.unity.2d.psdimporter.tests": "4.0.0" }, "upmCi": { - "footprint": "0f31bea79298fdd3aa5228cc6f288ac7de11395a" + "footprint": "d2b08e5f1725cfeb59cd2f03f5c922d7f5579ed5" }, "repository": { - "type": "git", "url": "https://github.cds.internal.unity3d.com/unity/2d.git", - "revision": "43ebcd28b387c0a52efed484cb7d9242b9d7cf6f" + "type": "git", + "revision": "4651ccecac488987a6b5bbb033282cb61de0e007" } } diff --git a/package.json.meta b/package.json.meta index e480932..ba1d0b6 100644 --- a/package.json.meta +++ b/package.json.meta @@ -1,7 +1,7 @@ -fileFormatVersion: 2 -guid: 2f948ecb81c850949a2725b1ba265844 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 2f948ecb81c850949a2725b1ba265844 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: