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 2010 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/common/BC_WhiteRectangleDetector.h" 25 #include "xfa/src/fxbarcode/common/BC_CommonBitMatrix.h" 26 #include "xfa/src/fxbarcode/BC_ResultPoint.h" 27 const int32_t CBC_WhiteRectangleDetector::INIT_SIZE = 30; 28 const int32_t CBC_WhiteRectangleDetector::CORR = 1; 29 CBC_WhiteRectangleDetector::CBC_WhiteRectangleDetector( 30 CBC_CommonBitMatrix* image) { 31 m_image = image; 32 m_height = image->GetHeight(); 33 m_width = image->GetWidth(); 34 m_leftInit = (m_width - INIT_SIZE) >> 1; 35 m_rightInit = (m_width + INIT_SIZE) >> 1; 36 m_upInit = (m_height - INIT_SIZE) >> 1; 37 m_downInit = (m_height + INIT_SIZE) >> 1; 38 } 39 void CBC_WhiteRectangleDetector::Init(int32_t& e) { 40 if (m_upInit < 0 || m_leftInit < 0 || m_downInit >= m_height || 41 m_rightInit >= m_width) { 42 e = BCExceptionNotFound; 43 BC_EXCEPTION_CHECK_ReturnVoid(e); 44 } 45 } 46 CBC_WhiteRectangleDetector::CBC_WhiteRectangleDetector( 47 CBC_CommonBitMatrix* image, 48 int32_t initSize, 49 int32_t x, 50 int32_t y) { 51 m_image = image; 52 m_height = image->GetHeight(); 53 m_width = image->GetWidth(); 54 int32_t halfsize = initSize >> 1; 55 m_leftInit = x - halfsize; 56 m_rightInit = x + halfsize; 57 m_upInit = y - halfsize; 58 m_downInit = y + halfsize; 59 } 60 CBC_WhiteRectangleDetector::~CBC_WhiteRectangleDetector() {} 61 CFX_PtrArray* CBC_WhiteRectangleDetector::Detect(int32_t& e) { 62 int32_t left = m_leftInit; 63 int32_t right = m_rightInit; 64 int32_t up = m_upInit; 65 int32_t down = m_downInit; 66 FX_BOOL sizeExceeded = FALSE; 67 FX_BOOL aBlackPointFoundOnBorder = TRUE; 68 FX_BOOL atLeastOneBlackPointFoundOnBorder = FALSE; 69 while (aBlackPointFoundOnBorder) { 70 aBlackPointFoundOnBorder = FALSE; 71 FX_BOOL rightBorderNotWhite = TRUE; 72 while (rightBorderNotWhite && right < m_width) { 73 rightBorderNotWhite = ContainsBlackPoint(up, down, right, FALSE); 74 if (rightBorderNotWhite) { 75 right++; 76 aBlackPointFoundOnBorder = TRUE; 77 } 78 } 79 if (right >= m_width) { 80 sizeExceeded = TRUE; 81 break; 82 } 83 FX_BOOL bottomBorderNotWhite = TRUE; 84 while (bottomBorderNotWhite && down < m_height) { 85 bottomBorderNotWhite = ContainsBlackPoint(left, right, down, TRUE); 86 if (bottomBorderNotWhite) { 87 down++; 88 aBlackPointFoundOnBorder = TRUE; 89 } 90 } 91 if (down >= m_height) { 92 sizeExceeded = TRUE; 93 break; 94 } 95 FX_BOOL leftBorderNotWhite = TRUE; 96 while (leftBorderNotWhite && left >= 0) { 97 leftBorderNotWhite = ContainsBlackPoint(up, down, left, FALSE); 98 if (leftBorderNotWhite) { 99 left--; 100 aBlackPointFoundOnBorder = TRUE; 101 } 102 } 103 if (left < 0) { 104 sizeExceeded = TRUE; 105 break; 106 } 107 FX_BOOL topBorderNotWhite = TRUE; 108 while (topBorderNotWhite && up >= 0) { 109 topBorderNotWhite = ContainsBlackPoint(left, right, up, TRUE); 110 if (topBorderNotWhite) { 111 up--; 112 aBlackPointFoundOnBorder = TRUE; 113 } 114 } 115 if (up < 0) { 116 sizeExceeded = TRUE; 117 break; 118 } 119 if (aBlackPointFoundOnBorder) { 120 atLeastOneBlackPointFoundOnBorder = TRUE; 121 } 122 } 123 if (!sizeExceeded && atLeastOneBlackPointFoundOnBorder) { 124 int32_t maxSize = right - left; 125 CBC_AutoPtr<CBC_ResultPoint> z(NULL); 126 for (int32_t i = 1; i < maxSize; i++) { 127 z = CBC_AutoPtr<CBC_ResultPoint>( 128 GetBlackPointOnSegment((FX_FLOAT)left, (FX_FLOAT)(down - i), 129 (FX_FLOAT)(left + i), (FX_FLOAT)(down))); 130 if (z.get() != NULL) { 131 break; 132 } 133 } 134 if (z.get() == NULL) { 135 e = BCExceptionNotFound; 136 BC_EXCEPTION_CHECK_ReturnValue(e, NULL); 137 } 138 CBC_AutoPtr<CBC_ResultPoint> t(NULL); 139 for (int32_t j = 1; j < maxSize; j++) { 140 t = CBC_AutoPtr<CBC_ResultPoint>( 141 GetBlackPointOnSegment((FX_FLOAT)left, (FX_FLOAT)(up + j), 142 (FX_FLOAT)(left + j), (FX_FLOAT)up)); 143 if (t.get() != NULL) { 144 break; 145 } 146 } 147 if (t.get() == NULL) { 148 e = BCExceptionNotFound; 149 BC_EXCEPTION_CHECK_ReturnValue(e, NULL); 150 } 151 CBC_AutoPtr<CBC_ResultPoint> x(NULL); 152 for (int32_t k = 1; k < maxSize; k++) { 153 x = CBC_AutoPtr<CBC_ResultPoint>( 154 GetBlackPointOnSegment((FX_FLOAT)right, (FX_FLOAT)(up + k), 155 (FX_FLOAT)(right - k), (FX_FLOAT)up)); 156 if (x.get() != NULL) { 157 break; 158 } 159 } 160 if (x.get() == NULL) { 161 e = BCExceptionNotFound; 162 BC_EXCEPTION_CHECK_ReturnValue(e, NULL); 163 } 164 CBC_AutoPtr<CBC_ResultPoint> y(NULL); 165 for (int32_t m = 1; m < maxSize; m++) { 166 y = CBC_AutoPtr<CBC_ResultPoint>( 167 GetBlackPointOnSegment((FX_FLOAT)right, (FX_FLOAT)(down - m), 168 (FX_FLOAT)(right - m), (FX_FLOAT)down)); 169 if (y.get() != NULL) { 170 break; 171 } 172 } 173 if (y.get() == NULL) { 174 e = BCExceptionNotFound; 175 BC_EXCEPTION_CHECK_ReturnValue(e, NULL); 176 } 177 return CenterEdges(y.get(), z.get(), x.get(), t.get()); 178 } else { 179 e = BCExceptionNotFound; 180 BC_EXCEPTION_CHECK_ReturnValue(e, NULL); 181 } 182 return NULL; 183 } 184 int32_t CBC_WhiteRectangleDetector::Round(FX_FLOAT d) { 185 return (int32_t)(d + 0.5f); 186 } 187 CBC_ResultPoint* CBC_WhiteRectangleDetector::GetBlackPointOnSegment( 188 FX_FLOAT aX, 189 FX_FLOAT aY, 190 FX_FLOAT bX, 191 FX_FLOAT bY) { 192 int32_t dist = DistanceL2(aX, aY, bX, bY); 193 float xStep = (bX - aX) / dist; 194 float yStep = (bY - aY) / dist; 195 for (int32_t i = 0; i < dist; i++) { 196 int32_t x = Round(aX + i * xStep); 197 int32_t y = Round(aY + i * yStep); 198 if (m_image->Get(x, y)) { 199 return new CBC_ResultPoint((FX_FLOAT)x, (FX_FLOAT)y); 200 } 201 } 202 return NULL; 203 } 204 int32_t CBC_WhiteRectangleDetector::DistanceL2(FX_FLOAT aX, 205 FX_FLOAT aY, 206 FX_FLOAT bX, 207 FX_FLOAT bY) { 208 float xDiff = aX - bX; 209 float yDiff = aY - bY; 210 return Round((float)sqrt(xDiff * xDiff + yDiff * yDiff)); 211 } 212 CFX_PtrArray* CBC_WhiteRectangleDetector::CenterEdges(CBC_ResultPoint* y, 213 CBC_ResultPoint* z, 214 CBC_ResultPoint* x, 215 CBC_ResultPoint* t) { 216 float yi = y->GetX(); 217 float yj = y->GetY(); 218 float zi = z->GetX(); 219 float zj = z->GetY(); 220 float xi = x->GetX(); 221 float xj = x->GetY(); 222 float ti = t->GetX(); 223 float tj = t->GetY(); 224 if (yi < m_width / 2) { 225 CFX_PtrArray* result = new CFX_PtrArray; 226 result->SetSize(4); 227 (*result)[0] = new CBC_ResultPoint(ti - CORR, tj + CORR); 228 (*result)[1] = new CBC_ResultPoint(zi + CORR, zj + CORR); 229 (*result)[2] = new CBC_ResultPoint(xi - CORR, xj - CORR); 230 (*result)[3] = new CBC_ResultPoint(yi + CORR, yj - CORR); 231 return result; 232 } else { 233 CFX_PtrArray* result = new CFX_PtrArray; 234 result->SetSize(4); 235 (*result)[0] = new CBC_ResultPoint(ti + CORR, tj + CORR); 236 (*result)[1] = new CBC_ResultPoint(zi + CORR, zj - CORR); 237 (*result)[2] = new CBC_ResultPoint(xi - CORR, xj + CORR); 238 (*result)[3] = new CBC_ResultPoint(yi - CORR, yj - CORR); 239 return result; 240 } 241 } 242 FX_BOOL CBC_WhiteRectangleDetector::ContainsBlackPoint(int32_t a, 243 int32_t b, 244 int32_t fixed, 245 FX_BOOL horizontal) { 246 if (horizontal) { 247 for (int32_t x = a; x <= b; x++) { 248 if (m_image->Get(x, fixed)) { 249 return TRUE; 250 } 251 } 252 } else { 253 for (int32_t y = a; y <= b; y++) { 254 if (m_image->Get(fixed, y)) { 255 return TRUE; 256 } 257 } 258 } 259 return FALSE; 260 } 261