Merge XFA to PDFium master at 4dc95e7 on 10/28/2014
[pdfium.git] / xfa / src / fxbarcode / src / 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 \r
7 #include "barcode.h"\r
8 #include "include/BC_Binarizer.h"\r
9 #include "include/BC_LuminanceSource.h"\r
10 #include "include/BC_CommonBitMatrix.h"\r
11 #include "include/BC_CommonBitArray.h"\r
12 #include "include/BC_GlobalHistogramBinarizer.h"\r
13 const FX_INT32 LUMINANCE_BITS = 5;\r
14 const FX_INT32 LUMINANCE_SHIFT = 8 - LUMINANCE_BITS;\r
15 const FX_INT32 LUMINANCE_BUCKETS = 1 << LUMINANCE_BITS;\r
16 CBC_GlobalHistogramBinarizer::CBC_GlobalHistogramBinarizer(CBC_LuminanceSource *source): CBC_Binarizer(source)\r
17 {\r
18 }\r
19 CBC_GlobalHistogramBinarizer::~CBC_GlobalHistogramBinarizer()\r
20 {\r
21 }\r
22 CBC_CommonBitArray *CBC_GlobalHistogramBinarizer::GetBlackRow(FX_INT32 y, CBC_CommonBitArray *row, FX_INT32 &e)\r
23 {\r
24     CBC_LuminanceSource *source = GetLuminanceSource();\r
25     FX_INT32 width = source->GetWidth();\r
26     CBC_AutoPtr<CBC_CommonBitArray> result(FX_NEW CBC_CommonBitArray(width));\r
27     InitArrays(width);\r
28     CFX_ByteArray *localLuminances = source->GetRow(y, m_luminance, e);\r
29     if (e != BCExceptionNO) {\r
30         return result.release();\r
31     }\r
32     CFX_Int32Array localBuckets;\r
33     localBuckets.Copy(m_buckets);\r
34     FX_INT32 x;\r
35     for (x = 0; x < width; x++) {\r
36         FX_INT32 pixel = (*localLuminances)[x] & 0xff;\r
37         localBuckets[pixel >> LUMINANCE_SHIFT]++;\r
38     }\r
39     FX_INT32 blackPoint = EstimateBlackPoint(localBuckets, e);\r
40     if (e != BCExceptionNO) {\r
41         return result.release();\r
42     }\r
43     FX_INT32 left = (*localLuminances)[0] & 0xff;\r
44     FX_INT32 center = (*localLuminances)[1] & 0xff;\r
45     for (x = 1; x < width - 1; x++) {\r
46         FX_INT32 right = (*localLuminances)[x + 1] & 0xff;\r
47         FX_INT32 luminance = ((center << 2) - left - right) >> 1;\r
48         if (luminance < blackPoint) {\r
49             result->Set(x);\r
50         }\r
51         left = center;\r
52         center = right;\r
53     }\r
54     return  result.release();\r
55 }\r
56 CBC_CommonBitMatrix *CBC_GlobalHistogramBinarizer::GetBlackMatrix(FX_INT32 &e)\r
57 {\r
58     CBC_LuminanceSource *source = GetLuminanceSource();\r
59     FX_INT32 width = source->GetWidth();\r
60     FX_INT32 height = source->GetHeight();\r
61     CBC_CommonBitMatrix *BitMatrixTemp = FX_NEW CBC_CommonBitMatrix();\r
62     BitMatrixTemp->Init(width, height);\r
63     CBC_AutoPtr<CBC_CommonBitMatrix> matrix(BitMatrixTemp);\r
64     InitArrays(width);\r
65     CFX_Int32Array localBuckets;\r
66     localBuckets.Copy(m_buckets);\r
67     FX_INT32 y;\r
68     for (y = 1; y < 5; y++) {\r
69         FX_INT32 row = height * y / 5;\r
70         CFX_ByteArray *localLuminances = source->GetRow(row, m_luminance, e);\r
71         BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
72         FX_INT32 right = (width << 2) / 5;\r
73         FX_INT32 x;\r
74         for (x = width / 5; x < right; x++) {\r
75             FX_INT32 pixel = (*localLuminances)[x] & 0xff;\r
76             localBuckets[pixel >> LUMINANCE_SHIFT]++;\r
77         }\r
78     }\r
79     FX_INT32 blackPoint = EstimateBlackPoint(localBuckets, e);\r
80     BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
81     CBC_AutoPtr<CFX_ByteArray> localLuminances(source->GetMatrix());\r
82     for (y = 0; y < height; y++) {\r
83         FX_INT32 offset = y * width;\r
84         for (FX_INT32 x = 0; x < width; x++) {\r
85             FX_INT32 pixel = (*localLuminances)[offset + x] & 0xff;\r
86             if (pixel < blackPoint) {\r
87                 matrix->Set(x, y);\r
88             }\r
89         }\r
90     }\r
91     return matrix.release();\r
92 }\r
93 void CBC_GlobalHistogramBinarizer::InitArrays(FX_INT32 luminanceSize)\r
94 {\r
95     if(m_luminance.GetSize() < luminanceSize) {\r
96         m_luminance.SetSize(luminanceSize);\r
97     }\r
98     if(m_buckets.GetSize() <= 0) {\r
99         m_buckets.SetSize(LUMINANCE_BUCKETS);\r
100     } else {\r
101         FX_INT32 x;\r
102         for(x = 0; x < LUMINANCE_BUCKETS; x++) {\r
103             m_buckets[x] = 0;\r
104         }\r
105     }\r
106 }\r
107 FX_INT32 CBC_GlobalHistogramBinarizer::EstimateBlackPoint(CFX_Int32Array &buckets, FX_INT32 &e)\r
108 {\r
109     FX_INT32 numBuckets = buckets.GetSize();\r
110     FX_INT32 maxBucketCount = 0;\r
111     FX_INT32 firstPeak = 0;\r
112     FX_INT32 firstPeakSize = 0;\r
113     FX_INT32 x;\r
114     for (x = 0; x < numBuckets; x++) {\r
115         if (buckets[x] > firstPeakSize) {\r
116             firstPeak = x;\r
117             firstPeakSize = buckets[x];\r
118         }\r
119         if (buckets[x] > maxBucketCount) {\r
120             maxBucketCount = buckets[x];\r
121         }\r
122     }\r
123     FX_INT32 secondPeak = 0;\r
124     FX_INT32 secondPeakScore = 0;\r
125     for (x = 0; x < numBuckets; x++) {\r
126         FX_INT32 distanceToBiggest = x - firstPeak;\r
127         FX_INT32 score = buckets[x] * distanceToBiggest * distanceToBiggest;\r
128         if (score > secondPeakScore) {\r
129             secondPeak = x;\r
130             secondPeakScore = score;\r
131         }\r
132     }\r
133     if (firstPeak > secondPeak) {\r
134         FX_INT32 temp = firstPeak;\r
135         firstPeak = secondPeak;\r
136         secondPeak = temp;\r
137     }\r
138     if (secondPeak - firstPeak <= numBuckets >> 4) {\r
139         e = BCExceptionRead;\r
140         return 0;\r
141     }\r
142     FX_INT32 bestValley = secondPeak - 1;\r
143     FX_INT32 bestValleyScore = -1;\r
144     for (x = secondPeak - 1; x > firstPeak; x--) {\r
145         FX_INT32 fromFirst = x - firstPeak;\r
146         FX_INT32 score = fromFirst * fromFirst * (secondPeak - x) * (maxBucketCount - buckets[x]);\r
147         if (score > bestValleyScore) {\r
148             bestValley = x;\r
149             bestValleyScore = score;\r
150         }\r
151     }\r
152     return bestValley << LUMINANCE_SHIFT;\r
153 }\r