/// <summary> /// Store layer metadata and image data. /// </summary> public static void StoreLayer(BitmapLayer layer, PhotoshopFile.Layer psdLayer, PsdSaveConfigToken psdToken) { // Set layer metadata psdLayer.Name = layer.Name; psdLayer.Rect = FindImageRectangle(layer.Surface); psdLayer.BlendModeKey = PsdBlendMode.Normal; psdLayer.Opacity = layer.Opacity; psdLayer.Visible = layer.Visible; psdLayer.Masks = new MaskInfo(); psdLayer.BlendingRangesData = new BlendingRanges(psdLayer); // Store channel metadata int layerSize = psdLayer.Rect.Width * psdLayer.Rect.Height; for (int i = -1; i < 3; i++) { var ch = new Channel((short)i, psdLayer); ch.ImageCompression = psdToken.RleCompress ? ImageCompression.Rle : ImageCompression.Raw; ch.ImageData = new byte[layerSize]; psdLayer.Channels.Add(ch); } // Store and compress channel image data var channelsArray = psdLayer.Channels.ToIdArray(); StoreLayerImage(channelsArray, psdLayer.AlphaChannel, layer.Surface, psdLayer.Rect); }
public Mask(Layer layer, Rectangle rect, byte color, BitVector32 flags) { Layer = layer; Rect = rect; BackgroundColor = color; this.flags = flags; }
/// <summary> /// Initializes a new instance of the <see cref="Mask"/> class. /// </summary> /// <param name="reader">The reader to use to initialize the instance.</param> /// <param name="layer">The layer this mask belongs to.</param> internal Mask(BinaryReverseReader reader, Layer layer) { Layer = layer; uint num1 = reader.ReadUInt32(); if (num1 <= 0U) { return; } long position = reader.BaseStream.Position; rect = new Rect(); rect.y = reader.ReadInt32(); rect.x = reader.ReadInt32(); rect.height = reader.ReadInt32() - rect.y; rect.width = reader.ReadInt32() - rect.x; DefaultColor = reader.ReadByte(); flags = new BitVector32(reader.ReadByte()); if ((int)num1 == 36) { reader.ReadByte(); // bit vector reader.ReadByte(); // ??? reader.ReadInt32(); // rect Y reader.ReadInt32(); // rect X reader.ReadInt32(); // rect total height (actual height = this - Y) reader.ReadInt32(); // rect total width (actual width = this - Y) } reader.BaseStream.Position = position + num1; }
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 <byte>(alphaSize, Allocator.TempJob); if (HasAlphaChannel > 0) { NativeArray <byte> .Copy(layer.AlphaChannel.ImageData, AlphaChannel, layer.AlphaChannel.ImageData.Length); } ColorMode = layer.PsdFile.ColorMode; ColorModeData = new NativeArray <byte>(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); } }
private ComposeLayerDelegate BuildModifyLayerCallback(NameValueCollection queryString) { PsdCommandSearcher searcher = new PsdCommandSearcher(new PsdCommandBuilder(queryString)); return(delegate(Graphics g, Bitmap b, object layer) { PhotoshopFile.Layer l = (PhotoshopFile.Layer)layer; //See if this layer is supposed to be re-colored. Nullable <Color> color = searcher.getColor(l.Name); if (b == null && l.Rect.X == 0 && l.Rect.Y == 0 && l.Rect.Width == 0 && l.Rect.Height == 0) { return; //This layer has no size, it is probably a layer group. } //See if we need to re-draw this text layer Nullable <bool> redraw = searcher.getRedraw(l.Name); if (redraw != null && redraw == true) { //Verify it has text layer information: bool hasText = false; foreach (PhotoshopFile.Layer.AdjustmentLayerInfo lInfo in l.AdjustmentInfo) { if (lInfo.Key.Equals("TySh", StringComparison.Ordinal)) { hasText = true; break; } } if (hasText) { //Re-draw the text directly, ignoring the bitmap var tlr = new TextLayerRenderer(l); tlr.IgnoreMissingFonts = !isStrictMode(); tlr.Render(g, color, searcher.getReplacementText(l.Name)); return; } } if (b == null && !isStrictMode()) { return; //Skip drawing layers that have no bitmap data. } if (b == null) { throw new Exception("No bitmap data found for layer " + l.Name); } //Draw the existing bitmap //Blend color into bitmap if (color != null) { ColorBitmap(b, color.Value); } //Draw image g.DrawImage(b, l.Rect); }); }
public LoadLayerContext(PhotoshopFile.Layer psdLayer, Document document, UserBlendOp blendOp, List <Layer> layersList, int idxLayersList) { this.psdLayer = psdLayer; this.document = document; this.blendOp = blendOp; this.layersList = layersList; this.idxLayersList = idxLayersList; }
/////////////////////////////////////////////////////////////////////////// public PsdFile() { Version = 1; BaseLayer = new Layer(this); ImageResources = new ImageResources(); Layers = new List<Layer>(); AdditionalInfo = new List<LayerInfo>(); }
public override void OnLoadLayerHeader(PhotoshopFile.Layer layer) { var psdFile = layer.PsdFile; if (psdFile.ColorMode == PsdColorMode.Multichannel) { PsdLoad.CheckSufficientMemory(psdFile); } }
public SaveLayerPixelsContext(BitmapLayer layer, PsdFile psdFile, Document input, PhotoshopFile.Layer psdLayer, PsdSaveConfigToken psdToken) { this.layer = layer; this.psdFile = psdFile; this.input = input; this.psdToken = psdToken; this.psdLayer = psdLayer; }
/// <summary> /// Store layer metadata and image data. /// </summary> public static void StoreLayer( BitmapLayerInfo layerInfo, PhotoshopFile.Layer psdLayer, PsdSaveConfigToken psdToken) { var layer = layerInfo.Layer; // Set layer metadata psdLayer.Name = layerInfo.Name; psdLayer.Rect = FindImageRectangle(layer.Surface); psdLayer.Opacity = layer.Opacity; psdLayer.Masks = new MaskInfo(); psdLayer.BlendingRangesData = new BlendingRanges(psdLayer); // Store channel metadata int layerSize = psdLayer.Rect.Width * psdLayer.Rect.Height; for (int i = -1; i < 3; i++) { var ch = new Channel((short)i, psdLayer); ch.ImageCompression = psdToken.RleCompress ? ImageCompression.Rle : ImageCompression.Raw; ch.ImageData = new byte[layerSize]; psdLayer.Channels.Add(ch); } psdLayer.BlendModeKey = layer.BlendMode.ToPsdBlendMode(); psdLayer.Visible = layer.Visible; // Create folders/groups before actual image data will be saved. if (psdToken.SaveLayers && !layerInfo.RenderAsRegularLayer) { if (layerInfo.IsGroupStart) { var status = layer.Visible ? LayerSectionType.OpenFolder : LayerSectionType.ClosedFolder; psdLayer.AdditionalInfo.Add(new LayerSectionInfo(status)); psdLayer.Name = layerInfo.Name; psdLayer.Visible = true; } else if (layerInfo.IsGroupEnd) { // End of the group psdLayer.Opacity = 255; psdLayer.BlendModeKey = PsdBlendMode.PassThrough; psdLayer.Name = "</Layer group>"; psdLayer.AdditionalInfo.Add(new LayerSectionInfo(LayerSectionType.SectionDivider)); } return; } // Store and compress channel image data var channelsArray = psdLayer.Channels.ToIdArray(); StoreLayerImage(channelsArray, psdLayer.AlphaChannel, layer.Surface, psdLayer.Rect); }
/////////////////////////////////////////////////////////////////////////// public BlendingRanges(PsdBinaryReader reader, Layer layer) { Debug.WriteLine("BlendingRanges started at " + reader.BaseStream.Position.ToString(CultureInfo.InvariantCulture)); Layer = layer; var dataLength = reader.ReadInt32(); if (dataLength <= 0) return; Data = reader.ReadBytes(dataLength); }
/////////////////////////////////////////////////////////////////////////// unsafe private static void SetPDNColor(ColorBgra* dstPixel, PhotoshopFile.Layer layer, PhotoshopFile.Layer.Channel[] channels, PhotoshopFile.Layer.Channel alphaChannel, int pos) { switch (layer.PsdFile.ColorMode) { case PsdFile.ColorModes.RGB: dstPixel->R = channels[0].ImageData[pos]; dstPixel->G = channels[1].ImageData[pos]; dstPixel->B = channels[2].ImageData[pos]; break; case PsdFile.ColorModes.CMYK: SetPDNColorCMYK(dstPixel, channels[0].ImageData[pos], channels[1].ImageData[pos], channels[2].ImageData[pos], channels[3].ImageData[pos]); break; case PsdFile.ColorModes.Multichannel: SetPDNColorCMYK(dstPixel, channels[0].ImageData[pos], channels[1].ImageData[pos], channels[2].ImageData[pos], 0); break; case PsdFile.ColorModes.Bitmap: byte bwValue = ImageDecoder.GetBitmapValue(channels[0].ImageData, pos); dstPixel->R = bwValue; dstPixel->G = bwValue; dstPixel->B = bwValue; break; case PsdFile.ColorModes.Grayscale: case PsdFile.ColorModes.Duotone: dstPixel->R = channels[0].ImageData[pos]; dstPixel->G = channels[0].ImageData[pos]; dstPixel->B = channels[0].ImageData[pos]; break; case PsdFile.ColorModes.Indexed: int index = (int)channels[0].ImageData[pos]; dstPixel->R = (byte)layer.PsdFile.ColorModeData[index]; dstPixel->G = layer.PsdFile.ColorModeData[index + 256]; dstPixel->B = layer.PsdFile.ColorModeData[index + 2 * 256]; break; case PsdFile.ColorModes.Lab: SetPDNColorLab(dstPixel, channels[0].ImageData[pos], channels[1].ImageData[pos], channels[2].ImageData[pos]); break; } }
/////////////////////////////////////////////////////////////////////////// public static BitmapLayer DecodeImage(PhotoshopFile.Layer psdLayer) { BitmapLayer pdnLayer = new BitmapLayer(psdLayer.PsdFile.Columns, psdLayer.PsdFile.Rows); Surface surface = pdnLayer.Surface; surface.Clear((ColorBgra)0); bool hasMaskChannel = psdLayer.SortedChannels.ContainsKey(-2); var channels = psdLayer.ChannelsArray; var alphaChannel = psdLayer.AlphaChannel; int yPsdLayerStart = Math.Max(0, -psdLayer.Rect.Y); int yPsdLayerEnd = Math.Min(psdLayer.Rect.Height, surface.Height - psdLayer.Rect.Y); for (int yPsdLayer = yPsdLayerStart; yPsdLayer < yPsdLayerEnd; yPsdLayer++) { unsafe { ColorBgra* dstRow = surface.GetRowAddress(yPsdLayer + psdLayer.Rect.Y); int xPsdLayerStart = Math.Max(0, -psdLayer.Rect.X); int xPsdLayerEnd = Math.Min(psdLayer.Rect.Width, psdLayer.PsdFile.Columns - psdLayer.Rect.Left); int xPsdLayerEndCopy = Math.Min(xPsdLayerEnd, surface.Width - psdLayer.Rect.X); int srcRowIndex = yPsdLayer * psdLayer.Rect.Width; int dstIndex = psdLayer.Rect.Left + xPsdLayerStart; ColorBgra* dstPixel = dstRow + dstIndex; for (int xPsdLayer = xPsdLayerStart; xPsdLayer < xPsdLayerEnd; xPsdLayer++) { if (xPsdLayer < xPsdLayerEndCopy) { int srcIndex = srcRowIndex + xPsdLayer; SetPDNColor(dstPixel, psdLayer, channels, alphaChannel, srcIndex); int maskAlpha = 255; if (hasMaskChannel) { maskAlpha = GetMaskAlpha(psdLayer.MaskData, xPsdLayer, yPsdLayer); } SetPDNAlpha(dstPixel, alphaChannel, srcIndex, maskAlpha); } dstPixel++; } } } return pdnLayer; }
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)); }
public PsdLayer(Layer layer, int index) { _name = layer.Name; _rect = layer.Rect; _visible = layer.Visible; _index = index; List<PhotoshopFile.Layer.AdjustmentLayerInfo> adjustments = layer.AdjustmentInfo; for (int j = 0; j < adjustments.Count; j++) { if (adjustments[j].Key.Equals("TySh")) { this._isTextLayer = true; } } }
/// <summary> /// Initializes a new instance of the <see cref="AdjustmentLayerInfo"/> class. /// </summary> /// <param name="reader">The reader containing the PSD file data</param> /// <param name="layer">The layer that this adjustment info belongs to</param> public AdjustmentLayerInfo(BinaryReverseReader reader, Layer layer) { if (new string(reader.ReadChars(4)) != "8BIM") { throw new IOException("Could not read an image resource"); } Key = new string(reader.ReadChars(4)); if (Key == "lfx2" || Key == "lrFX") { layer.HasEffects = true; } uint length = reader.ReadUInt32(); Data = reader.ReadBytes((int)length); }
internal static BitmapLayer DecodeToPdnLayer( this PhotoshopFile.Layer psdLayer) { var psdFile = psdLayer.PsdFile; psdLayer.CreateMissingChannels(); var pdnLayer = new BitmapLayer(psdFile.ColumnCount, psdFile.RowCount); pdnLayer.Name = psdLayer.Name; pdnLayer.Opacity = psdLayer.Opacity; pdnLayer.Visible = psdLayer.Visible; ImageDecoderPdn.DecodeImage(pdnLayer, psdLayer); return(pdnLayer); }
/// <summary> /// Decode image from Photoshop's channel-separated formats to BGRA. /// </summary> public static unsafe void DecodeImage(BitmapLayer pdnLayer, PhotoshopFile.Layer psdLayer) { var decodeContext = new DecodeContext(psdLayer, pdnLayer.Bounds); DecodeDelegate decoder = null; if (decodeContext.ByteDepth == 4) { decoder = GetDecodeDelegate32(decodeContext.ColorMode); } else { decoder = GetDecodeDelegate(decodeContext.ColorMode); } DecodeImage(pdnLayer, decodeContext, decoder); }
public DecodeContext(PhotoshopFile.Layer layer, Rectangle bounds) { Layer = layer; ByteDepth = Util.BytesFromBitDepth(layer.PsdFile.BitDepth); Channels = layer.Channels.ToIdArray(); AlphaChannel = layer.AlphaChannel; ColorMode = layer.PsdFile.ColorMode; ColorModeData = layer.PsdFile.ColorModeData; // 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); } }
/// <summary> /// Decode image from Photoshop's channel-separated formats to BGRA. /// </summary> public static void DecodeImage(BitmapLayer pdnLayer, PhotoshopFile.Layer psdLayer) { UnityEngine.Profiling.Profiler.BeginSample("DecodeImage"); var decodeContext = new DecodeContext(psdLayer, pdnLayer.Bounds); DecodeDelegate decoder = null; if (decodeContext.ByteDepth == 4) { decoder = GetDecodeDelegate32(decodeContext.ColorMode); } else { decoder = GetDecodeDelegate(decodeContext.ColorMode); } DecodeImage(pdnLayer, decodeContext, decoder); UnityEngine.Profiling.Profiler.EndSample(); }
/// <summary> /// Decode image from Photoshop's channel-separated formats to BGRA. /// </summary> 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); }
private Layer AddNewLayer(PsdFile psdFile, int index) { PhotoshopFile.Layer psdLayer = new PhotoshopFile.Layer(psdFile) { BlendModeKey = "norm", Visible = true, // Set layer metadata Rect = new System.Drawing.Rectangle(0, 0, psdFile.Columns, psdFile.Rows), Name = "Layer " + index, Opacity = 255 }; psdLayer.Visible = true; psdLayer.MaskData = new PhotoshopFile.Layer.Mask(psdLayer); psdLayer.BlendingRangesData = new PhotoshopFile.Layer.BlendingRanges(psdLayer); // Preserve Unicode layer name as Additional Layer Information var luniLayerInfo = new PhotoshopFile.Layer.AdjustmentLayerInfo("luni"); var luniData = Encoding.BigEndianUnicode.GetBytes("\u0000\u0000" + psdLayer.Name); Util.SetBigEndianInt32(luniData, 0, psdLayer.Name.Length); luniLayerInfo.Data = luniData; psdLayer.AdjustmentInfo.Add(luniLayerInfo); // Store channel metadata int layerSize = psdLayer.Rect.Width * psdLayer.Rect.Height; for (int i = -1; i < 3; i++) { PhotoshopFile.Layer.Channel ch = new PhotoshopFile.Layer.Channel((short)i, psdLayer) { ImageCompression = ImageCompression.Rle, ImageData = new byte[layerSize] }; } return(psdLayer); }
/// <summary> /// Decodes a <see cref="Layer"/> into a <see cref="Texture2D"/>. /// </summary> /// <param name="layer">The <see cref="Layer"/> to decode.</param> /// <returns>The <see cref="Texture2D"/> decoded from the layer.</returns> public static Texture2D DecodeImage(Layer layer) { if (layer.Rect.width == 0 || layer.Rect.height == 0) { return null; } Texture2D texture = new Texture2D((int)layer.Rect.width, (int)layer.Rect.height, TextureFormat.ARGB32, false); Color32[] colors = new Color32[(int)(layer.Rect.width * layer.Rect.height)]; for (int y = 0; y < layer.Rect.height; ++y) { int layerRow = y * (int)layer.Rect.width; // we need to reverse the Y position for the Unity texture int textureRow = ((int)layer.Rect.height - 1 - y) * (int)layer.Rect.width; for (int x = 0; x < layer.Rect.width; ++x) { int layerPosition = layerRow + x; int texturePosition = textureRow + x; colors[texturePosition] = GetColor(layer, layerPosition); // set the alpha if (layer.SortedChannels.ContainsKey(-2)) { byte color = GetColor(layer.MaskData, x, y); colors[texturePosition].a = (byte)(colors[texturePosition].a * color); } } } texture.SetPixels32(colors); return texture; }
/// <summary> /// Exports an art layer as an image file and sprite. It can also generate text meshes from text layers. /// </summary> /// <param name="layer">The art layer to export.</param> private static void ExportArtLayer(Layer layer) { if (!layer.IsTextLayer) { if (LayoutInScene || CreatePrefab) { // create a sprite from the layer to lay it out in the scene if (!UseUnityUI) { CreateSpriteGameObject(layer); } else { CreateUIImage(layer); } } else { // it is not being laid out in the scene, so simply save out the .png file CreatePNG(layer); } } else { // it is a text layer if (LayoutInScene || CreatePrefab) { // create text mesh if (!UseUnityUI) { CreateTextGameObject(layer); } else { CreateUIText(layer); } } } }
public AdjusmentLayerInfo(BinaryReverseReader reader, Layer layer) { Debug.WriteLine("AdjusmentLayerInfo started at " + reader.BaseStream.Position); m_layer = layer; var signature = new string(reader.ReadChars(4)); if (signature != LayerConstants.EightBimSignature) { throw new IOException("Could not read an image resource"); } m_key = new string(reader.ReadChars(4)); uint dataLength = reader.ReadUInt32(); m_data = reader.ReadBytes((int) dataLength); }
/////////////////////////////////////////////////////////////////////////// public BlendingRanges(BinaryReverseReader reader, Layer layer) { Debug.WriteLine("BlendingRanges started at " + reader.BaseStream.Position); m_layer = layer; int dataLength = reader.ReadInt32(); if (dataLength <= 0) return; m_data = reader.ReadBytes(dataLength); }
/////////////////////////////////////////////////////////////////////////// internal Mask(BinaryReverseReader reader, Layer layer) { Debug.WriteLine("Mask started at " + reader.BaseStream.Position); m_layer = layer; uint maskLength = reader.ReadUInt32(); if (maskLength <= 0) return; long startPosition = reader.BaseStream.Position; //----------------------------------------------------------------------- m_rect = new Rectangle { Y = reader.ReadInt32(), X = reader.ReadInt32() }; m_rect.Height = reader.ReadInt32() - m_rect.Y; m_rect.Width = reader.ReadInt32() - m_rect.X; m_defaultColor = reader.ReadByte(); //----------------------------------------------------------------------- byte flags = reader.ReadByte(); m_flags = new BitVector32(flags); //----------------------------------------------------------------------- if (maskLength == 36) { //var realFlags = new BitVector32(reader.ReadByte()); //var realUserMaskBackground = reader.ReadByte(); #if false var y = reader.ReadInt32(); var x = reader.ReadInt32(); var rect = new Rectangle { Y = y, X = x, Height = reader.ReadInt32() - y, Width = reader.ReadInt32() - x }; #else // this is just reading unused bytes... reader.ReadInt32(); reader.ReadInt32(); reader.ReadInt32(); reader.ReadInt32(); #endif } // there is other stuff following, but we will ignore this. reader.BaseStream.Position = startPosition + maskLength; }
internal Channel(BinaryReverseReader reader, Layer layer) { Debug.WriteLine("Channel started at " + reader.BaseStream.Position); m_id = reader.ReadInt16(); Length = reader.ReadInt32(); m_layer = layer; }
/// <summary> /// Decodes a <see cref="Layer"/> into a <see cref="Texture2D"/>. /// </summary> /// <param name="layer">The <see cref="Layer"/> to decode.</param> /// <returns>The <see cref="Texture2D"/> decoded from the layer.</returns> public static Texture2D DecodeImage(Layer layer) { if (layer.Rect.width == 0 || layer.Rect.height == 0) { return(null); } Texture2D texture = new Texture2D((int)layer.Rect.width, (int)layer.Rect.height, TextureFormat.ARGB32, false); Color32[] colors = new Color32[(int)(layer.Rect.width * layer.Rect.height)]; for (int y = 0; y < layer.Rect.height; ++y) { int layerRow = y * (int)layer.Rect.width; // we need to reverse the Y position for the Unity texture int textureRow = ((int)layer.Rect.height - 1 - y) * (int)layer.Rect.width; for (int x = 0; x < layer.Rect.width; ++x) { int layerPosition = layerRow + x; int texturePosition = textureRow + x; colors[texturePosition] = GetColor(layer, layerPosition); //// set the alpha //if(layer.SortedChannels.ContainsKey(-2)) //{ // byte color = GetColor(layer.MaskData, x, y); // colors[texturePosition].a = (byte)(colors[texturePosition].a * color); //} } } texture.SetPixels32(colors); if (layer.Is9Slice) { Regex reg = Layer.SLICE_REG; Match match = reg.Match(layer.Name); string[] size = match.Success ? match.ToString().Split(Layer.SLICE_SEPECTOR) : new string[] { "5", "5" }; int width = 0; int height = 0; //l t r b Border l b r t // y w if (layer.Border.x == 0 || layer.Border.z == 0) { width = (int)layer.Rect.width; height = int.Parse(size[1]); } else if (layer.Border.y == 0 || layer.Border.w == 0) { height = (int)layer.Rect.height; width = int.Parse(size[0]); } if (layer.Border.x != 0 && layer.Border.y != 0 && layer.Border.z != 0 && layer.Border.w != 0 && size.Length >= 2) { width = int.Parse(size[0]); height = int.Parse(size[1]); } int destWidth = (int)(layer.Border.x + layer.Border.z + width); int destHeight = (int)(layer.Border.y + layer.Border.w + height); float scaleFactorX = (texture.width * 1.0f - layer.Border.x - layer.Border.z) / width; float scaleFactorY = (texture.height * 1.0f - layer.Border.y - layer.Border.w) / height; return(Util9Slice.Create9Slice(texture, new Params((int)layer.Border.x, (int)layer.Border.z, (int)layer.Border.w, (int)layer.Border.y, width, height, destWidth, destHeight, scaleFactorX, scaleFactorY))); } return(texture); }
public Mask(Layer layer) { Layer = layer; this.flags = new BitVector32(); }
////////////////////////////////////////////////////////////////// internal Channel(short id, Layer layer) { ID = id; Layer = layer; }
/////////////////////////////////////////////////////////////////////////// /// <summary> /// Load Layers Info section, including image data. /// </summary> /// <param name="reader">PSD reader.</param> /// <param name="hasHeader">Whether the Layers Info section has a length header.</param> 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"); }
/// <summary> /// Returns true if the given <see cref="Layer"/> is marking the start of a layer group. /// </summary> /// <param name="layer">The <see cref="Layer"/> to check if it's the start of a group</param> /// <returns>True if the layer starts a group, otherwise false.</returns> private static bool IsStartGroup(Layer layer) { return layer.IsPixelDataIrrelevant; }
/////////////////////////////////////////////////////////////////////////// public static Bitmap DecodeImage(Layer.Mask mask) { if (mask.Rect.Width == 0 || mask.Rect.Height == 0) { return null; } var bitmap = new Bitmap(mask.Rect.Width, mask.Rect.Height, PixelFormat.Format32bppArgb); #if true // fix remove unsafeness (admittedly slower) // TODO: fast mode for (var y = 0; y < mask.Rect.Height; y++) { var rowIndex = y*mask.Rect.Width; for (var x = 0; x < mask.Rect.Width; x++) { var pos = rowIndex + x; var pixelColor = Color.FromArgb(mask.ImageData[pos], mask.ImageData[pos], mask.ImageData[pos]); // TODO: why is alpha ignored bitmap.SetPixel(x, y, Color.FromArgb(255, pixelColor)); } } #else Layer layer = mask.Layer; Rectangle r = new Rectangle(0, 0, bitmap.Width, bitmap.Height); BitmapData bd = bitmap.LockBits(r, ImageLockMode.ReadWrite, bitmap.PixelFormat); unsafe { byte* pCurrRowPixel = (byte*)bd.Scan0.ToPointer(); for (int y = 0; y < mask.Rect.Height; y++) { int rowIndex = y * mask.Rect.Width; PixelData* pCurrPixel = (PixelData*)pCurrRowPixel; for (int x = 0; x < mask.Rect.Width; x++) { int pos = rowIndex + x; Color pixelColor = Color.FromArgb(mask.ImageData[pos], mask.ImageData[pos], mask.ImageData[pos]); pCurrPixel->Alpha = 255; pCurrPixel->Red = pixelColor.R; pCurrPixel->Green = pixelColor.G; pCurrPixel->Blue = pixelColor.B; pCurrPixel += 1; } pCurrRowPixel += bd.Stride; } } bitmap.UnlockBits(bd); #endif return bitmap; }
/////////////////////////////////////////////////////////////////////////// private static Color GetColor(Layer layer, int pos) { var c = Color.White; switch (layer.PsdFile.ColorMode) { case PsdFile.ColorModes.RGB: c = Color.FromArgb(layer.SortedChannels[0].ImageData[pos], layer.SortedChannels[1].ImageData[pos], layer.SortedChannels[2].ImageData[pos]); break; case PsdFile.ColorModes.CMYK: c = CMYKToRGB(layer.SortedChannels[0].ImageData[pos], layer.SortedChannels[1].ImageData[pos], layer.SortedChannels[2].ImageData[pos], layer.SortedChannels[3].ImageData[pos]); break; case PsdFile.ColorModes.Multichannel: c = CMYKToRGB(layer.SortedChannels[0].ImageData[pos], layer.SortedChannels[1].ImageData[pos], layer.SortedChannels[2].ImageData[pos], 0); break; case PsdFile.ColorModes.Grayscale: case PsdFile.ColorModes.Duotone: c = Color.FromArgb(layer.SortedChannels[0].ImageData[pos], layer.SortedChannels[0].ImageData[pos], layer.SortedChannels[0].ImageData[pos]); break; case PsdFile.ColorModes.Indexed: { var index = (int)layer.SortedChannels[0].ImageData[pos]; c = Color.FromArgb(layer.PsdFile.ColorModeData[index], layer.PsdFile.ColorModeData[index + 256], layer.PsdFile.ColorModeData[index + 2*256]); } break; case PsdFile.ColorModes.Lab: { c = LabToRGB(layer.SortedChannels[0].ImageData[pos], layer.SortedChannels[1].ImageData[pos], layer.SortedChannels[2].ImageData[pos]); } break; } if (layer.SortedChannels.ContainsKey(-1)) c = Color.FromArgb(layer.SortedChannels[-1].ImageData[pos], c); return c; }
private static Texture2D CreateTexture(Layer layer) { if ((int)layer.Rect.width == 0 || (int)layer.Rect.height == 0) return null; // For possible clip to document functionality //int fileWidth = psd.ColumnCount; //int fileHeight = psd.RowCount; //int textureWidth = (int) layer.Rect.width; //int textureHeight = (int) layer.Rect.height; Texture2D tex = new Texture2D((int)layer.Rect.width, (int)layer.Rect.height, TextureFormat.RGBA32, true); Color32[] pixels = new Color32[tex.width * tex.height]; Channel red = (from l in layer.Channels where l.ID == 0 select l).First(); Channel green = (from l in layer.Channels where l.ID == 1 select l).First(); Channel blue = (from l in layer.Channels where l.ID == 2 select l).First(); Channel alpha = layer.AlphaChannel; for (int i = 0; i < pixels.Length; i++) { byte r = red.ImageData[i]; byte g = green.ImageData[i]; byte b = blue.ImageData[i]; byte a = 255; if (alpha != null) a = alpha.ImageData[i]; int mod = i % tex.width; int n = ((tex.width - mod - 1) + i) - mod; pixels[pixels.Length - n - 1] = new Color32(r, g, b, a); } tex.SetPixels32(pixels); tex.Apply(); return tex; }
private void BlendOpToBlendModeKey(UserBlendOp op, PhotoshopFile.Layer layer) { switch (op.ToString()) { case "Normal": layer.BlendModeKey = "norm"; break; case "Multiply": layer.BlendModeKey = "mul "; break; case "Additive": layer.BlendModeKey = "norm"; break; case "ColorBurn": layer.BlendModeKey = "div "; break; case "ColorDodge": layer.BlendModeKey = "idiv"; break; case "Reflect": layer.BlendModeKey = "norm"; break; case "Glow": layer.BlendModeKey = "norm"; break; case "Overlay": layer.BlendModeKey = "over"; break; case "Difference": layer.BlendModeKey = "diff"; break; case "Negation": layer.BlendModeKey = "norm"; break; case "Lighten": layer.BlendModeKey = "lite"; break; case "Darken": layer.BlendModeKey = "dark"; break; case "Screen": layer.BlendModeKey = "scrn"; break; case "Xor": layer.BlendModeKey = "norm"; break; default: layer.BlendModeKey = "norm"; break; } }
/////////////////////////////////////////////////////////////////////////// internal Mask(Layer layer) { m_layer = layer; m_layer.MaskData = this; }
private UserBlendOp BlendModeKeyToBlendOp(PhotoshopFile.Layer layer) { UserBlendOp blendOp = UserBlendOps.CreateBlendOp(typeof(UserBlendOps.NormalBlendOp)); switch (layer.BlendModeKey) { case "norm": blendOp = UserBlendOps.CreateBlendOp(typeof(UserBlendOps.NormalBlendOp)); break; case "dark": blendOp = UserBlendOps.CreateBlendOp(typeof(UserBlendOps.DarkenBlendOp)); break; case "lite": blendOp = UserBlendOps.CreateBlendOp(typeof(UserBlendOps.LightenBlendOp)); break; case "hue ": break; case "sat ": break; case "colr": break; case "lum ": break; case "mul ": blendOp = UserBlendOps.CreateBlendOp(typeof(UserBlendOps.MultiplyBlendOp)); break; case "scrn": blendOp = UserBlendOps.CreateBlendOp(typeof(UserBlendOps.ScreenBlendOp)); break; case "diss": break; case "over": blendOp = UserBlendOps.CreateBlendOp(typeof(UserBlendOps.OverlayBlendOp)); break; case "hLit": break; case "sLit": break; case "diff": blendOp = UserBlendOps.CreateBlendOp(typeof(UserBlendOps.DifferenceBlendOp)); break; case "smud": break; case "div ": blendOp = UserBlendOps.CreateBlendOp(typeof(UserBlendOps.ColorDodgeBlendOp)); break; case "idiv": blendOp = UserBlendOps.CreateBlendOp(typeof(UserBlendOps.ColorBurnBlendOp)); break; } return(blendOp); }
/////////////////////////////////////////////////////////////////////////// public BlendingRanges(Layer layer) { m_layer = layer; m_layer.BlendingRangesData = this; }
/// <summary> /// Returns true if the given <see cref="Layer"/> is marking the end of a layer group. /// </summary> /// <param name="layer">The <see cref="Layer"/> to check if it's the end of a group.</param> /// <returns>True if the layer ends a group, otherwise false.</returns> private static bool IsEndGroup(Layer layer) { return layer.Name.Contains("</Layer set>") || layer.Name.Contains("</Layer group>") || (layer.Name == " copy" && layer.Rect.height == 0); }
public AdjusmentLayerInfo(string key, Layer layer) { m_key = key; m_layer = layer; m_layer.AdjustmentInfo.Add(this); }
/// <summary> /// Exports a single layer from the tree. /// </summary> /// <param name="layer">The layer to export.</param> private static void ExportLayer(Layer layer) { layer.Name = MakeNameSafe(layer.Name); if (layer.Children.Count > 0 || layer.Rect.width == 0) { ExportFolderLayer(layer); } else { ExportArtLayer(layer); } }
/// <summary> /// Gets the color at the given position in the given <see cref="Layer"/>. /// </summary> /// <param name="layer">The <see cref="Layer"/> to sample.</param> /// <param name="position">The position to sample.</param> /// <returns>The sampled color.</returns> private static Color32 GetColor(Layer layer, int position) { Color32 baseColor = new Color32(1, 1, 1, 1); switch (layer.PsdFile.ColorMode) { case ColorModes.Grayscale: case ColorModes.Duotone: baseColor = new Color32(layer.SortedChannels[0].ImageData[position], layer.SortedChannels[0].ImageData[position], layer.SortedChannels[0].ImageData[position], 1); break; case ColorModes.Indexed: int index = layer.SortedChannels[0].ImageData[position]; baseColor = new Color32(layer.PsdFile.ColorModeData[index], layer.PsdFile.ColorModeData[index + 256], layer.PsdFile.ColorModeData[index + 512], 1); break; case ColorModes.RGB: baseColor = new Color32(layer.SortedChannels[0].ImageData[position], layer.SortedChannels[1].ImageData[position], layer.SortedChannels[2].ImageData[position], 1); break; case ColorModes.CMYK: baseColor = CMYKToRGB(layer.SortedChannels[0].ImageData[position], layer.SortedChannels[1].ImageData[position], layer.SortedChannels[2].ImageData[position], layer.SortedChannels[3].ImageData[position]); break; case ColorModes.Multichannel: baseColor = CMYKToRGB(layer.SortedChannels[0].ImageData[position], layer.SortedChannels[1].ImageData[position], layer.SortedChannels[2].ImageData[position], 0); break; case ColorModes.Lab: baseColor = LabToRGB(layer.SortedChannels[0].ImageData[position], layer.SortedChannels[1].ImageData[position], layer.SortedChannels[2].ImageData[position]); break; } // set the alpha if (layer.SortedChannels.ContainsKey(-1)) { baseColor.a = layer.SortedChannels[-1].ImageData[position]; } return baseColor; }
/// <summary> /// Creates a layer for each channel in a multichannel image. /// </summary> 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 = channel.ImageData; layer.Channels.Add(layerChannel); psdFile.Layers.Add(layer); } }
public static void Save(Document input, Stream output, PsdSaveConfigToken psdToken, Surface scratchSurface, ProgressEventHandler progressCallback) { var psdVersion = ((input.Height > 30000) || (input.Width > 30000)) ? PsdFileVersion.PsbLargeDocument : PsdFileVersion.Psd; var psdFile = new PsdFile(psdVersion); psdFile.RowCount = input.Height; psdFile.ColumnCount = input.Width; // We only save in RGBA format, 8 bits per channel, which corresponds to // Paint.NET's internal representation. psdFile.ChannelCount = 4; psdFile.ColorMode = PsdColorMode.RGB; psdFile.BitDepth = 8; psdFile.Resolution = GetResolutionInfo(input); psdFile.ImageCompression = psdToken.RleCompress ? ImageCompression.Rle : ImageCompression.Raw; // Treat the composite image as another layer when reporting progress. var progress = new ProgressNotifier(progressCallback); var percentPerLayer = percentStoreImages / (input.Layers.Count + 1); // Render the composite image. This operation is parallelized within // Paint.NET using its own private thread pool. using (var ra = new RenderArgs(scratchSurface)) { input.Flatten(scratchSurface); progress.Notify(percentRenderComposite); } // Delegate to store the composite Action storeCompositeAction = () => { // Allocate space for the composite image data int imageSize = psdFile.RowCount * psdFile.ColumnCount; for (short i = 0; i < psdFile.ChannelCount; i++) { var channel = new Channel(i, psdFile.BaseLayer); channel.ImageData = new byte[imageSize]; channel.ImageCompression = psdFile.ImageCompression; psdFile.BaseLayer.Channels.Add(channel); } var channelsArray = psdFile.BaseLayer.Channels.ToIdArray(); StoreLayerImage(channelsArray, channelsArray[3], scratchSurface, psdFile.BaseLayer.Rect); progress.Notify(percentPerLayer); }; // Delegate to store the layers Action storeLayersAction = () => { // LayerList is an ArrayList, so we have to cast to get a generic // IEnumerable that works with LINQ. var pdnLayers = input.Layers.Cast <BitmapLayer>(); // Create folders/groups before actual image data will be saved. var layerInfos = PrepareLayers(pdnLayers, psdToken.SaveLayers); var psdLayers = layerInfos.AsParallel().AsOrdered().Select(pdnLayer => { var psdLayer = new PhotoshopFile.Layer(psdFile); StoreLayer(pdnLayer, psdLayer, psdToken); progress.Notify(percentPerLayer); return(psdLayer); }); psdFile.Layers.AddRange(psdLayers); }; // Process composite and layers in parallel Parallel.Invoke(storeCompositeAction, storeLayersAction); psdFile.Save(output, Encoding.Default); }
/////////////////////////////////////////////////////////////////////////// public static Bitmap DecodeImage(Layer layer) { if (layer.Rect.Width == 0 || layer.Rect.Height == 0) { return null; } var bitmap = new Bitmap(layer.Rect.Width, layer.Rect.Height, PixelFormat.Format32bppArgb); #if TEST for (int y = 0; y < layer.Rect.Height; y++) { int rowIndex = y * layer.Rect.Width; for (int x = 0; x < layer.Rect.Width; x++) { int pos = rowIndex + x; //Color pixelColor=GetColor(psdFile,pos); Color pixelColor = Color.FromArgb(x % 255, Color.ForestGreen);// 255, 128, 0); bitmap.SetPixel(x, y, pixelColor); } } #else #if true // fix remove unsafeness (admittedly slower) // TODO: fast mode for (var y = 0; y < layer.Rect.Height; y++) { var rowIndex = y * layer.Rect.Width; for (var x = 0; x < layer.Rect.Width; x++) { var pos = rowIndex + x; var pixelColor = GetColor(layer, pos); if (layer.SortedChannels.ContainsKey(-2)) { var maskAlpha = GetColor(layer.MaskData, x, y); int oldAlpha = pixelColor.A; var newAlpha = (oldAlpha * maskAlpha) / 255; pixelColor = Color.FromArgb(newAlpha, pixelColor); } bitmap.SetPixel(x, y, pixelColor); } } #else Rectangle r = new Rectangle(0, 0, bitmap.Width, bitmap.Height); BitmapData bd = bitmap.LockBits(r, ImageLockMode.ReadWrite, bitmap.PixelFormat); unsafe { byte* pCurrRowPixel = (byte*)bd.Scan0.ToPointer(); for (int y = 0; y < layer.Rect.Height; y++) { int rowIndex = y * layer.Rect.Width; PixelData* pCurrPixel = (PixelData*)pCurrRowPixel; for (int x = 0; x < layer.Rect.Width; x++) { int pos = rowIndex + x; Color pixelColor = GetColor(layer, pos); if (layer.SortedChannels.ContainsKey(-2)) { int maskAlpha = GetColor(layer.MaskData, x, y); int oldAlpha = pixelColor.A; int newAlpha = (oldAlpha * maskAlpha) / 255; pixelColor = Color.FromArgb(newAlpha,pixelColor); } pCurrPixel->Alpha = pixelColor.A; pCurrPixel->Red = pixelColor.R; pCurrPixel->Green = pixelColor.G; pCurrPixel->Blue = pixelColor.B; pCurrPixel += 1; } pCurrRowPixel += bd.Stride; } } bitmap.UnlockBits(bd); #endif #endif return bitmap; }
/////////////////////////////////////////////////////////////////////////// public BlendingRanges(Layer layer) { Layer = layer; Data = new byte[0]; }
protected override void OnSave(Document input, System.IO.Stream output, SaveConfigToken token, Surface scratchSurface, ProgressEventHandler callback) { PsdSaveConfigToken psdToken = (PsdSaveConfigToken)token; PsdFile psdFile = new PsdFile(); //----------------------------------------------------------------------- psdFile.Rows = input.Height; psdFile.Columns = input.Width; // we have an Alpha channel which will be saved, // we have to add this to our image resources psdFile.Channels = 4; // for now we oly save the images as RGB psdFile.ColorMode = PsdFile.ColorModes.RGB; psdFile.Depth = 8; //----------------------------------------------------------------------- // no color mode Data //----------------------------------------------------------------------- ResolutionInfo resInfo = new ResolutionInfo(); resInfo.HeightUnit = ResolutionInfo.Unit.In; resInfo.WidthUnit = ResolutionInfo.Unit.In; if (input.DpuUnit == MeasurementUnit.Inch) { resInfo.HResUnit = ResolutionInfo.ResUnit.PxPerInch; resInfo.VResUnit = ResolutionInfo.ResUnit.PxPerInch; resInfo.HRes = (short)input.DpuX; resInfo.VRes = (short)input.DpuY; } else { resInfo.HResUnit = ResolutionInfo.ResUnit.PxPerCent; resInfo.VResUnit = ResolutionInfo.ResUnit.PxPerCent; resInfo.HRes = (short)(input.DpuX / 2.54); resInfo.VRes = (short)(input.DpuY / 2.54); } psdFile.Resolution = resInfo; //----------------------------------------------------------------------- psdFile.ImageCompression = psdToken.RleCompress ? ImageCompression.Rle : ImageCompression.Raw; int size = psdFile.Rows * psdFile.Columns; psdFile.ImageData = new byte[psdFile.Channels][]; for (int i = 0; i < psdFile.Channels; i++) { psdFile.ImageData[i] = new byte[size]; } using (RenderArgs ra = new RenderArgs(scratchSurface)) { input.Flatten(scratchSurface); } unsafe { for (int y = 0; y < psdFile.Rows; y++) { int rowIndex = y * psdFile.Columns; ColorBgra *srcRow = scratchSurface.GetRowAddress(y); ColorBgra *srcPixel = srcRow; for (int x = 0; x < psdFile.Columns; x++) { int pos = rowIndex + x; psdFile.ImageData[0][pos] = srcPixel->R; psdFile.ImageData[1][pos] = srcPixel->G; psdFile.ImageData[2][pos] = srcPixel->B; psdFile.ImageData[3][pos] = srcPixel->A; srcPixel++; } } } PaintDotNet.Threading.PrivateThreadPool threadPool = new PaintDotNet.Threading.PrivateThreadPool(); foreach (BitmapLayer layer in input.Layers) { PhotoshopFile.Layer psdLayer = new PhotoshopFile.Layer(psdFile); BlendOpToBlendModeKey(layer.BlendOp, psdLayer); SaveLayerPixelsContext slc = new SaveLayerPixelsContext(layer, psdFile, input, psdLayer, psdToken); WaitCallback waitCallback = new WaitCallback(slc.SaveLayer); threadPool.QueueUserWorkItem(waitCallback); } threadPool.Drain(); psdFile.Save(output); }
/////////////////////////////////////////////////////////////////////////// private static int GetColor(Layer.Mask mask, int x, int y) { int c = 255; if (mask.PositionIsRelative) { x -= mask.Rect.X; y -= mask.Rect.Y; } else { x = (x + mask.Layer.Rect.X) - mask.Rect.X; y = (y + mask.Layer.Rect.Y) - mask.Rect.Y; } if (y >= 0 && y < mask.Rect.Height && x >= 0 && x < mask.Rect.Width) { var pos = y * mask.Rect.Width + x; if (pos < mask.ImageData.Length) { c = mask.ImageData[pos]; } else { c = 255; } } return c; }
/// <summary> /// Exports a <see cref="Layer"/> that is a folder containing child layers. /// </summary> /// <param name="layer">The layer that is a folder.</param> private static void ExportFolderLayer(Layer layer) { if (layer.Name.ContainsIgnoreCase("|Button")) { layer.Name = layer.Name.ReplaceIgnoreCase("|Button", string.Empty); if (UseUnityUI) { CreateUIButton(layer); } else { ////CreateGUIButton(layer); } } else if (layer.Name.ContainsIgnoreCase("|Animation")) { layer.Name = layer.Name.ReplaceIgnoreCase("|Animation", string.Empty); string oldPath = currentPath; GameObject oldGroupObject = currentGroupGameObject; currentPath = Path.Combine(currentPath, layer.Name.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries)[0]); Directory.CreateDirectory(currentPath); if (UseUnityUI) { ////CreateUIAnimation(layer); } else { CreateAnimation(layer); } currentPath = oldPath; currentGroupGameObject = oldGroupObject; } else { // it is a "normal" folder layer that contains children layers string oldPath = currentPath; GameObject oldGroupObject = currentGroupGameObject; currentPath = Path.Combine(currentPath, layer.Name); Directory.CreateDirectory(currentPath); if (LayoutInScene || CreatePrefab) { currentGroupGameObject = new GameObject(layer.Name); currentGroupGameObject.transform.parent = oldGroupObject.transform; } ExportTree(layer.Children); currentPath = oldPath; currentGroupGameObject = oldGroupObject; } }
public MaskInfo(PsdBinaryReader reader, Layer layer) { Debug.WriteLine("MaskInfo started at " + reader.BaseStream.Position.ToString(CultureInfo.InvariantCulture)); 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; }
////////////////////////////////////////////////////////////////// internal Channel(short id, Layer layer) { m_id = id; m_layer = layer; m_layer.Channels.Add(this); m_layer.SortedChannels.Add(ID, this); }
public static void SaveLayerPixels(BitmapLayer layer, PsdFile psdFile, Document input, PhotoshopFile.Layer psdLayer, PsdSaveConfigToken psdToken) { Surface surface = layer.Surface; int rectLeft = input.Width; int rectTop = input.Height; int rectRight = 0; int rectBottom = 0; // Determine the real size of this layer, i.e., the smallest rectangle // that includes all all non-invisible pixels unsafe { for (int y = 0; y < psdFile.Rows; y++) { int rowIndex = y * psdFile.Columns; ColorBgra *srcRow = surface.GetRowAddress(y); ColorBgra *srcPixel = srcRow; for (int x = 0; x < psdFile.Columns; x++) { int pos = rowIndex + x; // Found a non-transparent pixel, potentially increase the size of the rectangle if (srcPixel->A > 0) { // Expand the rectangle if (x < rectLeft) { rectLeft = x; } if (x > rectRight) { rectRight = x; } if (y < rectTop) { rectTop = y; } if (y > rectBottom) { rectBottom = y; } } srcPixel++; } } } psdLayer.Rect = new Rectangle(rectLeft, rectTop, rectRight - rectLeft + 1, rectBottom - rectTop + 1); psdLayer.Name = layer.Name; psdLayer.Opacity = layer.Opacity; psdLayer.Visible = layer.Visible; psdLayer.MaskData = new PhotoshopFile.Layer.Mask(psdLayer); psdLayer.BlendingRangesData = new PhotoshopFile.Layer.BlendingRanges(psdLayer); int layerSize = psdLayer.Rect.Width * psdLayer.Rect.Height; for (int i = -1; i < 3; i++) { PhotoshopFile.Layer.Channel ch = new PhotoshopFile.Layer.Channel((short)i, psdLayer); ch.ImageCompression = psdToken.RleCompress ? ImageCompression.Rle : ImageCompression.Raw; ch.ImageData = new byte[layerSize]; } var channels = psdLayer.ChannelsArray; var alphaChannel = psdLayer.AlphaChannel; unsafe { int rowIndex = 0; for (int y = 0; y < psdLayer.Rect.Height; y++) { ColorBgra *srcRow = surface.GetRowAddress(y + psdLayer.Rect.Top); ColorBgra *srcPixel = srcRow + psdLayer.Rect.Left; for (int x = 0; x < psdLayer.Rect.Width; x++) { int pos = rowIndex + x; channels[0].ImageData[pos] = srcPixel->R; channels[1].ImageData[pos] = srcPixel->G; channels[2].ImageData[pos] = srcPixel->B; alphaChannel.ImageData[pos] = srcPixel->A; srcPixel++; } rowIndex += psdLayer.Rect.Width; } } }
/// <summary> /// Initializes a new instance of the <see cref="Channel"/> class. /// </summary> /// <param name="reader">The reader to use to initialize the instance.</param> /// <param name="layer">The layer this channel belongs to.</param> internal Channel(BinaryReverseReader reader, Layer layer) { ID = reader.ReadInt16(); Length = reader.ReadInt32(); Layer = layer; }