Committed C# port from Mohamad
[zxing.git] / csharp / BufferedImageMonochromeBitmapSource.cs
1 /*\r
2 * Licensed under the Apache License, Version 2.0 (the "License");\r
3 * you may not use this file except in compliance with the License.\r
4 * You may obtain a copy of the License at\r
5 *\r
6 *      http://www.apache.org/licenses/LICENSE-2.0\r
7 *\r
8 * Unless required by applicable law or agreed to in writing, software\r
9 * distributed under the License is distributed on an "AS IS" BASIS,\r
10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
11 * See the License for the specific language governing permissions and\r
12 * limitations under the License.\r
13 */\r
14 \r
15 using System;\r
16 using System.Drawing;\r
17 using MonochromeBitmapSource = com.google.zxing.MonochromeBitmapSource;\r
18 using BlackPointEstimationMethod = com.google.zxing.BlackPointEstimationMethod;\r
19 using BitArray = com.google.zxing.common.BitArray;\r
20 using BlackPointEstimator = com.google.zxing.common.BlackPointEstimator;\r
21 \r
22 \r
23 namespace com.google.zxing.client.j2se\r
24 {\r
25         \r
26         /// <summary> <p>An implementation based upon {@link BufferedImage}. This provides access to the\r
27         /// underlying image as if it were a monochrome image. Behind the scenes, it is evaluating\r
28         /// the luminance of the underlying image by retrieving its pixels' RGB values.</p>\r
29         /// \r
30         /// </summary>\r
31         /// <author>  srowen@google.com (Sean Owen), Daniel Switkin (dswitkin@google.com)\r
32         /// </author>\r
33         public sealed class BufferedImageMonochromeBitmapSource : MonochromeBitmapSource\r
34         {\r
35                 public bool iRotateSupported = false;\r
36 \r
37         public bool isRotateSupported() {\r
38             return iRotateSupported;\r
39         }\r
40 \r
41         public int getWidth() {\r
42             return (iRotateSupported ? image.Height : image.Width);\r
43         }\r
44 \r
45         public BlackPointEstimationMethod getLastEstimationMethod() {\r
46             return lastMethod;\r
47         }\r
48 \r
49         public int getHeight()\r
50         {\r
51             return (iRotateSupported ? image.Width : image.Height);\r
52         }\r
53 \r
54 \r
55         public MonochromeBitmapSource rotateCounterClockwise() {\r
56             return null;\r
57         }\r
58 \r
59         public BitArray getBlackColumn(int x, BitArray column, int startY, int getHeight) {\r
60             return null;\r
61         }\r
62                 \r
63                 //UPGRADE_NOTE: Final was removed from the declaration of 'image '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"\r
64                 private System.Drawing.Bitmap image;\r
65                 private int blackPoint;\r
66                 private BlackPointEstimationMethod lastMethod;\r
67                 private int lastArgument;\r
68                 \r
69                 private const int LUMINANCE_BITS = 5;\r
70                 //UPGRADE_NOTE: Final was removed from the declaration of 'LUMINANCE_SHIFT '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"\r
71                 private static readonly int LUMINANCE_SHIFT = 8 - LUMINANCE_BITS;\r
72                 //UPGRADE_NOTE: Final was removed from the declaration of 'LUMINANCE_BUCKETS '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"\r
73                 private static readonly int LUMINANCE_BUCKETS = 1 << LUMINANCE_BITS;\r
74                 \r
75                 public BufferedImageMonochromeBitmapSource(System.Drawing.Bitmap image, bool rotated)\r
76                 {\r
77                         this.image = image;\r
78                         blackPoint = 0x7F;\r
79                         lastMethod = null;\r
80                         lastArgument = 0;\r
81                         iRotateSupported = rotated;\r
82                 }\r
83                 \r
84                 public bool isBlack(int x, int y)\r
85                 {\r
86                         return (iRotateSupported ? computeRGBLuminance(image.GetPixel(y, x).ToArgb()) < blackPoint : computeRGBLuminance(image.GetPixel(x, y).ToArgb()) < blackPoint);\r
87                 }\r
88 \r
89                 int[] getRGB(int startx, int starty, int width)\r
90                 {\r
91                         int[] pixels = new int[width];\r
92                         for (int k = 0; k < width; k++)\r
93                         {\r
94                                 Color c = (iRotateSupported ? image.GetPixel(starty, startx + k) : image.GetPixel(startx + k, starty));\r
95                                 pixels[k] = ((int)c.R) << 16 | ((int)c.G) << 8 | ((int)c.B);\r
96                         }\r
97 \r
98                         return pixels;\r
99                 }\r
100 \r
101                 public BitArray getBlackRow(int y, BitArray row, int startX, int getWidth)\r
102                 {\r
103                         if (row == null)\r
104                         {\r
105                                 row = new BitArray(getWidth);\r
106                         }\r
107                         else\r
108                         {\r
109                                 row.clear();\r
110                         }\r
111                         //UPGRADE_ISSUE: Method 'java.awt.image.BufferedImage.getRGB' was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1000_javaawtimageBufferedImagegetRGB_int_int_int_int_int[]_int_int'"\r
112                         int[] pixelRow = getRGB(startX, y, getWidth);\r
113                         for (int i = 0; i < getWidth; i++)\r
114                         {\r
115                                 if (computeRGBLuminance(pixelRow[i]) < blackPoint)\r
116                                 {\r
117                                         row.set(i);\r
118                                 }\r
119                         }\r
120                         return row;\r
121                 }\r
122                 \r
123                 public void  estimateBlackPoint(BlackPointEstimationMethod method, int argument)\r
124                 {\r
125                         if (!method.Equals(lastMethod) || argument != lastArgument)\r
126                         {\r
127                 int width = getWidth();\r
128                 int height = getHeight();\r
129                                 int[] histogram = new int[LUMINANCE_BUCKETS];\r
130                                 float biasTowardsWhite = 1.0f;\r
131                                 if (method.Equals(BlackPointEstimationMethod.TWO_D_SAMPLING))\r
132                                 {\r
133                                         int minDimension = width < height?width:height;\r
134                                         int startI = height == minDimension?0:(height - width) >> 1;\r
135                                         int startJ = width == minDimension?0:(width - height) >> 1;\r
136                                         for (int n = 0; n < minDimension; n++)\r
137                                         {\r
138                                                 int pixel = (iRotateSupported ? image.GetPixel(startI + n, startJ + n).ToArgb() : image.GetPixel(startJ + n, startI + n).ToArgb());\r
139                                                 histogram[computeRGBLuminance(pixel) >> LUMINANCE_SHIFT]++;\r
140                                         }\r
141                                 }\r
142                                 else if (method.Equals(BlackPointEstimationMethod.ROW_SAMPLING))\r
143                                 {\r
144                                         if (argument < 0 || argument >= height)\r
145                                         {\r
146                                                 throw new System.ArgumentException("Row is not within the image: " + argument);\r
147                                         }\r
148                                         biasTowardsWhite = 2.0f;\r
149                                         int[] rgbArray = getRGB(0, argument, width);\r
150                                         for (int x = 0; x < width; x++)\r
151                                         {\r
152                                                 int l = computeRGBLuminance(rgbArray[x]);\r
153                                                 histogram[l >> LUMINANCE_SHIFT]++;\r
154                                         }\r
155                                 }\r
156                                 else\r
157                                 {\r
158                                         //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Object.toString' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'"\r
159                                         throw new System.ArgumentException("Unknown method: " + method);\r
160                                 }\r
161                                 blackPoint = BlackPointEstimator.estimate(histogram) << LUMINANCE_SHIFT;\r
162                                 lastMethod = method;\r
163                                 lastArgument = argument;\r
164                         }\r
165                 }\r
166                 \r
167                 /// <summary> Extracts luminance from a pixel from this source. By default, the source is assumed to use RGB,\r
168                 /// so this implementation computes luminance is a function of a red, green and blue components as\r
169                 /// follows:\r
170                 /// \r
171                 /// <code>Y = 0.299R + 0.587G + 0.114B</code>\r
172                 /// \r
173                 /// where R, G, and B are values in [0,1].\r
174                 /// </summary>\r
175                 private static int computeRGBLuminance(int pixel)\r
176                 {\r
177                         // Coefficients add up to 1024 to make the divide into a fast shift\r
178                         return (306 * ((pixel >> 16) & 0xFF) + 601 * ((pixel >> 8) & 0xFF) + 117 * (pixel & 0xFF)) >> 10;\r
179                 }\r
180         }\r
181 }