Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1441 ariadna 1
<?php
2
 
3
namespace PhpOffice\PhpSpreadsheet\Worksheet;
4
 
5
use GdImage;
6
use PhpOffice\PhpSpreadsheet\Exception;
7
use PhpOffice\PhpSpreadsheet\Shared\File;
8
 
9
class MemoryDrawing extends BaseDrawing
10
{
11
    // Rendering functions
12
    const RENDERING_DEFAULT = 'imagepng';
13
    const RENDERING_PNG = 'imagepng';
14
    const RENDERING_GIF = 'imagegif';
15
    const RENDERING_JPEG = 'imagejpeg';
16
 
17
    // MIME types
18
    const MIMETYPE_DEFAULT = 'image/png';
19
    const MIMETYPE_PNG = 'image/png';
20
    const MIMETYPE_GIF = 'image/gif';
21
    const MIMETYPE_JPEG = 'image/jpeg';
22
 
23
    const SUPPORTED_MIME_TYPES = [
24
        self::MIMETYPE_GIF,
25
        self::MIMETYPE_JPEG,
26
        self::MIMETYPE_PNG,
27
    ];
28
 
29
    /**
30
     * Image resource.
31
     */
32
    private null|GdImage $imageResource = null;
33
 
34
    /**
35
     * Rendering function.
36
     *
37
     * @var callable-string
38
     */
39
    private string $renderingFunction;
40
 
41
    /**
42
     * Mime type.
43
     */
44
    private string $mimeType;
45
 
46
    /**
47
     * Unique name.
48
     */
49
    private string $uniqueName;
50
 
51
    /**
52
     * Create a new MemoryDrawing.
53
     */
54
    public function __construct()
55
    {
56
        // Initialise values
57
        $this->renderingFunction = self::RENDERING_DEFAULT;
58
        $this->mimeType = self::MIMETYPE_DEFAULT;
59
        $this->uniqueName = md5(mt_rand(0, 9999) . time() . mt_rand(0, 9999));
60
 
61
        // Initialize parent
62
        parent::__construct();
63
    }
64
 
65
    public function __destruct()
66
    {
67
        if ($this->imageResource) {
68
            @imagedestroy($this->imageResource);
69
            $this->imageResource = null;
70
        }
71
        $this->worksheet = null;
72
    }
73
 
74
    public function __clone()
75
    {
76
        parent::__clone();
77
        $this->cloneResource();
78
    }
79
 
80
    private function cloneResource(): void
81
    {
82
        if (!$this->imageResource) {
83
            return;
84
        }
85
 
86
        $width = (int) imagesx($this->imageResource);
87
        $height = (int) imagesy($this->imageResource);
88
 
89
        if (imageistruecolor($this->imageResource)) {
90
            $clone = imagecreatetruecolor($width, $height);
91
            if (!$clone) {
92
                throw new Exception('Could not clone image resource');
93
            }
94
 
95
            imagealphablending($clone, false);
96
            imagesavealpha($clone, true);
97
        } else {
98
            $clone = imagecreate($width, $height);
99
            if (!$clone) {
100
                throw new Exception('Could not clone image resource');
101
            }
102
 
103
            // If the image has transparency...
104
            $transparent = imagecolortransparent($this->imageResource);
105
            if ($transparent >= 0) {
106
                // Starting with Php8.0, next function throws rather than return false
107
                $rgb = imagecolorsforindex($this->imageResource, $transparent);
108
 
109
                imagesavealpha($clone, true);
110
                $color = imagecolorallocatealpha($clone, $rgb['red'], $rgb['green'], $rgb['blue'], $rgb['alpha']);
111
                if ($color === false) {
112
                    throw new Exception('Could not get image alpha color');
113
                }
114
 
115
                imagefill($clone, 0, 0, $color);
116
            }
117
        }
118
 
119
        //Create the Clone!!
120
        imagecopy($clone, $this->imageResource, 0, 0, 0, 0, $width, $height);
121
 
122
        $this->imageResource = $clone;
123
    }
124
 
125
    /**
126
     * @param resource $imageStream Stream data to be converted to a Memory Drawing
127
     *
128
     * @throws Exception
129
     */
130
    public static function fromStream($imageStream): self
131
    {
132
        $streamValue = stream_get_contents($imageStream);
133
        if ($streamValue === false) {
134
            throw new Exception('Unable to read data from stream');
135
        }
136
 
137
        return self::fromString($streamValue);
138
    }
139
 
140
    /**
141
     * @param string $imageString String data to be converted to a Memory Drawing
142
     *
143
     * @throws Exception
144
     */
145
    public static function fromString(string $imageString): self
146
    {
147
        $gdImage = @imagecreatefromstring($imageString);
148
        if ($gdImage === false) {
149
            throw new Exception('Value cannot be converted to an image');
150
        }
151
 
152
        $mimeType = self::identifyMimeType($imageString);
153
        if (imageistruecolor($gdImage) || imagecolortransparent($gdImage) >= 0) {
154
            imagesavealpha($gdImage, true);
155
        }
156
        $renderingFunction = self::identifyRenderingFunction($mimeType);
157
 
158
        $drawing = new self();
159
        $drawing->setImageResource($gdImage);
160
        $drawing->setRenderingFunction($renderingFunction);
161
        $drawing->setMimeType($mimeType);
162
 
163
        return $drawing;
164
    }
165
 
166
    /** @return callable-string */
167
    private static function identifyRenderingFunction(string $mimeType): string
168
    {
169
        return match ($mimeType) {
170
            self::MIMETYPE_PNG => self::RENDERING_PNG,
171
            self::MIMETYPE_JPEG => self::RENDERING_JPEG,
172
            self::MIMETYPE_GIF => self::RENDERING_GIF,
173
            default => self::RENDERING_DEFAULT,
174
        };
175
    }
176
 
177
    /**
178
     * @throws Exception
179
     */
180
    private static function identifyMimeType(string $imageString): string
181
    {
182
        $temporaryFileName = File::temporaryFilename();
183
        file_put_contents($temporaryFileName, $imageString);
184
 
185
        $mimeType = self::identifyMimeTypeUsingExif($temporaryFileName);
186
        if ($mimeType !== null) {
187
            unlink($temporaryFileName);
188
 
189
            return $mimeType;
190
        }
191
 
192
        $mimeType = self::identifyMimeTypeUsingGd($temporaryFileName);
193
        if ($mimeType !== null) {
194
            unlink($temporaryFileName);
195
 
196
            return $mimeType;
197
        }
198
 
199
        unlink($temporaryFileName);
200
 
201
        return self::MIMETYPE_DEFAULT;
202
    }
203
 
204
    private static function identifyMimeTypeUsingExif(string $temporaryFileName): ?string
205
    {
206
        if (function_exists('exif_imagetype')) {
207
            $imageType = @exif_imagetype($temporaryFileName);
208
            $mimeType = ($imageType) ? image_type_to_mime_type($imageType) : null;
209
 
210
            return self::supportedMimeTypes($mimeType);
211
        }
212
 
213
        return null;
214
    }
215
 
216
    private static function identifyMimeTypeUsingGd(string $temporaryFileName): ?string
217
    {
218
        if (function_exists('getimagesize')) {
219
            $imageSize = @getimagesize($temporaryFileName);
220
            if (is_array($imageSize)) {
221
                $mimeType = $imageSize['mime'];
222
 
223
                return self::supportedMimeTypes($mimeType);
224
            }
225
        }
226
 
227
        return null;
228
    }
229
 
230
    private static function supportedMimeTypes(?string $mimeType = null): ?string
231
    {
232
        if (in_array($mimeType, self::SUPPORTED_MIME_TYPES, true)) {
233
            return $mimeType;
234
        }
235
 
236
        return null;
237
    }
238
 
239
    /**
240
     * Get image resource.
241
     */
242
    public function getImageResource(): ?GdImage
243
    {
244
        return $this->imageResource;
245
    }
246
 
247
    /**
248
     * Set image resource.
249
     *
250
     * @return $this
251
     */
252
    public function setImageResource(?GdImage $value): static
253
    {
254
        $this->imageResource = $value;
255
 
256
        if ($this->imageResource !== null) {
257
            // Get width/height
258
            $this->width = (int) imagesx($this->imageResource);
259
            $this->height = (int) imagesy($this->imageResource);
260
        }
261
 
262
        return $this;
263
    }
264
 
265
    /**
266
     * Get rendering function.
267
     *
268
     * @return callable-string
269
     */
270
    public function getRenderingFunction(): string
271
    {
272
        return $this->renderingFunction;
273
    }
274
 
275
    /**
276
     * Set rendering function.
277
     *
278
     * @param callable-string $value see self::RENDERING_*
279
     *
280
     * @return $this
281
     */
282
    public function setRenderingFunction(string $value): static
283
    {
284
        $this->renderingFunction = $value;
285
 
286
        return $this;
287
    }
288
 
289
    /**
290
     * Get mime type.
291
     */
292
    public function getMimeType(): string
293
    {
294
        return $this->mimeType;
295
    }
296
 
297
    /**
298
     * Set mime type.
299
     *
300
     * @param string $value see self::MIMETYPE_*
301
     *
302
     * @return $this
303
     */
304
    public function setMimeType(string $value): static
305
    {
306
        $this->mimeType = $value;
307
 
308
        return $this;
309
    }
310
 
311
    /**
312
     * Get indexed filename (using image index).
313
     */
314
    public function getIndexedFilename(): string
315
    {
316
        $extension = strtolower($this->getMimeType());
317
        $extension = explode('/', $extension);
318
        $extension = $extension[1];
319
 
320
        return $this->uniqueName . $this->getImageIndex() . '.' . $extension;
321
    }
322
 
323
    /**
324
     * Get hash code.
325
     *
326
     * @return string Hash code
327
     */
328
    public function getHashCode(): string
329
    {
330
        return md5(
331
            $this->renderingFunction
332
            . $this->mimeType
333
            . $this->uniqueName
334
            . parent::getHashCode()
335
            . __CLASS__
336
        );
337
    }
338
}