Skip to content

Commit 2fdd8e8

Browse files
committed
Add Driver for php-vips extension
1 parent afa3bfb commit 2fdd8e8

File tree

5 files changed

+121
-7
lines changed

5 files changed

+121
-7
lines changed

Readme.md

+6-5
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,12 @@ Dynamic::convertInto($reader, "/output.jpg", Format::JPG);
153153

154154
## Drivers
155155

156-
| Name | Requirements | Description |
157-
| ------- | ----------------------------- | ------------------------------------------------------------ |
158-
| Dynamic | one of : ext-imagick, ext-gd | Manipulates images using the appropriate PHP image extension |
159-
| Gd | ext-gd | gd use only 7 bits for the alpha channel instead of 8 |
160-
| Imagick | ext-imagick | imagick must have been compiled against ImageMagick >= 6.4.0 |
156+
| Name | Requirements | Description |
157+
| ------- | ----------------------- | ------------------------------------------------------------ |
158+
| Dynamic | at least one of the ext | Manipulates images using the appropriate PHP image extension |
159+
| Gd | ext-gd | gd use only 7 bits for the alpha channel instead of 8 |
160+
| Imagick | ext-imagick | imagick must have been compiled against ImageMagick >= 6.4.0 |
161+
| Vips | ext-vips | |
161162

162163

163164
## Supported images format

composer.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
},
1717
"suggests": {
1818
"ext-gd": "Required to convert images using gd",
19-
"ext-imagick": "Required to convert images using imagick"
19+
"ext-imagick": "Required to convert images using imagick",
20+
"ext-vips": "Required to convert images using vips"
2021
},
2122
"autoload": {
2223
"psr-4": {

src/Driver/Dynamic.php

+15
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class Dynamic
3434
public static function loadFromFile(string $filepath): ?Context
3535
{
3636
$function = match(true) {
37+
function_exists('vips_image_new_from_file') => static::useVips(...),
3738
class_exists("\Imagick") => static::useImagick(...),
3839
class_exists("\GdImage") => static::useGdImage(...),
3940
default => throw new \Exception()
@@ -80,4 +81,18 @@ private static function useImagick(string $filepath): ?Context
8081

8182
return new Context($descriptor, $iterator);
8283
}
84+
85+
private static function useVips(string $filepath): ?Context
86+
{
87+
try {
88+
$image = Vips::loadFromFile($filepath);
89+
$descriptor = Vips::createImageDescriptor($image, $filepath);
90+
} catch (\Exception $e) {
91+
return null;
92+
}
93+
94+
$iterator = Vips::createIterator($image, $descriptor);
95+
96+
return new Context($descriptor, $iterator);
97+
}
8398
}

src/Driver/Vips.php

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?php
2+
3+
/**
4+
* MIT License
5+
*
6+
* Copyright (c) 2021 Kevin Masseix
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in all
16+
* copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24+
* SOFTWARE.
25+
*/
26+
27+
namespace MKCG\Image\QOI\Driver;
28+
29+
use MKCG\Image\QOI\ImageDescriptor;
30+
use MKCG\Image\QOI\Colorspace;
31+
use MKCG\Image\QOI\Context;
32+
use MKCG\Image\QOI\Format;
33+
34+
class Vips
35+
{
36+
public static function loadFromFile(string $filepath): mixed
37+
{
38+
return match(($result = vips_image_new_from_file($filepath, []))) {
39+
-1 => throw new \Exception(),
40+
default => $result['out']
41+
};
42+
}
43+
44+
public static function createImageDescriptor($image, string $filepath): ImageDescriptor
45+
{
46+
$width = static::get($image, 'width');
47+
$height = static::get($image, 'height');
48+
$bands = static::get($image, 'bands');
49+
$interpretation = static::get($image, 'interpretation');
50+
$channels = 3;
51+
52+
if ($bands === 2 || $bands > 4 || ($bands === 4 && $interpretation !== "cmyk")) {
53+
$channels = 4;
54+
}
55+
56+
return new ImageDescriptor($width, $height, $channels, Colorspace::SRGB);
57+
}
58+
59+
public static function createIterator($image, ImageDescriptor $descriptor): iterable
60+
{
61+
$bin = vips_image_write_to_memory($image) or throw new \Exception();
62+
$length = strlen($bin);
63+
64+
$bands = static::get($image, 'bands');
65+
66+
if ($bands === 1) {
67+
for ($i = 0; $i < $length; $i++) {
68+
$byte = ord($bin[$i]);
69+
$alpha = $descriptor->channels === 4 ? $byte : 255;
70+
yield [ $byte, $byte, $byte, $alpha ];
71+
}
72+
} else {
73+
if ($length !== $descriptor->countBytes()) {
74+
throw new \Exception();
75+
}
76+
77+
for ($i = 0; $i < $length; $i += $descriptor->channels) {
78+
$pixel = [
79+
ord($bin[$i]),
80+
ord($bin[$i + 1]),
81+
ord($bin[$i + 2]),
82+
$descriptor->channels == 4 ? ord($bin[$i + 3]) : 255,
83+
];
84+
85+
yield $pixel;
86+
}
87+
}
88+
}
89+
90+
private static function get($image, $name)
91+
{
92+
return match(($result = vips_image_get($image, $name))) {
93+
-1 => throw new \Exception(),
94+
default => $result['out'],
95+
};
96+
}
97+
}

src/FFI/lib/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
build:
2-
gcc qoi.c -O1 -std=gnu99 -shared -lm -o "./../bin/$(shell uname -p).so"
2+
gcc qoi.c -O1 -std=gnu99 -shared -o "./../bin/$(shell uname -p).so"

0 commit comments

Comments
 (0)