/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. // This code contains code from SimplePsd class library by Igor Tolmachev.
  27. // http://www.codeproject.com/csharp/simplepsd.asp
  28. //
  29. /////////////////////////////////////////////////////////////////////////////////
  30. using System;
  31. using System.Collections.Generic;
  32. using System.Text;
  33. using System.Drawing;
  34. using System.Drawing.Imaging;
  35. namespace Photoshop
  36. {
  37. public class ImageDecoder
  38. {
  39. public ImageDecoder()
  40. {
  41. }
  42. ///////////////////////////////////////////////////////////////////////////
  43. #if !TEST
  44. private struct PixelData
  45. {
  46. public byte Blue;
  47. public byte Green;
  48. public byte Red;
  49. public byte Alpha;
  50. }
  51. #endif
  52. ///////////////////////////////////////////////////////////////////////////
  53. public static Bitmap DecodeImage(PsdFile psdFile)
  54. {
  55. Bitmap bitmap = new Bitmap(psdFile.Columns, psdFile.Rows, PixelFormat.Format32bppArgb);
  56. #if TEST
  57. for (int y = 0; y < psdFile.Rows; y++)
  58. {
  59. int rowIndex = y * psdFile.Columns;
  60. for (int x = 0; x < psdFile.Columns; x++)
  61. {
  62. int pos = rowIndex + x;
  63. Color pixelColor=GetColor(psdFile,pos);
  64. bitmap.SetPixel(x, y, pixelColor);
  65. }
  66. }
  67. #else
  68. Rectangle r = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
  69. BitmapData bd = bitmap.LockBits(r, ImageLockMode.ReadWrite, bitmap.PixelFormat);
  70. unsafe
  71. {
  72. byte* pCurrRowPixel = (byte*)bd.Scan0.ToPointer();
  73. for (int y = 0; y < psdFile.Rows; y++)
  74. {
  75. int rowIndex = y * psdFile.Columns;
  76. PixelData* pCurrPixel = (PixelData*)pCurrRowPixel;
  77. for (int x = 0; x < psdFile.Columns; x++)
  78. {
  79. int pos = rowIndex + x;
  80. Color pixelColor = GetColor(psdFile, pos);
  81. pCurrPixel->Alpha = 255;
  82. pCurrPixel->Red = pixelColor.R;
  83. pCurrPixel->Green = pixelColor.G;
  84. pCurrPixel->Blue = pixelColor.B;
  85. pCurrPixel += 1;
  86. }
  87. pCurrRowPixel += bd.Stride;
  88. }
  89. }
  90. bitmap.UnlockBits(bd);
  91. #endif
  92. return bitmap;
  93. }
  94. ///////////////////////////////////////////////////////////////////////////
  95. private static Color GetColor(PsdFile psdFile, int pos)
  96. {
  97. Color c = Color.White;
  98. switch (psdFile.ColorMode)
  99. {
  100. case PsdFile.ColorModes.RGB:
  101. c = Color.FromArgb(psdFile.ImageData[0][pos],
  102. psdFile.ImageData[1][pos],
  103. psdFile.ImageData[2][pos]);
  104. break;
  105. case PsdFile.ColorModes.CMYK:
  106. c = CMYKToRGB(psdFile.ImageData[0][pos],
  107. psdFile.ImageData[1][pos],
  108. psdFile.ImageData[2][pos],
  109. psdFile.ImageData[3][pos]);
  110. break;
  111. case PsdFile.ColorModes.Multichannel:
  112. c = CMYKToRGB(psdFile.ImageData[0][pos],
  113. psdFile.ImageData[1][pos],
  114. psdFile.ImageData[2][pos],
  115. 0);
  116. break;
  117. case PsdFile.ColorModes.Grayscale:
  118. case PsdFile.ColorModes.Duotone:
  119. c = Color.FromArgb(psdFile.ImageData[0][pos],
  120. psdFile.ImageData[0][pos],
  121. psdFile.ImageData[0][pos]);
  122. break;
  123. case PsdFile.ColorModes.Indexed:
  124. {
  125. int index = (int)psdFile.ImageData[0][pos];
  126. c = Color.FromArgb((int)psdFile.ColorModeData[index],
  127. psdFile.ColorModeData[index + 256],
  128. psdFile.ColorModeData[index + 2 * 256]);
  129. }
  130. break;
  131. case PsdFile.ColorModes.Lab:
  132. {
  133. c = LabToRGB(psdFile.ImageData[0][pos],
  134. psdFile.ImageData[1][pos],
  135. psdFile.ImageData[2][pos]);
  136. }
  137. break;
  138. }
  139. return c;
  140. }
  141. ///////////////////////////////////////////////////////////////////////////
  142. public static Bitmap DecodeImage(Layer layer)
  143. {
  144. if (layer.Rect.Width == 0 || layer.Rect.Height == 0)
  145. {
  146. return null;
  147. }
  148. Bitmap bitmap = new Bitmap(layer.Rect.Width, layer.Rect.Height, PixelFormat.Format32bppArgb);
  149. #if TEST
  150. for (int y = 0; y < layer.Rect.Height; y++)
  151. {
  152. int rowIndex = y * layer.Rect.Width;
  153. for (int x = 0; x < layer.Rect.Width; x++)
  154. {
  155. int pos = rowIndex + x;
  156. //Color pixelColor=GetColor(psdFile,pos);
  157. Color pixelColor = Color.FromArgb(x % 255, Color.ForestGreen);// 255, 128, 0);
  158. bitmap.SetPixel(x, y, pixelColor);
  159. }
  160. }
  161. #else
  162. Rectangle r = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
  163. BitmapData bd = bitmap.LockBits(r, ImageLockMode.ReadWrite, bitmap.PixelFormat);
  164. unsafe
  165. {
  166. byte* pCurrRowPixel = (byte*)bd.Scan0.ToPointer();
  167. for (int y = 0; y < layer.Rect.Height; y++)
  168. {
  169. int rowIndex = y * layer.Rect.Width;
  170. PixelData* pCurrPixel = (PixelData*)pCurrRowPixel;
  171. for (int x = 0; x < layer.Rect.Width; x++)
  172. {
  173. int pos = rowIndex + x;
  174. Color pixelColor = GetColor(layer, pos);
  175. if (layer.SortedChannels.ContainsKey(-2))
  176. {
  177. int maskAlpha = GetColor(layer.MaskData, x, y);
  178. int oldAlpha = pixelColor.A;
  179. int newAlpha = (oldAlpha * maskAlpha) / 255;
  180. pixelColor = Color.FromArgb(newAlpha,pixelColor);
  181. }
  182. pCurrPixel->Alpha = pixelColor.A;
  183. pCurrPixel->Red = pixelColor.R;
  184. pCurrPixel->Green = pixelColor.G;
  185. pCurrPixel->Blue = pixelColor.B;
  186. pCurrPixel += 1;
  187. }
  188. pCurrRowPixel += bd.Stride;
  189. }
  190. }
  191. bitmap.UnlockBits(bd);
  192. #endif
  193. return bitmap;
  194. }
  195. ///////////////////////////////////////////////////////////////////////////
  196. private static Color GetColor(Layer layer, int pos)
  197. {
  198. Color c = Color.White;
  199. switch (layer.PsdFile.ColorMode)
  200. {
  201. case PsdFile.ColorModes.RGB:
  202. c = Color.FromArgb(layer.SortedChannels[0].ImageData[pos],
  203. layer.SortedChannels[1].ImageData[pos],
  204. layer.SortedChannels[2].ImageData[pos]);
  205. break;
  206. case PsdFile.ColorModes.CMYK:
  207. c = CMYKToRGB(layer.SortedChannels[0].ImageData[pos],
  208. layer.SortedChannels[1].ImageData[pos],
  209. layer.SortedChannels[2].ImageData[pos],
  210. layer.SortedChannels[3].ImageData[pos]);
  211. break;
  212. case PsdFile.ColorModes.Multichannel:
  213. c = CMYKToRGB(layer.SortedChannels[0].ImageData[pos],
  214. layer.SortedChannels[1].ImageData[pos],
  215. layer.SortedChannels[2].ImageData[pos],
  216. 0);
  217. break;
  218. case PsdFile.ColorModes.Grayscale:
  219. case PsdFile.ColorModes.Duotone:
  220. c = Color.FromArgb(layer.SortedChannels[0].ImageData[pos],
  221. layer.SortedChannels[0].ImageData[pos],
  222. layer.SortedChannels[0].ImageData[pos]);
  223. break;
  224. case PsdFile.ColorModes.Indexed:
  225. {
  226. int index = (int)layer.SortedChannels[0].ImageData[pos];
  227. c = Color.FromArgb((int)layer.PsdFile.ColorModeData[index],
  228. layer.PsdFile.ColorModeData[index + 256],
  229. layer.PsdFile.ColorModeData[index + 2 * 256]);
  230. }
  231. break;
  232. case PsdFile.ColorModes.Lab:
  233. {
  234. c = LabToRGB(layer.SortedChannels[0].ImageData[pos],
  235. layer.SortedChannels[1].ImageData[pos],
  236. layer.SortedChannels[2].ImageData[pos]);
  237. }
  238. break;
  239. }
  240. if (layer.SortedChannels.ContainsKey(-1))
  241. c = Color.FromArgb(layer.SortedChannels[-1].ImageData[pos], c);
  242. return c;
  243. }
  244. ///////////////////////////////////////////////////////////////////////////
  245. private static int GetColor(Layer.Mask mask, int x, int y)
  246. {
  247. int c = 255;
  248. if (mask.PositionIsRelative)
  249. {
  250. x -= mask.Rect.X;
  251. y -= mask.Rect.Y;
  252. }
  253. else
  254. {
  255. x = (x + mask.Layer.Rect.X) - mask.Rect.X;
  256. y = (y + mask.Layer.Rect.Y) - mask.Rect.Y;
  257. }
  258. if (y >= 0 && y < mask.Rect.Height &&
  259. x >= 0 && x < mask.Rect.Width)
  260. {
  261. int pos = y * mask.Rect.Width + x;
  262. if (pos < mask.ImageData.Length)
  263. c = mask.ImageData[pos];
  264. else
  265. c = 255;
  266. }
  267. return c;
  268. }
  269. ///////////////////////////////////////////////////////////////////////////
  270. public static Bitmap DecodeImage(Layer.Mask mask)
  271. {
  272. Layer layer = mask.Layer;
  273. if (mask.Rect.Width == 0 || mask.Rect.Height == 0)
  274. {
  275. return null;
  276. }
  277. Bitmap bitmap = new Bitmap(mask.Rect.Width, mask.Rect.Height, PixelFormat.Format32bppArgb);
  278. Rectangle r = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
  279. BitmapData bd = bitmap.LockBits(r, ImageLockMode.ReadWrite, bitmap.PixelFormat);
  280. unsafe
  281. {
  282. byte* pCurrRowPixel = (byte*)bd.Scan0.ToPointer();
  283. for (int y = 0; y < mask.Rect.Height; y++)
  284. {
  285. int rowIndex = y * mask.Rect.Width;
  286. PixelData* pCurrPixel = (PixelData*)pCurrRowPixel;
  287. for (int x = 0; x < mask.Rect.Width; x++)
  288. {
  289. int pos = rowIndex + x;
  290. Color pixelColor = Color.FromArgb(mask.ImageData[pos], mask.ImageData[pos], mask.ImageData[pos]);
  291. pCurrPixel->Alpha = 255;
  292. pCurrPixel->Red = pixelColor.R;
  293. pCurrPixel->Green = pixelColor.G;
  294. pCurrPixel->Blue = pixelColor.B;
  295. pCurrPixel += 1;
  296. }
  297. pCurrRowPixel += bd.Stride;
  298. }
  299. }
  300. bitmap.UnlockBits(bd);
  301. return bitmap;
  302. }
  303. ///////////////////////////////////////////////////////////////////////////
  304. private static Color LabToRGB(byte lb, byte ab, byte bb)
  305. {
  306. double exL, exA, exB;
  307. exL = (double)lb;
  308. exA = (double)ab;
  309. exB = (double)bb;
  310. double L_coef, a_coef, b_coef;
  311. L_coef = 256.0 / 100.0;
  312. a_coef = 256.0 / 256.0;
  313. b_coef = 256.0 / 256.0;
  314. int L = (int)(exL / L_coef);
  315. int a = (int)(exA / a_coef - 128.0);
  316. int b = (int)(exB / b_coef - 128.0);
  317. // For the conversion we first convert values to XYZ and then to RGB
  318. // Standards used Observer = 2, Illuminant = D65
  319. const double ref_X = 95.047;
  320. const double ref_Y = 100.000;
  321. const double ref_Z = 108.883;
  322. double var_Y = ((double)L + 16.0) / 116.0;
  323. double var_X = (double)a / 500.0 + var_Y;
  324. double var_Z = var_Y - (double)b / 200.0;
  325. if (Math.Pow(var_Y, 3) > 0.008856)
  326. var_Y = Math.Pow(var_Y, 3);
  327. else
  328. var_Y = (var_Y - 16 / 116) / 7.787;
  329. if (Math.Pow(var_X, 3) > 0.008856)
  330. var_X = Math.Pow(var_X, 3);
  331. else
  332. var_X = (var_X - 16 / 116) / 7.787;
  333. if (Math.Pow(var_Z, 3) > 0.008856)
  334. var_Z = Math.Pow(var_Z, 3);
  335. else
  336. var_Z = (var_Z - 16 / 116) / 7.787;
  337. double X = ref_X * var_X;
  338. double Y = ref_Y * var_Y;
  339. double Z = ref_Z * var_Z;
  340. return XYZToRGB(X, Y, Z);
  341. }
  342. ////////////////////////////////////////////////////////////////////////////
  343. private static Color XYZToRGB(double X, double Y, double Z)
  344. {
  345. // Standards used Observer = 2, Illuminant = D65
  346. // ref_X = 95.047, ref_Y = 100.000, ref_Z = 108.883
  347. double var_X = X / 100.0;
  348. double var_Y = Y / 100.0;
  349. double var_Z = Z / 100.0;
  350. double var_R = var_X * 3.2406 + var_Y * (-1.5372) + var_Z * (-0.4986);
  351. double var_G = var_X * (-0.9689) + var_Y * 1.8758 + var_Z * 0.0415;
  352. double var_B = var_X * 0.0557 + var_Y * (-0.2040) + var_Z * 1.0570;
  353. if (var_R > 0.0031308)
  354. var_R = 1.055 * (Math.Pow(var_R, 1 / 2.4)) - 0.055;
  355. else
  356. var_R = 12.92 * var_R;
  357. if (var_G > 0.0031308)
  358. var_G = 1.055 * (Math.Pow(var_G, 1 / 2.4)) - 0.055;
  359. else
  360. var_G = 12.92 * var_G;
  361. if (var_B > 0.0031308)
  362. var_B = 1.055 * (Math.Pow(var_B, 1 / 2.4)) - 0.055;
  363. else
  364. var_B = 12.92 * var_B;
  365. int nRed = (int)(var_R * 256.0);
  366. int nGreen = (int)(var_G * 256.0);
  367. int nBlue = (int)(var_B * 256.0);
  368. if (nRed < 0) nRed = 0;
  369. else if (nRed > 255) nRed = 255;
  370. if (nGreen < 0) nGreen = 0;
  371. else if (nGreen > 255) nGreen = 255;
  372. if (nBlue < 0) nBlue = 0;
  373. else if (nBlue > 255) nBlue = 255;
  374. return Color.FromArgb(nRed, nGreen, nBlue);
  375. }
  376. ///////////////////////////////////////////////////////////////////////////////
  377. //
  378. // The algorithms for these routines were taken from:
  379. // http://www.neuro.sfc.keio.ac.jp/~aly/polygon/info/color-space-faq.html
  380. //
  381. // RGB --> CMYK CMYK --> RGB
  382. // --------------------------------------- --------------------------------------------
  383. // Black = minimum(1-Red,1-Green,1-Blue) Red = 1-minimum(1,Cyan*(1-Black)+Black)
  384. // Cyan = (1-Red-Black)/(1-Black) Green = 1-minimum(1,Magenta*(1-Black)+Black)
  385. // Magenta = (1-Green-Black)/(1-Black) Blue = 1-minimum(1,Yellow*(1-Black)+Black)
  386. // Yellow = (1-Blue-Black)/(1-Black)
  387. //
  388. private static Color CMYKToRGB(byte c, byte m, byte y, byte k)
  389. {
  390. double C, M, Y, K;
  391. double exC, exM, exY, exK;
  392. double dMaxColours = Math.Pow(2, 8);
  393. exC = (double)c;
  394. exM = (double)m;
  395. exY = (double)y;
  396. exK = (double)k;
  397. C = (1.0 - exC / dMaxColours);
  398. M = (1.0 - exM / dMaxColours);
  399. Y = (1.0 - exY / dMaxColours);
  400. K = (1.0 - exK / dMaxColours);
  401. int nRed = (int)((1.0 - (C * (1 - K) + K)) * 255);
  402. int nGreen = (int)((1.0 - (M * (1 - K) + K)) * 255);
  403. int nBlue = (int)((1.0 - (Y * (1 - K) + K)) * 255);
  404. if (nRed < 0) nRed = 0;
  405. else if (nRed > 255) nRed = 255;
  406. if (nGreen < 0) nGreen = 0;
  407. else if (nGreen > 255) nGreen = 255;
  408. if (nBlue < 0) nBlue = 0;
  409. else if (nBlue > 255) nBlue = 255;
  410. return Color.FromArgb(nRed, nGreen, nBlue);
  411. }
  412. }
  413. }