|
|
<?php |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace Zxing\Qrcode; |
|
|
|
|
|
use Zxing\BinaryBitmap; |
|
|
use Zxing\ChecksumException; |
|
|
use Zxing\FormatException; |
|
|
use Zxing\NotFoundException; |
|
|
use Zxing\Reader; |
|
|
use Zxing\Result; |
|
|
use Zxing\Common\BitMatrix; |
|
|
use Zxing\Qrcode\Decoder\Decoder; |
|
|
use Zxing\Qrcode\Detector\Detector; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class QRCodeReader implements Reader |
|
|
{ |
|
|
private static $NO_POINTS = []; |
|
|
private $decoder; |
|
|
|
|
|
public function __construct() |
|
|
{ |
|
|
$this->decoder = new Decoder(); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function decode(BinaryBitmap $image, $hints = null) |
|
|
{ |
|
|
$decoderResult = null; |
|
|
if ($hints !== null && $hints['PURE_BARCODE']) { |
|
|
$bits = self::extractPureBits($image->getBlackMatrix()); |
|
|
$decoderResult = $this->decoder->decode($bits, $hints); |
|
|
$points = self::$NO_POINTS; |
|
|
} else { |
|
|
$detector = new Detector($image->getBlackMatrix()); |
|
|
$detectorResult = $detector->detect($hints); |
|
|
|
|
|
$decoderResult = $this->decoder->decode($detectorResult->getBits(), $hints); |
|
|
$points = $detectorResult->getPoints(); |
|
|
} |
|
|
$result = new Result($decoderResult->getText(), $decoderResult->getRawBytes(), $points, 'QR_CODE'); |
|
|
|
|
|
$byteSegments = $decoderResult->getByteSegments(); |
|
|
if ($byteSegments !== null) { |
|
|
$result->putMetadata('BYTE_SEGMENTS', $byteSegments); |
|
|
} |
|
|
$ecLevel = $decoderResult->getECLevel(); |
|
|
if ($ecLevel !== null) { |
|
|
$result->putMetadata('ERROR_CORRECTION_LEVEL', $ecLevel); |
|
|
} |
|
|
if ($decoderResult->hasStructuredAppend()) { |
|
|
$result->putMetadata( |
|
|
'STRUCTURED_APPEND_SEQUENCE',//ResultMetadataType.STRUCTURED_APPEND_SEQUENCE |
|
|
$decoderResult->getStructuredAppendSequenceNumber() |
|
|
); |
|
|
$result->putMetadata( |
|
|
'STRUCTURED_APPEND_PARITY',//ResultMetadataType.STRUCTURED_APPEND_PARITY |
|
|
$decoderResult->getStructuredAppendParity() |
|
|
); |
|
|
} |
|
|
|
|
|
return $result; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static function extractPureBits(BitMatrix $image) |
|
|
{ |
|
|
$leftTopBlack = $image->getTopLeftOnBit(); |
|
|
$rightBottomBlack = $image->getBottomRightOnBit(); |
|
|
if ($leftTopBlack === null || $rightBottomBlack == null) { |
|
|
throw NotFoundException::getNotFoundInstance(); |
|
|
} |
|
|
|
|
|
$moduleSize = self::moduleSize($leftTopBlack, $image); |
|
|
|
|
|
$top = $leftTopBlack[1]; |
|
|
$bottom = $rightBottomBlack[1]; |
|
|
$left = $leftTopBlack[0]; |
|
|
$right = $rightBottomBlack[0]; |
|
|
|
|
|
|
|
|
if ($left >= $right || $top >= $bottom) { |
|
|
throw NotFoundException::getNotFoundInstance(); |
|
|
} |
|
|
|
|
|
if ($bottom - $top != $right - $left) { |
|
|
|
|
|
|
|
|
$right = $left + ($bottom - $top); |
|
|
} |
|
|
|
|
|
$matrixWidth = round(($right - $left + 1) / $moduleSize); |
|
|
$matrixHeight = round(($bottom - $top + 1) / $moduleSize); |
|
|
if ($matrixWidth <= 0 || $matrixHeight <= 0) { |
|
|
throw NotFoundException::getNotFoundInstance(); |
|
|
} |
|
|
if ($matrixHeight != $matrixWidth) { |
|
|
|
|
|
throw NotFoundException::getNotFoundInstance(); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$nudge = (int)($moduleSize / 2.0); |
|
|
$top += $nudge; |
|
|
$left += $nudge; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$nudgedTooFarRight = $left + (int)(($matrixWidth - 1) * $moduleSize) - $right; |
|
|
if ($nudgedTooFarRight > 0) { |
|
|
if ($nudgedTooFarRight > $nudge) { |
|
|
|
|
|
throw NotFoundException::getNotFoundInstance(); |
|
|
} |
|
|
$left -= $nudgedTooFarRight; |
|
|
} |
|
|
|
|
|
$nudgedTooFarDown = $top + (int)(($matrixHeight - 1) * $moduleSize) - $bottom; |
|
|
if ($nudgedTooFarDown > 0) { |
|
|
if ($nudgedTooFarDown > $nudge) { |
|
|
|
|
|
throw NotFoundException::getNotFoundInstance(); |
|
|
} |
|
|
$top -= $nudgedTooFarDown; |
|
|
} |
|
|
|
|
|
|
|
|
$bits = new BitMatrix($matrixWidth, $matrixHeight); |
|
|
for ($y = 0; $y < $matrixHeight; $y++) { |
|
|
$iOffset = $top + (int)($y * $moduleSize); |
|
|
for ($x = 0; $x < $matrixWidth; $x++) { |
|
|
if ($image->get($left + (int)($x * $moduleSize), $iOffset)) { |
|
|
$bits->set($x, $y); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
return $bits; |
|
|
} |
|
|
|
|
|
private static function moduleSize($leftTopBlack, BitMatrix $image) |
|
|
{ |
|
|
$height = $image->getHeight(); |
|
|
$width = $image->getWidth(); |
|
|
$x = $leftTopBlack[0]; |
|
|
$y = $leftTopBlack[1]; |
|
|
|
|
|
|
|
|
$inBlack = true; |
|
|
$transitions = 0; |
|
|
while ($x < $width && $y < $height) { |
|
|
if ($inBlack != $image->get($x, $y)) { |
|
|
if (++$transitions == 5) { |
|
|
break; |
|
|
} |
|
|
$inBlack = !$inBlack; |
|
|
} |
|
|
$x++; |
|
|
$y++; |
|
|
} |
|
|
if ($x == $width || $y == $height) { |
|
|
throw NotFoundException::getNotFoundInstance(); |
|
|
} |
|
|
|
|
|
return ($x - $leftTopBlack[0]) / 7.0; |
|
|
} |
|
|
|
|
|
public function reset() |
|
|
{ |
|
|
|
|
|
} |
|
|
|
|
|
protected final function getDecoder() |
|
|
{ |
|
|
return $this->decoder; |
|
|
} |
|
|
} |
|
|
|