PageRenderTime 36ms CodeModel.GetById 15ms app.highlight 17ms RepoModel.GetById 1ms app.codeStats 0ms

/Platters/classes/photoshop/ImageDecoderBitmaps.cs

http://skimpt.googlecode.com/
C# | 509 lines | 358 code | 96 blank | 55 comment | 51 complexity | 76e65664c49968b20a98d3e961be462a MD5 | raw file
  1/////////////////////////////////////////////////////////////////////////////////
  2// Copyright (C) 2006, Frank Blumenberg
  3// 
  4// See License.txt for complete licensing and attribution information.
  5// Permission is hereby granted, free of charge, to any person obtaining a copy 
  6// of this software and associated documentation files (the "Software"), to deal
  7// in the Software without restriction, including without limitation the rights
  8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
  9// copies of the Software, and to permit persons to whom the Software is 
 10// furnished to do so, subject to the following conditions:
 11// 
 12// The above copyright notice and this permission notice shall be included in all
 13// copies or substantial portions of the Software.
 14// 
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
 21// THE SOFTWARE.
 22// 
 23/////////////////////////////////////////////////////////////////////////////////
 24
 25/////////////////////////////////////////////////////////////////////////////////
 26//
 27// This code contains code from SimplePsd class library by Igor Tolmachev.
 28// http://www.codeproject.com/csharp/simplepsd.asp
 29//
 30/////////////////////////////////////////////////////////////////////////////////
 31
 32using System;
 33using System.Collections.Generic;
 34using System.Text;
 35using System.Drawing;
 36using System.Drawing.Imaging;
 37
 38namespace Photoshop
 39{
 40  public class ImageDecoder
 41  {
 42    public ImageDecoder()
 43    {
 44
 45    }
 46
 47    /////////////////////////////////////////////////////////////////////////// 
 48
 49#if !TEST
 50    private struct PixelData
 51    {
 52      public byte Blue;
 53      public byte Green;
 54      public byte Red;
 55      public byte Alpha;
 56    }
 57#endif
 58
 59    /////////////////////////////////////////////////////////////////////////// 
 60
 61    public static Bitmap DecodeImage(PsdFile psdFile)
 62    {
 63      Bitmap bitmap = new Bitmap(psdFile.Columns, psdFile.Rows, PixelFormat.Format32bppArgb);
 64
 65#if TEST
 66      for (int y = 0; y < psdFile.Rows; y++)
 67      {
 68        int rowIndex = y * psdFile.Columns;
 69
 70        for (int x = 0; x < psdFile.Columns; x++)
 71        {
 72          int pos = rowIndex + x;
 73
 74          Color pixelColor=GetColor(psdFile,pos);
 75
 76          bitmap.SetPixel(x, y, pixelColor);
 77        }
 78      }
 79
 80#else
 81
 82      Rectangle r = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
 83      BitmapData bd = bitmap.LockBits(r, ImageLockMode.ReadWrite, bitmap.PixelFormat);
 84
 85      unsafe
 86      {
 87        byte* pCurrRowPixel = (byte*)bd.Scan0.ToPointer();
 88
 89        for (int y = 0; y < psdFile.Rows; y++)
 90        {
 91          int rowIndex = y * psdFile.Columns;
 92          PixelData* pCurrPixel = (PixelData*)pCurrRowPixel;
 93          for (int x = 0; x < psdFile.Columns; x++)
 94          {
 95            int pos = rowIndex + x;
 96
 97            Color pixelColor = GetColor(psdFile, pos);
 98
 99            pCurrPixel->Alpha = 255;
100            pCurrPixel->Red = pixelColor.R;
101            pCurrPixel->Green = pixelColor.G;
102            pCurrPixel->Blue = pixelColor.B;
103
104            pCurrPixel += 1;
105          }
106          pCurrRowPixel += bd.Stride;
107        }
108      }
109
110      bitmap.UnlockBits(bd);
111#endif
112
113      return bitmap;
114    }
115
116    /////////////////////////////////////////////////////////////////////////// 
117
118    private static Color GetColor(PsdFile psdFile, int pos)
119    {
120      Color c = Color.White;
121
122      switch (psdFile.ColorMode)
123      {
124        case PsdFile.ColorModes.RGB:
125          c = Color.FromArgb(psdFile.ImageData[0][pos],
126                             psdFile.ImageData[1][pos],
127                             psdFile.ImageData[2][pos]);
128          break;
129        case PsdFile.ColorModes.CMYK:
130          c = CMYKToRGB(psdFile.ImageData[0][pos],
131                        psdFile.ImageData[1][pos],
132                        psdFile.ImageData[2][pos],
133                        psdFile.ImageData[3][pos]);
134          break;
135        case PsdFile.ColorModes.Multichannel:
136          c = CMYKToRGB(psdFile.ImageData[0][pos],
137                        psdFile.ImageData[1][pos],
138                        psdFile.ImageData[2][pos],
139                        0);
140          break;
141        case PsdFile.ColorModes.Grayscale:
142        case PsdFile.ColorModes.Duotone:
143          c = Color.FromArgb(psdFile.ImageData[0][pos],
144                             psdFile.ImageData[0][pos],
145                             psdFile.ImageData[0][pos]);
146          break;
147        case PsdFile.ColorModes.Indexed:
148          {
149            int index = (int)psdFile.ImageData[0][pos];
150            c = Color.FromArgb((int)psdFile.ColorModeData[index],
151                             psdFile.ColorModeData[index + 256],
152                             psdFile.ColorModeData[index + 2 * 256]);
153          }
154          break;
155        case PsdFile.ColorModes.Lab:
156          {
157            c = LabToRGB(psdFile.ImageData[0][pos],
158                         psdFile.ImageData[1][pos],
159                         psdFile.ImageData[2][pos]);
160          }
161          break;
162      }
163
164      return c;
165    }
166
167    /////////////////////////////////////////////////////////////////////////// 
168
169    public static Bitmap DecodeImage(Layer layer)
170    {
171      if (layer.Rect.Width == 0 || layer.Rect.Height == 0)
172      {
173        return null;
174      }
175
176      Bitmap bitmap = new Bitmap(layer.Rect.Width, layer.Rect.Height, PixelFormat.Format32bppArgb);
177
178#if TEST
179      for (int y = 0; y < layer.Rect.Height; y++)
180      {
181        int rowIndex = y * layer.Rect.Width;
182
183        for (int x = 0; x < layer.Rect.Width; x++)
184        {
185          int pos = rowIndex + x;
186
187          //Color pixelColor=GetColor(psdFile,pos);
188          Color pixelColor = Color.FromArgb(x % 255, Color.ForestGreen);// 255, 128, 0);
189
190          bitmap.SetPixel(x, y, pixelColor);
191        }
192      }
193
194#else
195
196      Rectangle r = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
197      BitmapData bd = bitmap.LockBits(r, ImageLockMode.ReadWrite, bitmap.PixelFormat);
198
199      unsafe
200      {
201        byte* pCurrRowPixel = (byte*)bd.Scan0.ToPointer();
202
203        for (int y = 0; y < layer.Rect.Height; y++)
204        {
205          int rowIndex = y * layer.Rect.Width;
206          PixelData* pCurrPixel = (PixelData*)pCurrRowPixel;
207          for (int x = 0; x < layer.Rect.Width; x++)
208          {
209            int pos = rowIndex + x;
210
211            Color pixelColor = GetColor(layer, pos);
212
213            if (layer.SortedChannels.ContainsKey(-2))
214            {
215                int maskAlpha = GetColor(layer.MaskData, x, y);
216                int oldAlpha = pixelColor.A;
217
218                int newAlpha = (oldAlpha * maskAlpha) / 255;
219                pixelColor = Color.FromArgb(newAlpha,pixelColor);
220            }
221
222            pCurrPixel->Alpha = pixelColor.A;
223            pCurrPixel->Red = pixelColor.R;
224            pCurrPixel->Green = pixelColor.G;
225            pCurrPixel->Blue = pixelColor.B;
226
227            pCurrPixel += 1;
228          }
229          pCurrRowPixel += bd.Stride;
230        }
231      }
232
233      bitmap.UnlockBits(bd);
234#endif
235
236      return bitmap;
237    }
238
239    /////////////////////////////////////////////////////////////////////////// 
240
241    private static Color GetColor(Layer layer, int pos)
242    {
243      Color c = Color.White;
244
245      switch (layer.PsdFile.ColorMode)
246      {
247        case PsdFile.ColorModes.RGB:
248          c = Color.FromArgb(layer.SortedChannels[0].ImageData[pos],
249                             layer.SortedChannels[1].ImageData[pos],
250                             layer.SortedChannels[2].ImageData[pos]);
251          break;
252        case PsdFile.ColorModes.CMYK:
253          c = CMYKToRGB(layer.SortedChannels[0].ImageData[pos],
254                        layer.SortedChannels[1].ImageData[pos],
255                        layer.SortedChannels[2].ImageData[pos],
256                        layer.SortedChannels[3].ImageData[pos]);
257          break;
258        case PsdFile.ColorModes.Multichannel:
259          c = CMYKToRGB(layer.SortedChannels[0].ImageData[pos],
260                        layer.SortedChannels[1].ImageData[pos],
261                        layer.SortedChannels[2].ImageData[pos],
262                        0);
263          break;
264        case PsdFile.ColorModes.Grayscale:
265        case PsdFile.ColorModes.Duotone:
266          c = Color.FromArgb(layer.SortedChannels[0].ImageData[pos],
267                             layer.SortedChannels[0].ImageData[pos],
268                             layer.SortedChannels[0].ImageData[pos]);
269          break;
270        case PsdFile.ColorModes.Indexed:
271          {
272            int index = (int)layer.SortedChannels[0].ImageData[pos];
273            c = Color.FromArgb((int)layer.PsdFile.ColorModeData[index],
274                             layer.PsdFile.ColorModeData[index + 256],
275                             layer.PsdFile.ColorModeData[index + 2 * 256]);
276          }
277          break;
278        case PsdFile.ColorModes.Lab:
279          {
280            c = LabToRGB(layer.SortedChannels[0].ImageData[pos],
281                         layer.SortedChannels[1].ImageData[pos],
282                         layer.SortedChannels[2].ImageData[pos]);
283          }
284          break;
285      }
286
287      if (layer.SortedChannels.ContainsKey(-1))
288        c = Color.FromArgb(layer.SortedChannels[-1].ImageData[pos], c);
289
290      return c;
291    }
292
293    /////////////////////////////////////////////////////////////////////////// 
294
295    private static int GetColor(Layer.Mask mask, int x, int y)
296    {
297      int c = 255;
298      
299      if (mask.PositionIsRelative)
300      {
301        x -= mask.Rect.X;
302        y -= mask.Rect.Y;
303      }
304      else
305      {
306        x = (x + mask.Layer.Rect.X) - mask.Rect.X;
307        y = (y + mask.Layer.Rect.Y) - mask.Rect.Y;
308      }
309
310      if (y >= 0 && y < mask.Rect.Height &&
311           x >= 0 && x < mask.Rect.Width)
312      {
313        int pos = y * mask.Rect.Width + x;
314        if (pos < mask.ImageData.Length)
315          c = mask.ImageData[pos];
316        else
317          c = 255;
318      }
319
320      return c;
321    }
322
323    /////////////////////////////////////////////////////////////////////////// 
324
325    public static Bitmap DecodeImage(Layer.Mask mask)
326    {
327      Layer layer = mask.Layer;
328
329      if (mask.Rect.Width == 0 || mask.Rect.Height == 0)
330      {
331        return null;
332      }
333
334      Bitmap bitmap = new Bitmap(mask.Rect.Width, mask.Rect.Height, PixelFormat.Format32bppArgb);
335
336      Rectangle r = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
337      BitmapData bd = bitmap.LockBits(r, ImageLockMode.ReadWrite, bitmap.PixelFormat);
338
339      unsafe
340      {
341        byte* pCurrRowPixel = (byte*)bd.Scan0.ToPointer();
342
343        for (int y = 0; y < mask.Rect.Height; y++)
344        {
345          int rowIndex = y * mask.Rect.Width;
346          PixelData* pCurrPixel = (PixelData*)pCurrRowPixel;
347          for (int x = 0; x < mask.Rect.Width; x++)
348          {
349            int pos = rowIndex + x;
350
351            Color pixelColor = Color.FromArgb(mask.ImageData[pos], mask.ImageData[pos], mask.ImageData[pos]);
352
353            pCurrPixel->Alpha = 255;
354            pCurrPixel->Red = pixelColor.R;
355            pCurrPixel->Green = pixelColor.G;
356            pCurrPixel->Blue = pixelColor.B;
357
358            pCurrPixel += 1;
359          }
360          pCurrRowPixel += bd.Stride;
361        }
362      }
363
364      bitmap.UnlockBits(bd);
365
366      return bitmap;
367    }
368
369    /////////////////////////////////////////////////////////////////////////// 
370
371    private static Color LabToRGB(byte lb, byte ab, byte bb)
372    {
373      double exL, exA, exB;
374
375      exL = (double)lb;
376      exA = (double)ab;
377      exB = (double)bb;
378
379      double L_coef, a_coef, b_coef;
380      L_coef = 256.0 / 100.0;
381      a_coef = 256.0 / 256.0;
382      b_coef = 256.0 / 256.0;
383
384      int L = (int)(exL / L_coef);
385      int a = (int)(exA / a_coef - 128.0);
386      int b = (int)(exB / b_coef - 128.0);
387
388      // For the conversion we first convert values to XYZ and then to RGB
389      // Standards used Observer = 2, Illuminant = D65
390
391      const double ref_X = 95.047;
392      const double ref_Y = 100.000;
393      const double ref_Z = 108.883;
394
395      double var_Y = ((double)L + 16.0) / 116.0;
396      double var_X = (double)a / 500.0 + var_Y;
397      double var_Z = var_Y - (double)b / 200.0;
398
399      if (Math.Pow(var_Y, 3) > 0.008856)
400        var_Y = Math.Pow(var_Y, 3);
401      else
402        var_Y = (var_Y - 16 / 116) / 7.787;
403
404      if (Math.Pow(var_X, 3) > 0.008856)
405        var_X = Math.Pow(var_X, 3);
406      else
407        var_X = (var_X - 16 / 116) / 7.787;
408
409      if (Math.Pow(var_Z, 3) > 0.008856)
410        var_Z = Math.Pow(var_Z, 3);
411      else
412        var_Z = (var_Z - 16 / 116) / 7.787;
413
414      double X = ref_X * var_X;
415      double Y = ref_Y * var_Y;
416      double Z = ref_Z * var_Z;
417
418      return XYZToRGB(X, Y, Z);
419    }
420
421    ////////////////////////////////////////////////////////////////////////////
422
423    private static Color XYZToRGB(double X, double Y, double Z)
424    {
425      // Standards used Observer = 2, Illuminant = D65
426      // ref_X = 95.047, ref_Y = 100.000, ref_Z = 108.883
427
428      double var_X = X / 100.0;
429      double var_Y = Y / 100.0;
430      double var_Z = Z / 100.0;
431
432      double var_R = var_X * 3.2406 + var_Y * (-1.5372) + var_Z * (-0.4986);
433      double var_G = var_X * (-0.9689) + var_Y * 1.8758 + var_Z * 0.0415;
434      double var_B = var_X * 0.0557 + var_Y * (-0.2040) + var_Z * 1.0570;
435
436      if (var_R > 0.0031308)
437        var_R = 1.055 * (Math.Pow(var_R, 1 / 2.4)) - 0.055;
438      else
439        var_R = 12.92 * var_R;
440
441      if (var_G > 0.0031308)
442        var_G = 1.055 * (Math.Pow(var_G, 1 / 2.4)) - 0.055;
443      else
444        var_G = 12.92 * var_G;
445
446      if (var_B > 0.0031308)
447        var_B = 1.055 * (Math.Pow(var_B, 1 / 2.4)) - 0.055;
448      else
449        var_B = 12.92 * var_B;
450
451      int nRed = (int)(var_R * 256.0);
452      int nGreen = (int)(var_G * 256.0);
453      int nBlue = (int)(var_B * 256.0);
454
455      if (nRed < 0) nRed = 0;
456      else if (nRed > 255) nRed = 255;
457      if (nGreen < 0) nGreen = 0;
458      else if (nGreen > 255) nGreen = 255;
459      if (nBlue < 0) nBlue = 0;
460      else if (nBlue > 255) nBlue = 255;
461
462      return Color.FromArgb(nRed, nGreen, nBlue);
463    }
464
465    ///////////////////////////////////////////////////////////////////////////////
466    //
467    // The algorithms for these routines were taken from:
468    //     http://www.neuro.sfc.keio.ac.jp/~aly/polygon/info/color-space-faq.html
469    //
470    // RGB --> CMYK                              CMYK --> RGB
471    // ---------------------------------------   --------------------------------------------
472    // Black   = minimum(1-Red,1-Green,1-Blue)   Red   = 1-minimum(1,Cyan*(1-Black)+Black)
473    // Cyan    = (1-Red-Black)/(1-Black)         Green = 1-minimum(1,Magenta*(1-Black)+Black)
474    // Magenta = (1-Green-Black)/(1-Black)       Blue  = 1-minimum(1,Yellow*(1-Black)+Black)
475    // Yellow  = (1-Blue-Black)/(1-Black)
476    //
477
478    private static Color CMYKToRGB(byte c, byte m, byte y, byte k)
479    {
480      double C, M, Y, K;
481
482      double exC, exM, exY, exK;
483      double dMaxColours = Math.Pow(2, 8);
484
485      exC = (double)c;
486      exM = (double)m;
487      exY = (double)y;
488      exK = (double)k;
489
490      C = (1.0 - exC / dMaxColours);
491      M = (1.0 - exM / dMaxColours);
492      Y = (1.0 - exY / dMaxColours);
493      K = (1.0 - exK / dMaxColours);
494
495      int nRed = (int)((1.0 - (C * (1 - K) + K)) * 255);
496      int nGreen = (int)((1.0 - (M * (1 - K) + K)) * 255);
497      int nBlue = (int)((1.0 - (Y * (1 - K) + K)) * 255);
498
499      if (nRed < 0) nRed = 0;
500      else if (nRed > 255) nRed = 255;
501      if (nGreen < 0) nGreen = 0;
502      else if (nGreen > 255) nGreen = 255;
503      if (nBlue < 0) nBlue = 0;
504      else if (nBlue > 255) nBlue = 255;
505
506      return Color.FromArgb(nRed, nGreen, nBlue);
507    }
508  }
509}