Home | History | Annotate | Download | only in common
      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