You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

BitmapLuminanceSource.cs 11 kB

10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /*
  2. * Copyright 2012 ZXing.Net authors
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. using System;
  17. using System.Drawing.Imaging;
  18. using System.Drawing;
  19. using System.Runtime.InteropServices;
  20. namespace ZXing
  21. {
  22. public partial class BitmapLuminanceSource : BaseLuminanceSource
  23. {
  24. /// <summary>
  25. /// Initializes a new instance of the <see cref="BitmapLuminanceSource"/> class.
  26. /// </summary>
  27. /// <param name="width">The width.</param>
  28. /// <param name="height">The height.</param>
  29. protected BitmapLuminanceSource(int width, int height)
  30. : base(width, height)
  31. {
  32. }
  33. /// <summary>
  34. /// Initializes a new instance of the <see cref="BitmapLuminanceSource"/> class
  35. /// with the image of a Bitmap instance
  36. /// </summary>
  37. /// <param name="bitmap">The bitmap.</param>
  38. public BitmapLuminanceSource(Bitmap bitmap)
  39. : base(bitmap.Width, bitmap.Height)
  40. {
  41. var height = bitmap.Height;
  42. var width = bitmap.Width;
  43. // In order to measure pure decoding speed, we convert the entire image to a greyscale array
  44. // The underlying raster of image consists of bytes with the luminance values
  45. #if WindowsCE
  46. var data = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
  47. #else
  48. var data = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
  49. #endif
  50. try
  51. {
  52. var stride = Math.Abs(data.Stride);
  53. var pixelWidth = stride/width;
  54. if (pixelWidth > 4)
  55. {
  56. // old slow way for unsupported bit depth
  57. Color c;
  58. for (int y = 0; y < height; y++)
  59. {
  60. int offset = y*width;
  61. for (int x = 0; x < width; x++)
  62. {
  63. c = bitmap.GetPixel(x, y);
  64. luminances[offset + x] = (byte)((RChannelWeight * c.R + GChannelWeight * c.G + BChannelWeight * c.B) >> ChannelWeight);
  65. }
  66. }
  67. }
  68. else
  69. {
  70. var strideStep = data.Stride;
  71. var buffer = new byte[stride];
  72. var ptrInBitmap = data.Scan0;
  73. #if !WindowsCE
  74. // prepare palette for 1 and 8 bit indexed bitmaps
  75. var luminancePalette = new byte[bitmap.Palette.Entries.Length];
  76. for (var index = 0; index < bitmap.Palette.Entries.Length; index++)
  77. {
  78. var color = bitmap.Palette.Entries[index];
  79. luminancePalette[index] = (byte) ((RChannelWeight*color.R +
  80. GChannelWeight*color.G +
  81. BChannelWeight*color.B) >> ChannelWeight);
  82. }
  83. if (bitmap.PixelFormat == PixelFormat.Format32bppArgb ||
  84. bitmap.PixelFormat == PixelFormat.Format32bppPArgb)
  85. {
  86. pixelWidth = 40;
  87. }
  88. if ((int)bitmap.PixelFormat == 8207 ||
  89. (bitmap.Flags & (int)ImageFlags.ColorSpaceCmyk) == (int)ImageFlags.ColorSpaceCmyk)
  90. {
  91. pixelWidth = 41;
  92. }
  93. #endif
  94. for (int y = 0; y < height; y++)
  95. {
  96. // copy a scanline not the whole bitmap because of memory usage
  97. Marshal.Copy(ptrInBitmap, buffer, 0, stride);
  98. #if NET40
  99. ptrInBitmap = IntPtr.Add(ptrInBitmap, strideStep);
  100. #else
  101. ptrInBitmap = new IntPtr(ptrInBitmap.ToInt64() + strideStep);
  102. #endif
  103. var offset = y*width;
  104. switch (pixelWidth)
  105. {
  106. #if !WindowsCE
  107. case 0:
  108. for (int x = 0; x*8 < width; x++)
  109. {
  110. for (int subX = 0; subX < 8 && 8*x + subX < width; subX++)
  111. {
  112. var index = (buffer[x] >> (7 - subX)) & 1;
  113. luminances[offset + 8*x + subX] = luminancePalette[index];
  114. }
  115. }
  116. break;
  117. case 1:
  118. for (int x = 0; x < width; x++)
  119. {
  120. luminances[offset + x] = luminancePalette[buffer[x]];
  121. }
  122. break;
  123. #endif
  124. case 2:
  125. // should be RGB565 or RGB555, assume RGB565
  126. {
  127. var maxIndex = 2*width;
  128. for (int index = 0; index < maxIndex; index += 2)
  129. {
  130. var byte1 = buffer[index];
  131. var byte2 = buffer[index + 1];
  132. var b5 = byte1 & 0x1F;
  133. var g5 = (((byte1 & 0xE0) >> 5) | ((byte2 & 0x03) << 3)) & 0x1F;
  134. var r5 = (byte2 >> 2) & 0x1F;
  135. var r8 = (r5*527 + 23) >> 6;
  136. var g8 = (g5*527 + 23) >> 6;
  137. var b8 = (b5*527 + 23) >> 6;
  138. luminances[offset] = (byte)((RChannelWeight * r8 + GChannelWeight * g8 + BChannelWeight * b8) >> ChannelWeight);
  139. offset++;
  140. }
  141. }
  142. break;
  143. case 3:
  144. {
  145. var maxIndex = width*3;
  146. for (int x = 0; x < maxIndex; x += 3)
  147. {
  148. var luminance = (byte) ((BChannelWeight*buffer[x] +
  149. GChannelWeight*buffer[x + 1] +
  150. RChannelWeight*buffer[x + 2]) >> ChannelWeight);
  151. luminances[offset] = luminance;
  152. offset++;
  153. }
  154. }
  155. break;
  156. case 4:
  157. // 4 bytes without alpha channel value
  158. {
  159. var maxIndex = 4*width;
  160. for (int x = 0; x < maxIndex; x += 4)
  161. {
  162. var luminance = (byte) ((BChannelWeight*buffer[x] +
  163. GChannelWeight*buffer[x + 1] +
  164. RChannelWeight*buffer[x + 2]) >> ChannelWeight);
  165. luminances[offset] = luminance;
  166. offset++;
  167. }
  168. }
  169. break;
  170. case 40:
  171. // with alpha channel; some barcodes are completely black if you
  172. // only look at the r, g and b channel but the alpha channel controls
  173. // the view
  174. {
  175. var maxIndex = 4*width;
  176. for (int x = 0; x < maxIndex; x += 4)
  177. {
  178. var luminance = (byte) ((BChannelWeight*buffer[x] +
  179. GChannelWeight*buffer[x + 1] +
  180. RChannelWeight*buffer[x + 2]) >> ChannelWeight);
  181. // calculating the resulting luminance based upon a white background
  182. // var alpha = buffer[x * pixelWidth + 3] / 255.0;
  183. // luminance = (byte)(luminance * alpha + 255 * (1 - alpha));
  184. var alpha = buffer[x + 3];
  185. luminance = (byte) (((luminance*alpha) >> 8) + (255*(255 - alpha) >> 8) + 1);
  186. luminances[offset] = luminance;
  187. offset++;
  188. }
  189. }
  190. break;
  191. case 41:
  192. // CMYK color space
  193. {
  194. var maxIndex = 4 * width;
  195. for (int x = 0; x < maxIndex; x += 4)
  196. {
  197. var luminance = (byte) (255 - ((BChannelWeight*buffer[x] +
  198. GChannelWeight*buffer[x + 1] +
  199. RChannelWeight*buffer[x + 2]) >> ChannelWeight));
  200. // Ignore value of k at the moment
  201. luminances[offset] = luminance;
  202. offset++;
  203. }
  204. }
  205. break;
  206. default:
  207. throw new NotSupportedException();
  208. }
  209. }
  210. }
  211. }
  212. finally
  213. {
  214. bitmap.UnlockBits(data);
  215. }
  216. }
  217. /// <summary>
  218. /// Should create a new luminance source with the right class type.
  219. /// The method is used in methods crop and rotate.
  220. /// </summary>
  221. /// <param name="newLuminances">The new luminances.</param>
  222. /// <param name="width">The width.</param>
  223. /// <param name="height">The height.</param>
  224. /// <returns></returns>
  225. protected override LuminanceSource CreateLuminanceSource(byte[] newLuminances, int width, int height)
  226. {
  227. return new BitmapLuminanceSource(width, height) { luminances = newLuminances };
  228. }
  229. }
  230. }