| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 | <?php/* * Copyright 2007 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */namespace Zxing\Qrcode\Decoder;use Zxing\ChecksumException;use Zxing\DecodeHintType;use Zxing\FormatException;use Zxing\Common\BitMatrix;use Zxing\Common\DecoderResult;use Zxing\Common\Reedsolomon\GenericGF;use Zxing\Common\Reedsolomon\ReedSolomonDecoder;use Zxing\Common\Reedsolomon\ReedSolomonException;/** * <p>The main class which implements QR Code decoding -- as opposed to locating and extracting * the QR Code from an image.</p> * * @author Sean Owen */final class Decoder {    private  $rsDecoder;    public function __construct() {        $this->rsDecoder = new ReedSolomonDecoder(GenericGF::$QR_CODE_FIELD_256);    }    function decode($variable, $hints=null){        if(is_array($variable)){            return $this->decodeImage($variable,$hints);        }elseif(is_object($variable)&&$variable instanceof BitMatrix){            return $this->decodeBits($variable,$hints);        }elseif(is_object($variable)&&$variable instanceof BitMatrixParser){            return $this->decodeParser($variable,$hints);        }else{            die('decode error Decoder.php');        }    }    /**     * <p>Convenience method that can decode a QR Code represented as a 2D array of booleans.     * "true" is taken to mean a black module.</p>     *     * @param image booleans representing white/black QR Code modules     * @param hints decoding hints that should be used to influence decoding     * @return text and bytes encoded within the QR Code     * @throws FormatException if the QR Code cannot be decoded     * @throws ChecksumException if error correction fails     */    public function decodeImage($image, $hints=null)    {        $dimension = count($image);        $bits = new BitMatrix($dimension);        for ($i = 0; $i < $dimension; $i++) {            for ($j = 0; $j < $dimension; $j++) {                if ($image[$i][$j]) {                    $bits->set($j, $i);                }            }        }        return $this->decode($bits, $hints);    }    /**     * <p>Decodes a QR Code represented as a {@link BitMatrix}. A 1 or "true" is taken to mean a black module.</p>     *     * @param bits booleans representing white/black QR Code modules     * @param hints decoding hints that should be used to influence decoding     * @return text and bytes encoded within the QR Code     * @throws FormatException if the QR Code cannot be decoded     * @throws ChecksumException if error correction fails     */    public function decodeBits($bits, $hints=null)    {// Construct a parser and read version, error-correction level        $parser = new BitMatrixParser($bits);        $fe = null;        $ce = null;        try {            return $this->decode($parser, $hints);        } catch (FormatException $e) {            $fe = $e;        } catch (ChecksumException $e) {            $ce = $e;        }        try {// Revert the bit matrix            $parser->remask();// Will be attempting a mirrored reading of the version and format info.            $parser->setMirror(true);// Preemptively read the version.            $parser->readVersion();// Preemptively read the format information.            $parser->readFormatInformation();            /*            * Since we're here, this means we have successfully detected some kind            * of version and format information when mirrored. This is a good sign,            * that the QR code may be mirrored, and we should try once more with a            * mirrored content.            */// Prepare for a mirrored reading.            $parser->mirror();            $result = $this->decode($parser, $hints);// Success! Notify the caller that the code was mirrored.            $result->setOther(new QRCodeDecoderMetaData(true));            return $result;        } catch (FormatException $e ) {// catch (FormatException | ChecksumException e) {// Throw the exception from the original reading            if ($fe != null) {                throw $fe;            }            if ($ce != null) {                throw $ce;            }            throw $e;        }    }    private function decodeParser($parser,$hints=null)    {        $version = $parser->readVersion();        $ecLevel = $parser->readFormatInformation()->getErrorCorrectionLevel();// Read codewords        $codewords = $parser->readCodewords();// Separate into data blocks        $dataBlocks = DataBlock::getDataBlocks($codewords, $version, $ecLevel);// Count total number of data bytes        $totalBytes = 0;        foreach ($dataBlocks as $dataBlock) {            $totalBytes += $dataBlock->getNumDataCodewords();        }        $resultBytes = fill_array(0,$totalBytes,0);        $resultOffset = 0;// Error-correct and copy data blocks together into a stream of bytes        foreach ($dataBlocks as $dataBlock) {            $codewordBytes = $dataBlock->getCodewords();            $numDataCodewords = $dataBlock->getNumDataCodewords();            $this->correctErrors($codewordBytes, $numDataCodewords);            for ($i = 0; $i < $numDataCodewords; $i++) {                $resultBytes[$resultOffset++] = $codewordBytes[$i];            }        }// Decode the contents of that stream of bytes        return DecodedBitStreamParser::decode($resultBytes, $version, $ecLevel, $hints);    }    /**     * <p>Given data and error-correction codewords received, possibly corrupted by errors, attempts to     * correct the errors in-place using Reed-Solomon error correction.</p>     *     * @param codewordBytes data and error correction codewords     * @param numDataCodewords number of codewords that are data bytes     * @throws ChecksumException if error correction fails     */    private function correctErrors(&$codewordBytes, $numDataCodewords){        $numCodewords = count($codewordBytes);// First read into an array of ints        $codewordsInts =fill_array(0,$numCodewords,0);        for ($i = 0; $i < $numCodewords; $i++) {            $codewordsInts[$i] = $codewordBytes[$i] & 0xFF;        }        $numECCodewords = count($codewordBytes)- $numDataCodewords;        try {            $this->rsDecoder->decode($codewordsInts, $numECCodewords);        } catch (ReedSolomonException $ignored) {            throw ChecksumException::getChecksumInstance();        }// Copy back into array of bytes -- only need to worry about the bytes that were data// We don't care about errors in the error-correction codewords        for ($i = 0; $i < $numDataCodewords; $i++) {            $codewordBytes[$i] =  $codewordsInts[$i];        }    }}
 |