Skip to content

Commit

Permalink
Merge pull request #18 from mike42/feature/14-indexed-raster
Browse files Browse the repository at this point in the history
Implement indexed raster image
  • Loading branch information
mike42 authored Apr 28, 2018
2 parents cdf329a + 4c04051 commit 2d39a1d
Show file tree
Hide file tree
Showing 8 changed files with 442 additions and 33 deletions.
16 changes: 15 additions & 1 deletion src/Mike42/ImagePhp/BlackAndWhiteRasterImage.php
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,23 @@ public function toGrayscale() : GrayscaleRasterImage
}
return $img;
}

public function toBlackAndWhite() : BlackAndWhiteRasterImage
{
return clone $this;
}

public function toIndexed(): IndexedRasterImage
{
$width = $this -> width;
$height = $this -> height;
$pixelData = array_fill(0, $width * $height, 0);
for ($y = 0; $y < $height; $y++) {
for ($x = 0; $x < $width; $x++) {
$pixelData[$y * $width + $x] = $this -> getPixel($x, $y);
}
}
$colorTable = PaletteGenerator::blackAndWhitePalette();
return IndexedRasterImage::create($width, $height, $pixelData, $colorTable, 255);
}
}
45 changes: 32 additions & 13 deletions src/Mike42/ImagePhp/Codec/GifCodec.php
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
<?php
namespace Mike42\ImagePhp\Codec;

use Mike42\ImagePhp\GrayscaleRasterImage;
use Mike42\ImagePhp\RasterImage;
use Mike42\ImagePhp\Util\LzwCompression;
use Mike42\ImagePhp\IndexedRasterImage;

class GifCodec implements ImageEncoder
{
protected static $instance = null;

public function encode(RasterImage $image, string $format): string
{
if (!($image instanceof GrayscaleRasterImage)) {
if (!($image instanceof IndexedRasterImage)) {
// Convert if necessary
$image = $image -> toGrayscale();
} else {
if ($image -> getMaxVal() != 256) {
// Scaling has the side-effect of mapping to 256 colors
$image = $image -> scale($image -> getWidth(), $image -> getHeight());
}
$image = $image -> toIndexed();
}
$palette = $image -> getPalette();
if ($image -> getMaxVal() > 256) {
// Color count is too large, clone the image and drop the color depth
$image = $image -> toIndexed();
$image -> setMaxVal(255);
$palette = $image -> getPalette();
}
// GIF signature
$signature = pack("c6", 0x47, 0x49, 0x46, 0x38, 0x39, 0x61);
Expand All @@ -28,14 +30,31 @@ public function encode(RasterImage $image, string $format): string
$header = pack('v2c3', $width, $height, 0xF7, 0, 0);
// Color table of grayscale
$colorTable = [];
for ($i = 0; $i < 256; $i++) {
$colorTable[] = $i;
$colorTable[] = $i;
$colorTable[] = $i;
$paletteSize = count($palette);
for ($i = 0; $i < $paletteSize; $i++) {
$entry = $palette[$i];
$colorTable[] = $entry[0];
$colorTable[] = $entry[1];
$colorTable[] = $entry[2];
}
// Padding to 256 color entries
for ($i = $paletteSize; $i < 256; $i++) {
$colorTable[] = 0;
$colorTable[] = 0;
$colorTable[] = 0;
}

$gct = pack("C*", ... $colorTable);
// Transparent color for graphic control
$transparentColorFlag = 0x00;
$transparentColor = 0;
if ($image -> getTransparentColor() !== null) {
$transparentColor = $image -> getTransparentColor() & 0xFF;
$transparentColorFlag = 0x01;
}
// Graphic control
$gce = pack("C4vC2", 0x21, 0xF9, 0x04, 0x01, 0x00, 0x10, 0x00);
// TODO one of these flags does not do what you think it does.
$gce = pack("C4vC2", 0x21, 0xF9, 0x04, 0x00 | $transparentColorFlag, 0x00, $transparentColor, 0x00);
// Image
$imageDescriptor = pack('Cv4C', 0x2C, 0, 0, $width, $height, 0);
$raster = $image -> getRasterData();
Expand Down
4 changes: 2 additions & 2 deletions src/Mike42/ImagePhp/Codec/PnmCodec.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public function decode(string $blob): RasterImage
$next_line_end = strpos($blob, "\n", $line_end + 1);
$maxValLine = substr($blob, $line_end + 1, ($next_line_end - $line_end) - 1);
$maxVal = (int)$maxValLine;
$depth = $maxVal >= 255 ? 2 : 1;
$depth = $maxVal > 255 ? 2 : 1;
$line_end = $next_line_end;
// Extract data
$expectedBytes = $width * $height * $depth;
Expand All @@ -93,7 +93,7 @@ public function decode(string $blob): RasterImage
$next_line_end = strpos($blob, "\n", $line_end + 1);
$maxValLine = substr($blob, $line_end + 1, ($next_line_end - $line_end) - 1);
$maxVal = (int)$maxValLine;
$depth = $maxVal >= 255 ? 2 : 1;
$depth = $maxVal > 255 ? 2 : 1;
$line_end = $next_line_end;
$expectedBytes = $width * $height * $depth * 3;
$data = substr($blob, $line_end + 1);
Expand Down
16 changes: 14 additions & 2 deletions src/Mike42/ImagePhp/GrayscaleRasterImage.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public function getHeight() : int
{
return $this -> height;
}

public function setPixel(int $x, int $y, int $value)
{
if ($x < 0 || $x >= $this -> width) {
Expand Down Expand Up @@ -110,7 +110,7 @@ public function toGrayscale() : GrayscaleRasterImage
{
return clone $this;
}

public function toBlackAndWhite() : BlackAndWhiteRasterImage
{
$img = BlackAndWhiteRasterImage::create($this -> width, $this -> height);
Expand All @@ -123,4 +123,16 @@ public function toBlackAndWhite() : BlackAndWhiteRasterImage
}
return $img;
}

public function toIndexed(): IndexedRasterImage
{
if ($this -> maxVal > 255) {
// Making use of how scale() uses default values to make a new canvas, which has the
// side-effect of creating an 8-bit image.
return $this -> scale($this -> width, $this -> height) -> toIndexed();
}
$data = $this -> data;
$colorTable = PaletteGenerator::monochromePalette();
return IndexedRasterImage::create($this -> width, $this -> height, $data, $colorTable, 255);
}
}
Loading

0 comments on commit 2d39a1d

Please sign in to comment.