Merge to XFA: Use stdint.h types throughout PDFium.
[pdfium.git] / xfa / src / fxbarcode / common / BC_GlobalHistogramBinarizer.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.\r
2 // Use of this source code is governed by a BSD-style license that can be\r
3 // found in the LICENSE file.\r
4 \r
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\r
6 // Original code is licensed as follows:\r
7 /*\r
8  * Copyright 2009 ZXing authors\r
9  *\r
10  * Licensed under the Apache License, Version 2.0 (the "License");\r
11  * you may not use this file except in compliance with the License.\r
12  * You may obtain a copy of the License at\r
13  *\r
14  *      http://www.apache.org/licenses/LICENSE-2.0\r
15  *\r
16  * Unless required by applicable law or agreed to in writing, software\r
17  * distributed under the License is distributed on an "AS IS" BASIS,\r
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
19  * See the License for the specific language governing permissions and\r
20  * limitations under the License.\r
21  */\r
22 \r
23 #include "../barcode.h"\r
24 #include "../BC_Binarizer.h"\r
25 #include "../BC_LuminanceSource.h"\r
26 #include "BC_CommonBitMatrix.h"\r
27 #include "BC_CommonBitArray.h"\r
28 #include "BC_GlobalHistogramBinarizer.h"\r
29 const int32_t LUMINANCE_BITS = 5;\r
30 const int32_t LUMINANCE_SHIFT = 8 - LUMINANCE_BITS;\r
31 const int32_t LUMINANCE_BUCKETS = 1 << LUMINANCE_BITS;\r
32 CBC_GlobalHistogramBinarizer::CBC_GlobalHistogramBinarizer(CBC_LuminanceSource *source): CBC_Binarizer(source)\r
33 {\r
34 }\r
35 CBC_GlobalHistogramBinarizer::~CBC_GlobalHistogramBinarizer()\r
36 {\r
37 }\r
38 CBC_CommonBitArray *CBC_GlobalHistogramBinarizer::GetBlackRow(int32_t y, CBC_CommonBitArray *row, int32_t &e)\r
39 {\r
40     CBC_LuminanceSource *source = GetLuminanceSource();\r
41     int32_t width = source->GetWidth();\r
42     CBC_AutoPtr<CBC_CommonBitArray> result(FX_NEW CBC_CommonBitArray(width));\r
43     InitArrays(width);\r
44     CFX_ByteArray *localLuminances = source->GetRow(y, m_luminance, e);\r
45     if (e != BCExceptionNO) {\r
46         return result.release();\r
47     }\r
48     CFX_Int32Array localBuckets;\r
49     localBuckets.Copy(m_buckets);\r
50     int32_t x;\r
51     for (x = 0; x < width; x++) {\r
52         int32_t pixel = (*localLuminances)[x] & 0xff;\r
53         localBuckets[pixel >> LUMINANCE_SHIFT]++;\r
54     }\r
55     int32_t blackPoint = EstimateBlackPoint(localBuckets, e);\r
56     if (e != BCExceptionNO) {\r
57         return result.release();\r
58     }\r
59     int32_t left = (*localLuminances)[0] & 0xff;\r
60     int32_t center = (*localLuminances)[1] & 0xff;\r
61     for (x = 1; x < width - 1; x++) {\r
62         int32_t right = (*localLuminances)[x + 1] & 0xff;\r
63         int32_t luminance = ((center << 2) - left - right) >> 1;\r
64         if (luminance < blackPoint) {\r
65             result->Set(x);\r
66         }\r
67         left = center;\r
68         center = right;\r
69     }\r
70     return  result.release();\r
71 }\r
72 CBC_CommonBitMatrix *CBC_GlobalHistogramBinarizer::GetBlackMatrix(int32_t &e)\r
73 {\r
74     CBC_LuminanceSource *source = GetLuminanceSource();\r
75     int32_t width = source->GetWidth();\r
76     int32_t height = source->GetHeight();\r
77     CBC_CommonBitMatrix *BitMatrixTemp = FX_NEW CBC_CommonBitMatrix();\r
78     BitMatrixTemp->Init(width, height);\r
79     CBC_AutoPtr<CBC_CommonBitMatrix> matrix(BitMatrixTemp);\r
80     InitArrays(width);\r
81     CFX_Int32Array localBuckets;\r
82     localBuckets.Copy(m_buckets);\r
83     int32_t y;\r
84     for (y = 1; y < 5; y++) {\r
85         int32_t row = height * y / 5;\r
86         CFX_ByteArray *localLuminances = source->GetRow(row, m_luminance, e);\r
87         BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
88         int32_t right = (width << 2) / 5;\r
89         int32_t x;\r
90         for (x = width / 5; x < right; x++) {\r
91             int32_t pixel = (*localLuminances)[x] & 0xff;\r
92             localBuckets[pixel >> LUMINANCE_SHIFT]++;\r
93         }\r
94     }\r
95     int32_t blackPoint = EstimateBlackPoint(localBuckets, e);\r
96     BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
97     CBC_AutoPtr<CFX_ByteArray> localLuminances(source->GetMatrix());\r
98     for (y = 0; y < height; y++) {\r
99         int32_t offset = y * width;\r
100         for (int32_t x = 0; x < width; x++) {\r
101             int32_t pixel = (*localLuminances)[offset + x] & 0xff;\r
102             if (pixel < blackPoint) {\r
103                 matrix->Set(x, y);\r
104             }\r
105         }\r
106     }\r
107     return matrix.release();\r
108 }\r
109 void CBC_GlobalHistogramBinarizer::InitArrays(int32_t luminanceSize)\r
110 {\r
111     if(m_luminance.GetSize() < luminanceSize) {\r
112         m_luminance.SetSize(luminanceSize);\r
113     }\r
114     if(m_buckets.GetSize() <= 0) {\r
115         m_buckets.SetSize(LUMINANCE_BUCKETS);\r
116     } else {\r
117         int32_t x;\r
118         for(x = 0; x < LUMINANCE_BUCKETS; x++) {\r
119             m_buckets[x] = 0;\r
120         }\r
121     }\r
122 }\r
123 int32_t CBC_GlobalHistogramBinarizer::EstimateBlackPoint(CFX_Int32Array &buckets, int32_t &e)\r
124 {\r
125     int32_t numBuckets = buckets.GetSize();\r
126     int32_t maxBucketCount = 0;\r
127     int32_t firstPeak = 0;\r
128     int32_t firstPeakSize = 0;\r
129     int32_t x;\r
130     for (x = 0; x < numBuckets; x++) {\r
131         if (buckets[x] > firstPeakSize) {\r
132             firstPeak = x;\r
133             firstPeakSize = buckets[x];\r
134         }\r
135         if (buckets[x] > maxBucketCount) {\r
136             maxBucketCount = buckets[x];\r
137         }\r
138     }\r
139     int32_t secondPeak = 0;\r
140     int32_t secondPeakScore = 0;\r
141     for (x = 0; x < numBuckets; x++) {\r
142         int32_t distanceToBiggest = x - firstPeak;\r
143         int32_t score = buckets[x] * distanceToBiggest * distanceToBiggest;\r
144         if (score > secondPeakScore) {\r
145             secondPeak = x;\r
146             secondPeakScore = score;\r
147         }\r
148     }\r
149     if (firstPeak > secondPeak) {\r
150         int32_t temp = firstPeak;\r
151         firstPeak = secondPeak;\r
152         secondPeak = temp;\r
153     }\r
154     if (secondPeak - firstPeak <= numBuckets >> 4) {\r
155         e = BCExceptionRead;\r
156         return 0;\r
157     }\r
158     int32_t bestValley = secondPeak - 1;\r
159     int32_t bestValleyScore = -1;\r
160     for (x = secondPeak - 1; x > firstPeak; x--) {\r
161         int32_t fromFirst = x - firstPeak;\r
162         int32_t score = fromFirst * fromFirst * (secondPeak - x) * (maxBucketCount - buckets[x]);\r
163         if (score > bestValleyScore) {\r
164             bestValley = x;\r
165             bestValleyScore = score;\r
166         }\r
167     }\r
168     return bestValley << LUMINANCE_SHIFT;\r
169 }\r