Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve test coverage, related bug fixes #32

Merged
merged 6 commits into from
Jun 10, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 25 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![Build Status](https://travis-ci.org/mike42/gfx-php.svg?branch=master)](https://travis-ci.org/mike42/gfx-php) [![Latest Stable Version](https://poser.pugx.org/mike42/gfx-php/v/stable)](https://packagist.org/packages/mike42/gfx-php)
[![Total Downloads](https://poser.pugx.org/mike42/gfx-php/downloads)](https://packagist.org/packages/mike42/gfx-php)
[![License](https://poser.pugx.org/mike42/gfx-php/license)](https://packagist.org/packages/mike42/gfx-php)
[![License](https://poser.pugx.org/mike42/gfx-php/license)](https://packagist.org/packages/mike42/gfx-php) [![Coverage Status](https://coveralls.io/repos/github/mike42/gfx-php/badge.svg?branch=master)](https://coveralls.io/github/mike42/gfx-php?branch=master)

This library implements input, output and processing of raster images in pure PHP, so that image
processing extensions (Gd, Imagick) are not required.
Expand All @@ -11,46 +11,51 @@ This allows developers to eliminate some portability issues from their applicati

## Requirements

- PHP 7.0 or newer
- PHP 7.0 or newer.
- zlib extension, for reading PNG files.

## Examples
## Get started

- See the `examples/` sub-folder.
- Have a read of the documentation at [gfx-php.readthedocs.io](https://gfx-php.readthedocs.io/)
- See the `examples/` sub-folder for snippets.

## Status & Scope
## Status & scope

Currently, we are implementing basic raster operations on select file formats. If you're interested in image processing algorithms, then please consider contributing an implementation.
Currently, we are implementing basic raster operations on select file formats.

See related documentation for:

- [Available input file formats](https://gfx-php.readthedocs.io/en/latest/user/formats.html#input-formats).
- [Available output file formats](https://gfx-php.readthedocs.io/en/latest/user/formats.html#output-formats).
- [Available image operations](https://gfx-php.readthedocs.io/en/latest/user/operations.html).

If you're interested in image processing algorithms, then please consider contributing an implementation.

For algorithms, it appears feasable to implement:

- Color conversions
- Scale
- Crop
- Blur
- Composite
- Mask
- Rotate
- Layered operations
- Affine transformations
- Lines, arcs, circles, and rectangles.

And the roadmap for format support:
And sill on the roadmap for format support:

- The full suite of Netpbm binary and text formats (PNM, PBM, PGM, PPM).
- BMP, which involves RLE (de)compression
- PNG, which involves DEFLATE (de)compression
- GIF and TIFF, which involve LZW (de)compression
- BMP input, which involves RLE decompression (BMP output is already available).
- GIF input, which involves LZW decompression (GIF output is already available).
- TIFF input and output, which also involves LZW (de)compression.

In the interests of getting the basic features working first, I'm not currently planning to attempt lossy compression, or formats that are not common on either the web or for printing:
In the interests of getting the basic features working first, there is no current plan to attempt lossy compression, or formats that are not common on either the web or for printing, eg:

- JPEG
- MNG
- PAM format
- XPM
- More advanced transformations
- .. etc.

Also, as we don't have the luxury of pulling in dependencies, I'm considering anything that is not a raster operation out-of-scope:

- All vector image formats (PDF, SVG, EPS, etc).
- Anything involving fonts
- Anything involving vector fonts

### Test data sets

Expand Down
3 changes: 2 additions & 1 deletion src/Mike42/GfxPhp/Codec/Png/InterlaceDecoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ private function decodeAdam7Interlace(PngHeader $header, string $binData)
foreach ($passes as $passId => $pass) {
$passWidth = $pass['width'];
$passHeight = $pass['height'];
if ($passWidth == 0) {
if ($passWidth == 0 || $passHeight == 0) {
// No data in this scanline, proceed.
continue;
}
$passScanlineWidth = intdiv($passWidth * $bitDepth + 7, 8) * $channels;
Expand Down
32 changes: 24 additions & 8 deletions src/Mike42/GfxPhp/Codec/Png/PngHeader.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ class PngHeader
const COLOR_TYPE_INDEXED = 3;
const COLOR_TYPE_MONOCHROME_ALPHA = 4;
const COLOR_TYPE_RGBA = 6;

const COMPRESSION_DEFLATE = 0;

const INTERLACE_NONE = 0;
const INTERLACE_ADAM7 = 1;

private $width;
private $height;
private $bitDepth;
Expand All @@ -32,13 +32,29 @@ public function __construct(int $width, int $height, int $bitDepth, int $colorTy
$height < 1 || $height > 2147483647) {
throw new \Exception("Invalid image dimensions");
}
$this -> width = $width;
$this -> height = $height;
// Color type & bit depth
// - Only some combinations of bit depth and colorType are valid
$this -> width = $width;
$this -> height = $height;
// Color type & bit depth - Only some combinations of bit depth and colorType are valid.
// I'm sure you could abbreviate this code, but it's written for comparison with the PNG standard.
if ($colorType === 0 && ($bitDepth === 1 || $bitDepth === 2 || $bitDepth === 4 || $bitDepth === 8 || $bitDepth === 16)) {
$this -> bitDepth = $bitDepth;
$this -> colorType = $colorType;
} else if ($colorType === 2 && ($bitDepth === 8 || $bitDepth === 16)) {
$this -> bitDepth = $bitDepth;
$this -> colorType = $colorType;
// Compression
} else if ($colorType === 3 && ($bitDepth === 1 || $bitDepth === 2 || $bitDepth === 4 || $bitDepth === 8)) {
$this -> bitDepth = $bitDepth;
$this -> colorType = $colorType;
} else if ($colorType === 4 && ($bitDepth === 8 || $bitDepth === 16)) {
$this -> bitDepth = $bitDepth;
$this -> colorType = $colorType;
} else if ($colorType === 6 && ($bitDepth === 8 || $bitDepth === 16)) {
$this -> bitDepth = $bitDepth;
$this -> colorType = $colorType;
} else {
throw new \Exception("Invalid color type / bit depth combination.");
}
// Compression
if ($compression != PngHeader::COMPRESSION_DEFLATE) {
throw new \Exception("Compression type not supported");
}
Expand Down
6 changes: 3 additions & 3 deletions src/Mike42/GfxPhp/Image.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public static function fromFile(string $filename) : RasterImage
if ($blob === false) {
throw new \Exception("Could not retrieve image data from '$filename'. Check that the file exists and can be read.");
}
return self::fromBlob($blob);
return self::fromBlob($blob, $filename);
}

public static function fromBlob(string $blob, string $filename = null) : RasterImage
Expand All @@ -29,11 +29,11 @@ public static function fromBlob(string $blob, string $filename = null) : RasterI
self::$codecs = ImageCodec::getInstance();
}
$format = self::$codecs -> identify($blob);
if ($format == null) {
if ($format === null) {
throw new \Exception("Unknown format for image '$filename'.");
}
$decoder = self::$codecs ->getDecoderForFormat($format);
if ($decoder == null) {
if ($decoder === null) {
throw new \Exception("Format $format not supported, reading '$filename'.");
}
return $decoder -> decode($blob);
Expand Down
6 changes: 3 additions & 3 deletions src/Mike42/GfxPhp/IndexedRasterImage.php
Original file line number Diff line number Diff line change
Expand Up @@ -200,11 +200,11 @@ public function setMaxVal(int $maxVal)
$this -> maxVal = $maxVal;
$this -> setPalette(PaletteGenerator::colorPalette());
return;
} else if ($maxVal >= 2) {
} else if ($maxVal >= 1) {
$this -> maxVal = $maxVal;
$this -> setPalette(PaletteGenerator::blackAndWhitePalette());
return;
} else if ($maxVal >= 1) {
} else if ($maxVal >= 0) {
$this -> maxVal = $maxVal;
$this -> setPalette(PaletteGenerator::whitePalette());
return;
Expand All @@ -228,7 +228,7 @@ public function deallocateColor(array $color)
throw new \Exception("Not implemented");
}

public static function create(int $width, int $height, array $data = null, array $palette = null, int $maxVal = 255)
public static function create(int $width, int $height, array $data = null, array $palette = [], int $maxVal = 255)
{
$expectedSize = $width * $height;
if ($data == null) {
Expand Down
Loading