recreate project

This commit is contained in:
root
2026-02-10 22:11:06 -05:00
commit 663c0cdbda
10149 changed files with 1379710 additions and 0 deletions
@@ -0,0 +1,96 @@
<?php
use Mike42\GfxPhp\BlackAndWhiteRasterImage;
use PHPUnit\Framework\TestCase;
/*
* Many of these tests use an example image like this-
*╭────╮
*│████│ ██ = 1
*│░░██│ ░░ = 0
*╰────╯
*/
class BlackAndWhiteRasterImageTest extends TestCase
{
protected function createBlackAndWhiteTestImage() {
$image = BlackAndWhiteRasterImage::create(2, 2);
$image -> setPixel(0, 0, 1);
$image -> setPixel(1, 0, 1);
$image -> setPixel(0, 1, 0);
$image -> setPixel(1, 1, 1);
return $image;
}
public function testCreate()
{
$img = $this -> createBlackAndWhiteTestImage();
$this -> assertEquals("▀█\n", $img -> toString());
}
public function testInvert() {
$img = $this -> createBlackAndWhiteTestImage();
$img -> invert();
$this -> assertEquals("\n", $img -> toString());
}
public function testToRgb()
{
$img = $this -> createBlackAndWhiteTestImage() -> toRgb() -> toBlackAndWhite();
$this -> assertEquals("▀█\n", $img -> toString());
}
public function testToIndexed()
{
$img = $this -> createBlackAndWhiteTestImage() -> toIndexed() -> toBlackAndWhite();
$this -> assertEquals("▀█\n", $img -> toString());
}
public function testToGrayscale()
{
$img = $this -> createBlackAndWhiteTestImage() -> toGrayscale() -> toBlackAndWhite();
$this -> assertEquals("▀█\n", $img -> toString());
}
public function testClear()
{
$img = $this -> createBlackAndWhiteTestImage();
$img -> clear();
$this -> assertEquals(" \n", $img -> toString());
}
public function testScale()
{
$img = $this -> createBlackAndWhiteTestImage() -> scale(4, 2);
$this -> assertEquals("▀▀██\n", $img -> toString());
}
public function testRectEmpty()
{
$img = BlackAndWhiteRasterImage::create(5, 5);
$img -> rect(1, 1, 3, 3);
$expected = " ▄▄▄ \n" .
" █▄█ \n" .
" \n";
$this -> assertEquals($expected, $img -> toString());
}
public function testSubImageEmpty()
{
$img = BlackAndWhiteRasterImage::create(5, 5);
$img -> rect(1, 1, 3, 3);
$img = $img -> subImage(1, 1, 3, 3);
$expected = "█▀█\n" .
"▀▀▀\n";
$this -> assertEquals($expected, $img -> toString());
}
public function testRectFilled()
{
$img = BlackAndWhiteRasterImage::create(5, 5);
$img -> rect(1, 1, 3, 3, true);
$expected = " ▄▄▄ \n" .
" ███ \n" .
" \n";
$this -> assertEquals($expected, $img -> toString());
}
}
@@ -0,0 +1,25 @@
<?php
namespace Mike42\GfxPhp\Codec\Bmp;
use PHPUnit\Framework\TestCase;
class BmpBitfieldDecoderTest extends TestCase
{
/**
* Decode various 16-bit pixels with the default 5-5-5 bit depths
*/
public function testReadDefaults()
{
// 5-5-5, little-endian encoded as 2 bytes.
$decoder = new BmpBitfieldDecoder(BmpColorBitfield::from16bitDefaults());
$this -> assertEquals([0, 0, 0], $decoder -> read16bit([0x00, 0x00])); // Black
$this -> assertEquals([0, 0, 0], $decoder -> read16bit([0x00, 0x80])); // Also black (MSB ignored)
$this -> assertEquals([255, 255, 255], $decoder -> read16bit([0xff, 0xff])); // White
$this -> assertEquals([0, 0, 255], $decoder -> read16bit([0x1f, 0])); // Blue
$this -> assertEquals([0, 255, 0], $decoder -> read16bit([0xe0, 0x03])); // Green
$this -> assertEquals([255, 0, 0], $decoder -> read16bit([0x00, 0x7c])); // Red
}
}
@@ -0,0 +1,80 @@
<?php
namespace Mike42\GfxPhp\Codec\Bmp;
use PHPUnit\Framework\TestCase;
class BmpColorMaskTest extends TestCase
{
public function testEmpty() {
$mask = new BmpColorMask(0x00); // 00000000
$this -> assertEquals(0, $mask -> getLen());
$this -> assertEquals(0, $mask -> getOffset());
$this -> assertEquals(0, $mask -> getMaxValue());
$this -> assertEquals(0, $mask -> getValue(0xFF));
$this -> assertEquals(0, $mask -> getNormalisedValue(0xFF));
}
public function testOne() {
$mask = new BmpColorMask(0x01); // 00000001
$this -> assertEquals(1, $mask -> getLen());
$this -> assertEquals(0, $mask -> getOffset());
$this -> assertEquals(1, $mask -> getMaxValue());
// Regular
$this -> assertEquals(0, $mask -> getValue(0xFE)); // 11111110
$this -> assertEquals(1, $mask -> getValue(0x01)); // 00000001
// Normalised
$this -> assertEquals(0, $mask -> getNormalisedValue(0xFE));
$this -> assertEquals(255, $mask -> getNormalisedValue(0x01));
}
public function testOffset() {
$mask = new BmpColorMask(0x10); // 00010000
$this -> assertEquals(1, $mask -> getLen());
$this -> assertEquals(4, $mask -> getOffset());
$this -> assertEquals(1, $mask -> getMaxValue());
// Regular
$this -> assertEquals(0, $mask -> getValue(0xEF)); // 11101111
$this -> assertEquals(1, $mask -> getValue(0x10)); // 00010000
// Normalised
$this -> assertEquals(0, $mask -> getNormalisedValue(0xEF));
$this -> assertEquals(255, $mask -> getNormalisedValue(0x10));
}
public function testLength() {
$mask = new BmpColorMask(0x30); // 00110000
$this -> assertEquals(2, $mask -> getLen());
$this -> assertEquals(4, $mask -> getOffset());
$this -> assertEquals(3, $mask -> getMaxValue());
// Regular
$this -> assertEquals(0, $mask -> getValue(0xCF)); // 11001111
$this -> assertEquals(2, $mask -> getValue(0x20)); // 00100000 -> 10
$this -> assertEquals(3, $mask -> getValue(0x30)); // 00110000
// Normalised
$this -> assertEquals(0, $mask -> getNormalisedValue(0xCF));
$this -> assertEquals(170, $mask -> getNormalisedValue(0x20)); // 10 in binary shifted then repeated to use full space.
$this -> assertEquals(255, $mask -> getNormalisedValue(0x30));
}
public function testLarge() {
$mask = new BmpColorMask(0x03FF); // 00000011 11111111
$this -> assertEquals(10, $mask -> getLen());
$this -> assertEquals(0, $mask -> getOffset());
$this -> assertEquals(1023, $mask -> getMaxValue());
// Regular
$this -> assertEquals(0, $mask -> getValue(0x0000));
$this -> assertEquals(511, $mask -> getValue(0x01FF));
$this -> assertEquals(1023, $mask -> getValue(0x03FF));
// Normalised - note how raw value is scaled down this time
$this -> assertEquals(0, $mask -> getNormalisedValue(0x0000));
$this -> assertEquals(127, $mask -> getNormalisedValue(0x01FF));
$this -> assertEquals(255, $mask -> getNormalisedValue(0x03FF));
}
public function testNonContiguous() {
$this -> expectException(\Exception::class);
$mask = new BmpColorMask(0x50); // 01010000
$this -> assertEquals(3, $mask -> getLen());
$this -> assertEquals(4, $mask -> getOffset());
}
}
+31
View File
@@ -0,0 +1,31 @@
<?php
use Mike42\GfxPhp\Codec\BmpCodec;
use PHPUnit\Framework\TestCase;
use Mike42\GfxPhp\RgbRasterImage;
class BmpCodecTest extends TestCase
{
const BMP_IMAGE = "BM:\x00\x00\x00\x00\x00\x00\x006\x00\x00\x00(\x00\x00" .
"\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01\x00\x18\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff" .
"\xff\x00";
public function testBmpEncode()
{
$encoder = new BmpCodec();
$image = RgbRasterImage::create(1, 1);
$imageStr = $encoder -> encode($image, 'bmp');
$this -> assertEquals(self::BMP_IMAGE, $imageStr);
}
public function testBmpDecode()
{
$decoder = new BmpCodec();
$image = $decoder -> decode(self::BMP_IMAGE);
$this -> assertEquals(1, $image -> getWidth());
$this -> assertEquals(1, $image -> getHeight());
}
}
+74
View File
@@ -0,0 +1,74 @@
<?php
use PHPUnit\Framework\TestCase;
use Mike42\GfxPhp\Codec\GifCodec;
use Mike42\GfxPhp\IndexedRasterImage;
class GifCodecTest extends TestCase
{
/*
* 1px by 1px white image, with a one white value and the remainder of the
* 256-color palette filled with black.
*/
const GIF_IMAGE = "GIF89a\x01\x00\x01\x00\xf7\x00\x00\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!\xf9" .
"\x04\x01\x00\x00\xff\x00,\x00\x00\x00\x00\x01\x00\x01\x00\x00\x08\x04\x00" .
"\x01\x04\x04\x00;";
public function testGifEncode() {
$encoder = new GifCodec();
$image = IndexedRasterImage::create(1, 1);
$image -> setTransparentColor(255);
$imageStr = $encoder -> encode($image, 'gif');
$this -> assertEquals(self::GIF_IMAGE, $imageStr);
}
public function testGifDecode() {
$decoder = new GifCodec();
$image = $decoder -> decode(self::GIF_IMAGE, 'gif') -> toIndexed();
$this -> assertEquals(1, $image -> getWidth());
$this -> assertEquals(1, $image -> getHeight());
$this -> assertEquals([255, 255, 255], $image -> indexToRgb($image -> getPixel(0, 0)));
}
}
+91
View File
@@ -0,0 +1,91 @@
<?php
use Mike42\GfxPhp\Image;
use PHPUnit\Framework\TestCase;
use Mike42\GfxPhp\RgbRasterImage;
use Mike42\GfxPhp\Codec\PngCodec;
class PngCodecTest extends TestCase
{
// Example file that we compare encoder results against, and decode.
const SMALL_FILE = "\x89PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x02\x00\x00\x00\x90wS\xde\x00\x00\x00\x0cIDATx\x9cc\xf8\xff\xff?\x00\x05\xfe\x02\xfe\x0d\xefF\xb8\x00\x00\x00\x00IEND\xaeB`\x82";
public function testEncode() {
// Simplest image I can come up with
$img = RgbRasterImage::create(1, 1);
$codec = new PngCodec();
// Encode
$pngStr = $codec -> encode($img, "png");
// Compare to known-good PNG
$this -> assertEquals(self::SMALL_FILE, $pngStr);
}
public function testDecode() {
$codec = new PngCodec();
$img = $codec -> decode(self::SMALL_FILE);
$this -> assertTrue($img instanceof RgbRasterImage);
$this -> assertEquals(1, $img -> getWidth());
$this -> assertEquals(1, $img -> getHeight());
}
public function testBlackAndWhiteImageLoad() {
// Simple test of a black-and-white, interlaced & non-interlaced image, since
// we can do a text-based assertion on the actual image content.
$expected = " ▄█\n" .
" ▄███\n" .
" ██ ██ ▄█████\n" .
" ██ ▄▄ ██ ▄███████\n" .
" ██ ██ ██ ▄█████████\n" .
" ████████ ▄███████████\n" .
" ██ ██ ▄█████████████\n" .
" ▄███████████████\n" .
" ▄█████████████████\n" .
" ▄███████ █████\n" .
" ▄█████████ ████ ████\n" .
" ▄███████████ █████\n" .
" ▄█████████████ ████ ████\n" .
" ▄███████████████ █████\n" .
" ▄█████████████████████████████\n" .
"▄███████████████████████████████\n";
// Load interlaced & non-interlaced
$interlacedImage = Image::fromFile(__DIR__ . "/../../resources/pngsuite/basi0g01.png");
$interlacedResult = $interlacedImage -> toString();
$nonInterlacedImage = Image::fromFile(__DIR__ . "/../../resources/pngsuite/basn0g01.png");
$nonInterlacedResult = $nonInterlacedImage -> toString();
// These should both match the expected output
$this -> assertEquals($expected, $interlacedResult);
$this -> assertEquals($expected, $nonInterlacedResult);
}
public function testIndexedImageLoad() {
// Load an interlaced 8-bit image, which follows a very different code path to
// lower bit depths.
$img = Image::fromFile(__DIR__ . "/../../resources/pngsuite/basi3p08.png") -> toIndexed();
$this -> assertEquals(255, $img -> getMaxVal());
$this -> assertEquals(32, $img -> getWidth());
$this -> assertEquals(32, $img -> getHeight());
}
public function testFiltering() {
// Expected value is sensitive to the grayscale -> B&W conversion
$expected = "████████████████████████████████\n" .
"███████████▀▀▀▀▀▀▀▀▀▀███████████\n" .
"████████▀ ▀████████\n" .
"██████▀ ▀██████\n" .
"████▀ ▀████\n" .
"███▀ ▀███\n" .
"███ ███\n" .
"███ ███\n" .
"███ ███\n" .
"███ ███\n" .
"███▄ ▄███\n" .
"████▄ ▄████\n" .
"██████▄ ▄██████\n" .
"████████▄ ▄████████\n" .
"███████████▄▄▄▄▄▄▄▄▄▄███████████\n" .
"████████████████████████████████\n";
// Image with different filters on each scanline
$img = Image::fromFile(__DIR__ . "/../../resources/pngsuite/f99n0g04.png") -> toBlackAndWhite();
$result = $img -> toString();
$this -> assertEquals($expected, $result);
}
}
+96
View File
@@ -0,0 +1,96 @@
<?php
use PHPUnit\Framework\TestCase;
use Mike42\GfxPhp\RgbRasterImage;
use Mike42\GfxPhp\Codec\PngCodec;
use Mike42\GfxPhp\Codec\PnmCodec;
use Mike42\GfxPhp\BlackAndWhiteRasterImage;
use Mike42\GfxPhp\GrayscaleRasterImage;
/*
* Tiny example image used throughout this test looks like this:
*╭────╮
*│██░░│ ██ = 0x00
*│░░██│ ░░ = 0xFF
*╰────╯
*/
class PnmCodecTest extends TestCase
{
const IMAGE_TEXT = "▀▄\n";
const PBM_EXAMPLE = "P4\x0a2 2\x0a\x80@";
const PGM_EXAMPLE = "P5\x0a2 2\x0a255\x0a\x00\xff\xff\x00";
const PPM_EXAMPLE = "P6\x0a2 2\x0a255\x0a\x00\x00\x00\xff\xff\xff\xff\xff\xff\x00\x00\x00";
protected function createRgbTestImage() {
$image = RgbRasterImage::create(2, 2);
$black = $image -> rgbToInt(0, 0, 0);
$white = $image -> rgbToInt(255, 255, 255);
$image -> setPixel(0, 0, $black);
$image -> setPixel(1, 0, $white);
$image -> setPixel(0, 1, $white);
$image -> setPixel(1, 1, $black);
return $image;
}
public function testPnmEncodeRgb() {
// Test image as RGB
$encoder = new PnmCodec();
$image = $this -> createRgbTestImage();
// Encode
$blob = $encoder -> encode($image, 'pnm');
// Should have auto-selected PPM based on RgbTestImage input
$this -> assertEquals(self::PPM_EXAMPLE, $blob);
}
public function testPbmEncodeRgb() {
// Test image as RGB
$encoder = new PnmCodec();
$image = $this -> createRgbTestImage();
// Encode
$blob = $encoder -> encode($image, 'pbm');
// Check against known-good encoding of PBM
$this -> assertEquals(self::PBM_EXAMPLE, $blob);
}
public function testPbmDecode() {
$decoder = new PnmCodec();
$image = $decoder -> decode(self::PBM_EXAMPLE);
$this -> assertTrue($image instanceof BlackAndWhiteRasterImage);
$this -> assertEquals(self::IMAGE_TEXT, $image -> toString());
}
public function testPgmEncodeRgb() {
// Test image as RGB
$encoder = new PnmCodec();
$image = $this -> createRgbTestImage();
// Encode
$blob = $encoder -> encode($image, 'pgm');
// Check against known-good encoding of PGM
$this -> assertEquals(self::PGM_EXAMPLE, $blob);
}
public function testPgmDecode() {
$decoder = new PnmCodec();
$image = $decoder -> decode(self::PGM_EXAMPLE);
$this -> assertTrue($image instanceof GrayscaleRasterImage);
$this -> assertEquals(self::IMAGE_TEXT, $image -> toBlackAndWhite() -> toString());
}
public function testPpmEncodeRgb() {
// Test image as RGB
$encoder = new PnmCodec();
$image = $this -> createRgbTestImage();
// Encode
$blob = $encoder -> encode($image, 'ppm');
// Check against known-good encoding of PPM
$this -> assertEquals(self::PPM_EXAMPLE, $blob);
}
public function testPpmDecode() {
$decoder = new PnmCodec();
$image = $decoder -> decode(self::PPM_EXAMPLE);
$this -> assertTrue($image instanceof RgbRasterImage);
$this -> assertEquals(self::IMAGE_TEXT, $image -> toBlackAndWhite() -> toString());
}
}
@@ -0,0 +1,158 @@
<?php
namespace Mike42\GfxPhp\Codec\Bmp;
use Exception;
use PHPUnit\Framework\TestCase;
class Rle8DecoderTest extends TestCase
{
public function testDecodeEmpty()
{
$decoder = new Rle8Decoder();
$result = $decoder -> decodeNumbers([], 0, 0);
$this -> assertEquals([], $result);
}
public function testDecodeEmpty2()
{
$decoder = new Rle8Decoder();
$result = $decoder -> decodeNumbers([
0, 1 // End of bitmap
], 0, 0);
$this -> assertEquals([], $result);
}
public function testDecodeRun()
{
$decoder = new Rle8Decoder();
$result = $decoder -> decodeNumbers([
3, 1, // 3 1's
0, 0, // Line break
3, 3, // 3 3's
0, 0, // Line break
3, 5, // 3 5's
0, 1 // End of bitmap
], 3, 3);
$expected = [
[1, 1, 1],
[3, 3, 3],
[5, 5, 5]
];
$this -> assertEquals($expected, $result);
}
public function testRunTooWide()
{
$this -> expectException(Exception::class);
$decoder = new Rle8Decoder();
$result = $decoder -> decodeNumbers([
4, 1, // 4 1's (x-direction overflow)
0, 0, // Line break
3, 3, // 3 3's
0, 0, // Line break
3, 5, // 3 5's
0, 1 // End of bitmap
], 3, 3);
$expected = [
[1, 1, 1],
[3, 3, 3],
[5, 5, 5]
];
$this -> assertEquals($expected, $result);
}
public function testRunTooTall()
{
$this -> expectException(Exception::class);
$decoder = new Rle8Decoder();
$result = $decoder -> decodeNumbers([
3, 1, // 3 1's
0, 0, // Line break
3, 3, // 3 3's
0, 0, // Line break
3, 5, // 3 5's
0, 0, // Line break
3, 6, // 3 6's (y-direction overflow)
0, 1 // End of bitmap
], 3, 3);
$expected = [
[1, 1, 1],
[3, 3, 3],
[5, 5, 5]
];
$this -> assertEquals($expected, $result);
}
public function testDeltaDiagonal()
{
$decoder = new Rle8Decoder();
$result = $decoder -> decodeNumbers([
0, 2, // Jump..
2, 2, // .. diagonally
1, 1, // Print 1
0, 1 // End of bitmap
], 3, 3);
$expected = [
[0, 0, 0],
[0, 0, 0],
[0, 0, 1]
];
$this -> assertEquals($expected, $result);
}
public function testDeltaRight()
{
$decoder = new Rle8Decoder();
$result = $decoder -> decodeNumbers([
0, 2, // Jump..
2, 0, // .. right
1, 1, // Print 1
0, 1 // End of bitmap
], 3, 3);
$expected = [
[0, 0, 1],
[0, 0, 0],
[0, 0, 0]
];
$this -> assertEquals($expected, $result);
}
public function testDeltaDown()
{
$decoder = new Rle8Decoder();
$result = $decoder -> decodeNumbers([
0, 2, // Jump..
0, 2, // .. down
1, 1, // Print 1
0, 1 // End of bitmap
], 3, 3);
$expected = [
[0, 0, 0],
[0, 0, 0],
[1, 0, 0]
];
$this -> assertEquals($expected, $result);
}
public function testAbsolute()
{
$decoder = new Rle8Decoder();
$result = $decoder -> decodeNumbers([
0, 3, 1, 2, 3, 0, // Absolute run of 3 pixels + 1 pixel of padding
0, 0, // Line break
0, 3, 4, 5, 6, 0, // 3 pixels
0, 0, // Line break
0, 3, 7, 8, 9, 0, // 3 pixels
0, 0, // Line break
0, 1 // End of bitmap
], 3, 3);
$expected = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
$this -> assertEquals($expected, $result);
}
}
+89
View File
@@ -0,0 +1,89 @@
<?php
use Mike42\GfxPhp\BlackAndWhiteRasterImage;
use Mike42\GfxPhp\Codec\Common\DataBlobInputStream;
use Mike42\GfxPhp\Codec\WbmpCodec;
use PHPUnit\Framework\TestCase;
class WbmpCodecTest extends TestCase {
const WBMP_IMAGE = "\x00\x00\x0c\x06\x24\x90\xff\xf0\x49\x20\xff\xf0\x92\x40\xff\xf0";
public function testIdentify() {
$codec = new WbmpCodec();
$this -> assertEquals("wbmp", $codec -> identify(self::WBMP_IMAGE));
$this -> assertEquals("", $codec -> identify("HELLO"));
}
public function testDecode() {
$codec = new WbmpCodec();
$image = $codec -> decode(self::WBMP_IMAGE) -> toBlackAndWhite();
$this -> assertEquals(12, $image -> getWidth());
$this -> assertEquals(6, $image -> getHeight());
$content = "▀▀ ▀▀ ▀▀ ▀▀ \n" .
"▀ ▀▀ ▀▀ ▀▀ ▀\n" .
" ▀▀ ▀▀ ▀▀ ▀▀\n";
$this -> assertEquals($content, $image -> toString());
}
public function testEncode() {
// Raster representation is inverse to WBMP format.
$image = BlackAndWhiteRasterImage::create(12, 6, [0xdb, 0x6f, 0x00, 0x0f, 0xb6, 0xdf, 0x00, 0x0f, 0x6d, 0xbf, 0x00, 0x0f]);
$codec = new WbmpCodec();
$data = $codec -> encode($image, "wbmp");
$this -> assertEquals(self::WBMP_IMAGE, $data);
}
public function testReadOneByte() {
$data = DataBlobInputStream::fromBlob("\x60");
$codec = new WbmpCodec();
$val = $codec -> readInt($data);
$this -> assertEquals(0x60, $val);
}
public function testReadMultibyte() {
$data = DataBlobInputStream::fromBlob("\x81\x20");
$codec = new WbmpCodec();
$val = $codec -> readInt($data);
$this -> assertEquals(0xA0, $val);
}
public function testReadMax() {
$data = DataBlobInputStream::fromBlob("\xFF\xFF\xFF\x7F\x00"); // Final byte not used
$codec = new WbmpCodec();
$val = $codec -> readInt($data);
$this -> assertEquals(268435455, $val);
}
public function testReadMultibyteOverflow() {
// Appears to be no limit in WBMP to image dimensions, but we stop reading the multibyte-ints after 28 bits.
$this -> expectException(Exception::class);
$data = DataBlobInputStream::fromBlob("\xFF\xFF\xFF\x80\x00"); // (value in testMax()) + 1
$codec = new WbmpCodec();
$codec -> readInt($data);
}
public function testWriteOneByte() {
$codec = new WbmpCodec();
$val = $codec -> writeInt(0x60);
$this -> assertEquals("\x60", $val);
}
public function testWriteMultibyte() {
$codec = new WbmpCodec();
$val = $codec -> writeInt(0xA0);
$this -> assertEquals("\x81\x20", $val);
}
public function testWriteMax() {
$codec = new WbmpCodec();
$val = $codec -> writeInt(268435455);
$this -> assertEquals("\xFF\xFF\xFF\x7F", $val);
}
public function testWriteMultibyteOverflow() {
$this -> expectException(Exception::class);
$codec = new WbmpCodec();
$val = $codec -> writeInt(268435456); // As testWriteMax(), +1
}
}
@@ -0,0 +1,56 @@
<?php
/*
* Many of these tests use an example image like this-
*╭────╮
*│░░▒▒│ ░░ = 255 ▓▓ = 80
*│▓▓██│ ▒▒ = 160 ██ = 0
*╰────╯
*/
use PHPUnit\Framework\TestCase;
use Mike42\GfxPhp\GrayscaleRasterImage;
use Mike42\GfxPhp\RgbRasterImage;
class GrayscaleRasterImageTest extends TestCase {
protected function createGrayscaleTestImage() {
$image = GrayscaleRasterImage::create(2, 2);
$image -> setPixel(0, 0, 255);
$image -> setPixel(1, 0, 160);
$image -> setPixel(0, 1, 80);
$image -> setPixel(1, 1, 0);
return $image;
}
public function testCreate()
{
$img = $this -> createGrayscaleTestImage();
$this -> assertEquals(2, $img -> getWidth());
$this -> assertEquals(2, $img -> getHeight());
$this -> assertEquals(255, $img -> getMaxVal());
$this -> assertEquals("▄▄\n", $img -> toBlackAndWhite() -> toString());
}
public function testToRgb()
{
$white = RgbRasterImage::rgbToInt(255, 255, 255);
$lightGray = RgbRasterImage::rgbToInt(160, 160, 160);
$darkGray = RgbRasterImage::rgbToInt(80, 80, 80);
$black = RgbRasterImage::rgbToInt(0, 0, 0);
$img = $this -> createGrayscaleTestImage() -> toRgb();
$this -> assertEquals($white, $img -> getPixel(0, 0));
$this -> assertEquals($lightGray, $img -> getPixel(1, 0));
$this -> assertEquals($darkGray, $img -> getPixel(0, 1));
$this -> assertEquals($black, $img -> getPixel(1, 1));
}
public function testToIndexed()
{
// Same raster data is used, with grayscale 'palette'
$img = $this -> createGrayscaleTestImage() -> toIndexed();
$this -> assertEquals(255, $img -> getPixel(0, 0));
$this -> assertEquals(160, $img -> getPixel(1, 0));
$this -> assertEquals(80, $img -> getPixel(0, 1));
$this -> assertEquals(0, $img -> getPixel(1, 1));
}
}
+12
View File
@@ -0,0 +1,12 @@
<?php
use Mike42\GfxPhp\Image;
use PHPUnit\Framework\TestCase;
class ImageTest extends TestCase
{
public function testBadFilename() {
$this -> expectException(Exception::class);
Image::fromFile("not a real file");
}
}
@@ -0,0 +1,95 @@
<?php
/*
* Many of these tests use an example image like this-
*╭────╮
*│░░▒▒│ ░░ = 0 ▓▓ = 2
*│▓▓██│ ▒▒ = 1 ██ = 3
*╰────╯
*/
use PHPUnit\Framework\TestCase;
use Mike42\GfxPhp\Image;
use Mike42\GfxPhp\IndexedRasterImage;
use Mike42\GfxPhp\RgbRasterImage;
class IndexedRasterImageTest extends TestCase
{
protected function createIndexedTestImage() {
$image = IndexedRasterImage::create(2, 2, null, [
[255, 255, 255],
[160, 160, 160],
[80, 80, 80],
[0, 0, 0]]);
$image -> setPixel(0, 0, 0);
$image -> setPixel(1, 0, 1);
$image -> setPixel(0, 1, 2);
$image -> setPixel(1, 1, 3);
return $image;
}
public function testCreate()
{
$img = $this -> createIndexedTestImage();
$this -> assertEquals(2, $img -> getWidth());
$this -> assertEquals(2, $img -> getHeight());
$this -> assertEquals(255, $img -> getMaxVal());
$this -> assertEquals("▄▄\n", $img -> toBlackAndWhite() -> toString());
}
public function testReduceDepthTo1Bit()
{
$img = $this -> createIndexedTestImage();
$img -> setMaxVal(1);
$this -> assertEquals(0, $img -> getPixel(0, 0));
$this -> assertEquals(0, $img -> getPixel(1, 0));
$this -> assertEquals(1, $img -> getPixel(0, 1));
$this -> assertEquals(1, $img -> getPixel(1, 1));
}
public function testToGrayscale() {
$img = $this -> createIndexedTestImage() -> toGrayscale();
$this -> assertEquals(255, $img -> getPixel(0, 0));
$this -> assertEquals(160, $img -> getPixel(1, 0));
$this -> assertEquals(80, $img -> getPixel(0, 1));
$this -> assertEquals(0, $img -> getPixel(1, 1));
}
public function testToRgb() {
$white = RgbRasterImage::rgbToInt(255, 255, 255);
$lightGray = RgbRasterImage::rgbToInt(160, 160, 160);
$darkGray = RgbRasterImage::rgbToInt(80, 80, 80);
$black = RgbRasterImage::rgbToInt(0, 0, 0);
$img = $this -> createIndexedTestImage() -> toRgb();
$this -> assertEquals($white, $img -> getPixel(0, 0));
$this -> assertEquals($lightGray, $img -> getPixel(1, 0));
$this -> assertEquals($darkGray, $img -> getPixel(0, 1));
$this -> assertEquals($black, $img -> getPixel(1, 1));
}
public function testRgbToIndexExists() {
$img = $this -> createIndexedTestImage();
$idx = $img -> rgbToIndex([80, 80, 80]);
$this -> assertEquals(2, $idx);
}
public function testQuantizeGrayscale() {
// Produce 8-bit grayscale image via high color-count RGBA
$img = Image::fromFile(__DIR__ . "/../resources/pngsuite/basn2c08.png") -> toIndexed() -> toGrayscale();
$this -> assertEquals(255, $img -> getMaxVal());
$this -> assertEquals(255, $img -> getPixel(0, 0)); // White
$this -> assertEquals(0, $img -> getPixel(31, 31)); // Black
}
public function testQuantizeRgb() {
// Reduce depth of image with more than 16 colors.
$img = Image::fromFile(__DIR__ . "/../resources/pngsuite/basn2c08.png") -> toIndexed();
$this -> assertEquals(16777215, $img -> getMaxVal());
$img -> setMaxVal(255);
// Check new range.
$this -> assertEquals(255, $img -> getMaxVal());
$this -> assertEquals(255, $img -> getPixel(0, 0)); // White
$this -> assertEquals(0, $img -> getPixel(31, 31)); // Black
}
}
@@ -0,0 +1,70 @@
<?php
use Mike42\GfxPhp\Util\LzwCompression;
use Mike42\GfxPhp\Util\LzwDecodeBuffer;
use PHPUnit\Framework\TestCase;
class LzwCompressionTest extends TestCase
{
/*
* Known-good GIF-LZW strings from Wikipedia
* for 3x5 image like the one shown below.
*
* https://en.wikipedia.org/wiki/GIF
*╭──────╮
*│██░░░░│ ██ = 0x40
*│░░██░░│ ░░ = 0xFF
*│░░░░░░│
*│░░░░░░│
*│░░░░░░│
*╰──────╯
*/
const compressedChars = [0x00, 0x51, 0xFC, 0x1B, 0x28, 0x70, 0xA0, 0xC1, 0x83, 0x01, 0x01];
const uncompressedChars = [0x28, 0xFF, 0xFF, 0xFF, 0x28, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
public function testLzwDecodeBufferBytes()
{
// Ensure we can extract numbers from input stream
$contents = "ABCD";
$buffer = new LzwDecodeBuffer($contents);
$this -> assertEquals(65, $buffer -> read(8));
$this -> assertEquals(66, $buffer -> read(8));
$this -> assertEquals(67, $buffer -> read(8));
$this -> assertEquals(68, $buffer -> read(8));
$this -> assertEquals(false, $buffer -> read(8));
}
public function testLzwDecodeBufferBits()
{
// Ensure we can extract numbers of strange lengths from input stream
$inp = pack("C*", ... LzwCompressionTest::compressedChars);
$buffer = new LzwDecodeBuffer($inp);
$this -> assertEquals(0x100, $buffer -> read(9));
$this -> assertEquals(0x028, $buffer -> read(9));
$this -> assertEquals(0x0FF, $buffer -> read(9));
$this -> assertEquals(0x103, $buffer -> read(9));
$this -> assertEquals(0x102, $buffer -> read(9));
$this -> assertEquals(0x103, $buffer -> read(9));
$this -> assertEquals(0x106, $buffer -> read(9));
$this -> assertEquals(0x107, $buffer -> read(9));
$this -> assertEquals(0x101, $buffer -> read(9));
$this -> assertEquals(false, $buffer -> read(9));
}
public function testLzwDecompression()
{
// Test de-compression
$compressedStr = pack("C*", ... LzwCompressionTest::compressedChars);
$uncompressedStr = LzwCompression::decompress($compressedStr, 8);
$this -> assertEquals(LzwCompressionTest::uncompressedChars, array_values(unpack("C*", $uncompressedStr)));
}
public function testLzwCompression()
{
// Test de-compression
$uncompressedStr = pack("C*", ... LzwCompressionTest::uncompressedChars);
$compressedStr = LzwCompression::compress($uncompressedStr, 8);
$this -> assertEquals(LzwCompressionTest::compressedChars, array_values(unpack("C*", $compressedStr)));
}
}