Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
89.47% covered (warning)
89.47%
17 / 19
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
GifParser
89.47% covered (warning)
89.47%
17 / 19
50.00% covered (danger)
50.00%
1 / 2
5.03
0.00% covered (danger)
0.00%
0 / 1
 parseFile
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 parse
86.67% covered (warning)
86.67%
13 / 15
0.00% covered (danger)
0.00%
0 / 1
4.04
1<?php
2
3declare(strict_types=1);
4
5namespace Phpdftk\ImageMetadata;
6
7use Phpdftk\Filesystem\LocalFilesystem;
8
9/**
10 * Parse GIF logical screen descriptor for dimensions and color info.
11 *
12 * GIF is palette-based — always reported as DeviceRGB since PDF
13 * requires explicit color space declaration.
14 */
15final class GifParser
16{
17    public static function parseFile(string $path): ImageInfo
18    {
19        $fh = LocalFilesystem::openReadable($path, "image file");
20        try {
21            $data = fread($fh, 13);
22        } finally {
23            fclose($fh);
24        }
25        return self::parse($data);
26    }
27
28    public static function parse(string $data): ImageInfo
29    {
30        if (strlen($data) < 13) {
31            throw new \RuntimeException('Not enough data for a valid GIF file');
32        }
33
34        $header = substr($data, 0, 6);
35        if ($header !== 'GIF87a' && $header !== 'GIF89a') {
36            throw new \RuntimeException('Not a valid GIF file');
37        }
38
39        // Width and height are little-endian 16-bit at bytes 6-7 and 8-9
40        $width  = unpack('v', substr($data, 6, 2))[1];
41        $height = unpack('v', substr($data, 8, 2))[1];
42
43        return new ImageInfo(
44            width: $width,
45            height: $height,
46            colorSpace: 'DeviceRGB',
47            bitsPerComponent: 8,
48            format: 'gif',
49            hasAlpha: false,
50        );
51    }
52}