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