:octocat: integrate reader into QRCode, extract LuminanceSourceInterface

This commit is contained in:
codemasher
2021-11-19 15:49:53 +01:00
parent 9bfe5e1880
commit 5e9cf0047e
9 changed files with 170 additions and 158 deletions
+2 -2
View File
@@ -45,12 +45,12 @@ final class Binarizer{
private const LUMINANCE_SHIFT = 3;
private const LUMINANCE_BUCKETS = 32;
private LuminanceSource $source;
private LuminanceSourceInterface $source;
/**
*
*/
public function __construct(LuminanceSource $source){
public function __construct(LuminanceSourceInterface $source){
$this->source = $source;
}
+2 -2
View File
@@ -31,12 +31,12 @@ final class Decoder{
* <p>Decodes a QR Code represented as a {@link \chillerlan\QRCode\Decoder\BitMatrix}.
* A 1 or "true" is taken to mean a black module.</p>
*
* @param \chillerlan\QRCode\Decoder\LuminanceSource $source
* @param \chillerlan\QRCode\Decoder\LuminanceSourceInterface $source
*
* @return \chillerlan\QRCode\Decoder\DecoderResult text and bytes encoded within the QR Code
* @throws \Exception if the QR Code cannot be decoded
*/
public function decode(LuminanceSource $source):DecoderResult{
public function decode(LuminanceSourceInterface $source):DecoderResult{
$matrix = (new Binarizer($source))->getBlackMatrix();
$bitMatrix = (new Detector($matrix))->detect();
+16 -3
View File
@@ -14,14 +14,15 @@
namespace chillerlan\QRCode\Decoder;
use InvalidArgumentException;
use function get_resource_type, imagecolorat, imagecolorsforindex, imagesx, imagesy, is_resource;
use function file_get_contents, get_resource_type, imagecolorat, imagecolorsforindex,
imagecreatefromstring, imagesx, imagesy, is_resource;
use const PHP_MAJOR_VERSION;
/**
* This class is used to help decode images from files which arrive as GD Resource
* It does not support rotation.
*/
final class GDLuminanceSource extends LuminanceSource{
final class GDLuminanceSource extends LuminanceSourceAbstract{
/**
* @var resource|\GdImage
@@ -40,7 +41,7 @@ final class GDLuminanceSource extends LuminanceSource{
/** @noinspection PhpFullyQualifiedNameUsageInspection */
if(
(PHP_MAJOR_VERSION >= 8 && !$gdImage instanceof \GdImage)
|| (PHP_MAJOR_VERSION < 8 && (!is_resource($gdImage) || get_resource_type($gdImage) !== 'gd'))
|| (!is_resource($gdImage) || get_resource_type($gdImage) !== 'gd')
){
throw new InvalidArgumentException('Invalid GD image source.');
}
@@ -66,4 +67,16 @@ final class GDLuminanceSource extends LuminanceSource{
}
}
/** @inheritDoc */
public static function fromFile(string $path):self{
$path = self::checkFile($path);
return new self(imagecreatefromstring(file_get_contents($path)));
}
/** @inheritDoc */
public static function fromBlob(string $blob):self{
return new self(imagecreatefromstring($blob));
}
}
+16 -1
View File
@@ -20,7 +20,7 @@ use function count;
* This class is used to help decode images from files which arrive as Imagick Resource
* It does not support rotation.
*/
final class IMagickLuminanceSource extends LuminanceSource{
final class IMagickLuminanceSource extends LuminanceSourceAbstract{
private Imagick $imagick;
@@ -53,4 +53,19 @@ final class IMagickLuminanceSource extends LuminanceSource{
}
}
/** @inheritDoc */
public static function fromFile(string $path):self{
$path = self::checkFile($path);
return new self(new Imagick($path));
}
/** @inheritDoc */
public static function fromBlob(string $blob):self{
$im = new Imagick;
$im->readImageBlob($blob);
return new self($im);
}
}
@@ -1,6 +1,6 @@
<?php
/**
* Class LuminanceSource
* Class LuminanceSourceAbstract
*
* @created 24.01.2021
* @author ZXing Authors
@@ -12,7 +12,7 @@
namespace chillerlan\QRCode\Decoder;
use InvalidArgumentException;
use function array_slice, array_splice;
use function array_slice, array_splice, file_exists, is_file, is_readable, realpath;
/**
* The purpose of this class hierarchy is to abstract different bitmap implementations across
@@ -23,7 +23,7 @@ use function array_slice, array_splice;
*
* @author dswitkin@google.com (Daniel Switkin)
*/
abstract class LuminanceSource{
abstract class LuminanceSourceAbstract implements LuminanceSourceInterface{
protected array $luminances;
protected int $width;
@@ -38,47 +38,24 @@ abstract class LuminanceSource{
// In order to measure pure decoding speed, we convert the entire image to a greyscale array
// up front, which is the same as the Y channel of the YUVLuminanceSource in the real app.
$this->luminances = [];
// @todo: grayscale?
//$this->luminances = $this->grayScaleToBitmap($this->grayscale());
}
/**
* Fetches luminance data for the underlying bitmap. Values should be fetched using:
* {@code int luminance = array[y * width + x] & 0xff}
*
* @return array A row-major 2D array of luminance values. Do not use result.length as it may be
* larger than width * height bytes on some platforms. Do not modify the contents
* of the result.
*/
/** @inheritDoc */
public function getMatrix():array{
return $this->luminances;
}
/**
* @return int The width of the bitmap.
*/
/** @inheritDoc */
public function getWidth():int{
return $this->width;
}
/**
* @return int The height of the bitmap.
*/
/** @inheritDoc */
public function getHeight():int{
return $this->height;
}
/**
* Fetches one row of luminance data from the underlying platform's bitmap. Values range from
* 0 (black) to 255 (white). Because Java does not have an unsigned byte type, callers will have
* to bitwise and with 0xff for each value. It is preferable for implementations of this method
* to only fetch this row rather than the whole image, since no 2D Readers may be installed and
* getMatrix() may never be called.
*
* @param int $y The row to fetch, which must be in [0,getHeight())
*
* @return array An array containing the luminance data.
*/
/** @inheritDoc */
public function getRow(int $y):array{
if($y < 0 || $y >= $this->getHeight()){
@@ -93,11 +70,7 @@ abstract class LuminanceSource{
}
/**
* @param int $r
* @param int $g
* @param int $b
*
* @return void
*/
protected function setLuminancePixel(int $r, int $g, int $b):void{
$this->luminances[] = $r === $g && $g === $b
@@ -107,4 +80,23 @@ abstract class LuminanceSource{
: ($r + 2 * $g + $b) / 4; // (((($r + 2 * $g + $b) / 4) + 128) % 256) - 128;
}
/**
*
*/
protected static function checkFile(string $path):string{
$path = trim($path);
if(!file_exists($path) || !is_file($path) || !is_readable($path)){
throw new InvalidArgumentException('invalid file: '.$path);
}
$realpath = realpath($path);
if($realpath === false){
throw new InvalidArgumentException('unable to resolve path: '.$path);
}
return $realpath;
}
}
+54
View File
@@ -0,0 +1,54 @@
<?php
/**
* Interface LuminanceSourceInterface
*
* @created 18.11.2021
* @author smiley <smiley@chillerlan.net>
* @copyright 2021 smiley
* @license MIT
*/
namespace chillerlan\QRCode\Decoder;
/**
*/
interface LuminanceSourceInterface{
/**
* Fetches luminance data for the underlying bitmap. Values should be fetched using:
* {@code int luminance = array[y * width + x] & 0xff}
*
* @return array A row-major 2D array of luminance values. Do not use result.length as it may be
* larger than width * height bytes on some platforms. Do not modify the contents
* of the result.
*/
public function getMatrix():array;
/**
* @return int The width of the bitmap.
*/
public function getWidth():int;
/**
* @return int The height of the bitmap.
*/
public function getHeight():int;
/**
* Fetches one row of luminance data from the underlying platform's bitmap. Values range from
* 0 (black) to 255 (white). Because Java does not have an unsigned byte type, callers will have
* to bitwise and with 0xff for each value. It is preferable for implementations of this method
* to only fetch this row rather than the whole image, since no 2D Readers may be installed and
* getMatrix() may never be called.
*
* @param int $y The row to fetch, which must be in [0,getHeight())
*
* @return array An array containing the luminance data.
*/
public function getRow(int $y):array;
public static function fromFile(string $path):self;
public static function fromBlob(string $blob):self;
}