/Platters/classes/photoshop/ImageDecoderBitmaps.cs
http://skimpt.googlecode.com/ · C# · 509 lines · 358 code · 96 blank · 55 comment · 51 complexity · 76e65664c49968b20a98d3e961be462a MD5 · raw file
- /////////////////////////////////////////////////////////////////////////////////
- // Copyright (C) 2006, Frank Blumenberg
- //
- // See License.txt for complete licensing and attribution information.
- // 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.
- //
- /////////////////////////////////////////////////////////////////////////////////
-
- /////////////////////////////////////////////////////////////////////////////////
- //
- // This code contains code from SimplePsd class library by Igor Tolmachev.
- // http://www.codeproject.com/csharp/simplepsd.asp
- //
- /////////////////////////////////////////////////////////////////////////////////
-
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Drawing;
- using System.Drawing.Imaging;
-
- namespace Photoshop
- {
- public class ImageDecoder
- {
- public ImageDecoder()
- {
-
- }
-
- ///////////////////////////////////////////////////////////////////////////
-
- #if !TEST
- private struct PixelData
- {
- public byte Blue;
- public byte Green;
- public byte Red;
- public byte Alpha;
- }
- #endif
-
- ///////////////////////////////////////////////////////////////////////////
-
- public static Bitmap DecodeImage(PsdFile psdFile)
- {
- Bitmap bitmap = new Bitmap(psdFile.Columns, psdFile.Rows, PixelFormat.Format32bppArgb);
-
- #if TEST
- for (int y = 0; y < psdFile.Rows; y++)
- {
- int rowIndex = y * psdFile.Columns;
-
- for (int x = 0; x < psdFile.Columns; x++)
- {
- int pos = rowIndex + x;
-
- Color pixelColor=GetColor(psdFile,pos);
-
- 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 < psdFile.Rows; y++)
- {
- int rowIndex = y * psdFile.Columns;
- PixelData* pCurrPixel = (PixelData*)pCurrRowPixel;
- for (int x = 0; x < psdFile.Columns; x++)
- {
- int pos = rowIndex + x;
-
- Color pixelColor = GetColor(psdFile, 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(PsdFile psdFile, int pos)
- {
- Color c = Color.White;
-
- switch (psdFile.ColorMode)
- {
- case PsdFile.ColorModes.RGB:
- c = Color.FromArgb(psdFile.ImageData[0][pos],
- psdFile.ImageData[1][pos],
- psdFile.ImageData[2][pos]);
- break;
- case PsdFile.ColorModes.CMYK:
- c = CMYKToRGB(psdFile.ImageData[0][pos],
- psdFile.ImageData[1][pos],
- psdFile.ImageData[2][pos],
- psdFile.ImageData[3][pos]);
- break;
- case PsdFile.ColorModes.Multichannel:
- c = CMYKToRGB(psdFile.ImageData[0][pos],
- psdFile.ImageData[1][pos],
- psdFile.ImageData[2][pos],
- 0);
- break;
- case PsdFile.ColorModes.Grayscale:
- case PsdFile.ColorModes.Duotone:
- c = Color.FromArgb(psdFile.ImageData[0][pos],
- psdFile.ImageData[0][pos],
- psdFile.ImageData[0][pos]);
- break;
- case PsdFile.ColorModes.Indexed:
- {
- int index = (int)psdFile.ImageData[0][pos];
- c = Color.FromArgb((int)psdFile.ColorModeData[index],
- psdFile.ColorModeData[index + 256],
- psdFile.ColorModeData[index + 2 * 256]);
- }
- break;
- case PsdFile.ColorModes.Lab:
- {
- c = LabToRGB(psdFile.ImageData[0][pos],
- psdFile.ImageData[1][pos],
- psdFile.ImageData[2][pos]);
- }
- break;
- }
-
- return c;
- }
-
- ///////////////////////////////////////////////////////////////////////////
-
- public static Bitmap DecodeImage(Layer layer)
- {
- if (layer.Rect.Width == 0 || layer.Rect.Height == 0)
- {
- return null;
- }
-
- Bitmap 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
-
- 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
-
- return bitmap;
- }
-
- ///////////////////////////////////////////////////////////////////////////
-
- private static Color GetColor(Layer layer, int pos)
- {
- Color 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:
- {
- int index = (int)layer.SortedChannels[0].ImageData[pos];
- c = Color.FromArgb((int)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 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)
- {
- int pos = y * mask.Rect.Width + x;
- if (pos < mask.ImageData.Length)
- c = mask.ImageData[pos];
- else
- c = 255;
- }
-
- return c;
- }
-
- ///////////////////////////////////////////////////////////////////////////
-
- public static Bitmap DecodeImage(Layer.Mask mask)
- {
- Layer layer = mask.Layer;
-
- if (mask.Rect.Width == 0 || mask.Rect.Height == 0)
- {
- return null;
- }
-
- Bitmap bitmap = new Bitmap(mask.Rect.Width, mask.Rect.Height, PixelFormat.Format32bppArgb);
-
- 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);
-
- return bitmap;
- }
-
- ///////////////////////////////////////////////////////////////////////////
-
- private static Color LabToRGB(byte lb, byte ab, byte bb)
- {
- double exL, exA, exB;
-
- exL = (double)lb;
- exA = (double)ab;
- exB = (double)bb;
-
- double L_coef, a_coef, b_coef;
- L_coef = 256.0 / 100.0;
- a_coef = 256.0 / 256.0;
- b_coef = 256.0 / 256.0;
-
- int L = (int)(exL / L_coef);
- int a = (int)(exA / a_coef - 128.0);
- int b = (int)(exB / b_coef - 128.0);
-
- // For the conversion we first convert values to XYZ and then to RGB
- // 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;
-
- if (Math.Pow(var_Y, 3) > 0.008856)
- var_Y = Math.Pow(var_Y, 3);
- else
- var_Y = (var_Y - 16 / 116) / 7.787;
-
- if (Math.Pow(var_X, 3) > 0.008856)
- var_X = Math.Pow(var_X, 3);
- else
- var_X = (var_X - 16 / 116) / 7.787;
-
- if (Math.Pow(var_Z, 3) > 0.008856)
- var_Z = Math.Pow(var_Z, 3);
- 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;
-
- return XYZToRGB(X, Y, Z);
- }
-
- ////////////////////////////////////////////////////////////////////////////
-
- private static Color XYZToRGB(double X, double Y, double Z)
- {
- // Standards used Observer = 2, Illuminant = D65
- // ref_X = 95.047, ref_Y = 100.000, ref_Z = 108.883
-
- double var_X = X / 100.0;
- double var_Y = Y / 100.0;
- double var_Z = Z / 100.0;
-
- double var_R = var_X * 3.2406 + var_Y * (-1.5372) + var_Z * (-0.4986);
- double var_G = var_X * (-0.9689) + var_Y * 1.8758 + var_Z * 0.0415;
- double var_B = var_X * 0.0557 + var_Y * (-0.2040) + var_Z * 1.0570;
-
- 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;
-
- return Color.FromArgb(nRed, nGreen, nBlue);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // The algorithms for these routines were taken from:
- // http://www.neuro.sfc.keio.ac.jp/~aly/polygon/info/color-space-faq.html
- //
- // 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 Color CMYKToRGB(byte c, byte m, byte y, byte k)
- {
- double C, M, Y, K;
-
- double exC, exM, exY, exK;
- double dMaxColours = Math.Pow(2, 8);
-
- exC = (double)c;
- exM = (double)m;
- exY = (double)y;
- exK = (double)k;
-
- C = (1.0 - exC / dMaxColours);
- M = (1.0 - exM / dMaxColours);
- Y = (1.0 - exY / dMaxColours);
- K = (1.0 - exK / dMaxColours);
-
- int nRed = (int)((1.0 - (C * (1 - K) + K)) * 255);
- int nGreen = (int)((1.0 - (M * (1 - K) + K)) * 255);
- int nBlue = (int)((1.0 - (Y * (1 - K) + K)) * 255);
-
- 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;
-
- return Color.FromArgb(nRed, nGreen, nBlue);
- }
- }
- }