Completed
Push — master ( a50e59...22377b )
by Freek
10:42
created

src/ResponsiveImages/ResponsiveImageGenerator.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Spatie\MediaLibrary\ResponsiveImages;
4
5
use Spatie\MediaLibrary\Helpers\File;
6
use Spatie\MediaLibrary\Models\Media;
7
use Spatie\MediaLibrary\Helpers\ImageFactory;
8
use Spatie\MediaLibrary\Conversion\Conversion;
9
use Spatie\MediaLibrary\Filesystem\Filesystem;
10
use Spatie\MediaLibrary\Helpers\TemporaryDirectory;
11
use Spatie\MediaLibrary\Events\ResponsiveImagesGenerated;
12
use Spatie\MediaLibrary\ResponsiveImages\Exceptions\InvalidTinyJpg;
13
use Spatie\MediaLibrary\ResponsiveImages\WidthCalculator\WidthCalculator;
14
use Spatie\TemporaryDirectory\TemporaryDirectory as BaseTemporaryDirectory;
15
use Spatie\MediaLibrary\ResponsiveImages\TinyPlaceholderGenerator\TinyPlaceholderGenerator;
16
17
class ResponsiveImageGenerator
18
{
19
    /** \Spatie\MediaLibrary\Filesystem\Filesystem */
20
    protected $filesystem;
21
22
    /** \Spatie\MediaLibrary\ResponsiveImages\WidthCalculator\WidthCalculator */
23
    protected $widthCalculator;
24
25
    /** \Spatie\MediaLibrary\ResponsiveImages\TinyPlaceHolderGenerator\TinyPlaceHolderGenerator */
26
    protected $tinyPlaceholderGenerator;
27
28
    public function __construct(
29
        Filesystem $filesystem,
30
        WidthCalculator $widthCalculator,
31
        TinyPlaceholderGenerator $tinyPlaceholderGenerator
32
    ) {
33
        $this->filesystem = $filesystem;
34
35
        $this->widthCalculator = $widthCalculator;
36
37
        $this->tinyPlaceholderGenerator = $tinyPlaceholderGenerator;
38
    }
39
40
    public function generateResponsiveImages(Media $media)
41
    {
42
        $temporaryDirectory = TemporaryDirectory::create();
43
44
        $baseImage = app(Filesystem::class)->copyFromMediaLibrary(
45
            $media,
46
            $temporaryDirectory->path(str_random(16).'.'.$media->extension)
0 ignored issues
show
Deprecated Code introduced by
The function str_random() has been deprecated with message: Str::random() should be used directly instead. Will be removed in Laravel 5.9.

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
47
        );
48
49
        $media = $this->cleanResponsiveImages($media);
50
51
        foreach ($this->widthCalculator->calculateWidthsFromFile($baseImage) as $width) {
52
            $this->generateResponsiveImage($media, $baseImage, 'medialibrary_original', $width, $temporaryDirectory);
53
        }
54
55
        event(new ResponsiveImagesGenerated($media));
56
57
        $this->generateTinyJpg($media, $baseImage, 'medialibrary_original', $temporaryDirectory);
58
59
        $temporaryDirectory->delete();
60
    }
61
62
    public function generateResponsiveImagesForConversion(Media $media, Conversion $conversion, string $baseImage)
63
    {
64
        $temporaryDirectory = TemporaryDirectory::create();
65
66
        $media = $this->cleanResponsiveImages($media, $conversion->getName());
67
68
        foreach ($this->widthCalculator->calculateWidthsFromFile($baseImage) as $width) {
69
            $this->generateResponsiveImage($media, $baseImage, $conversion->getName(), $width, $temporaryDirectory);
70
        }
71
72
        $this->generateTinyJpg($media, $baseImage, $conversion->getName(), $temporaryDirectory);
73
74
        $temporaryDirectory->delete();
75
    }
76
77
    public function generateResponsiveImage(
78
        Media $media,
79
        string $baseImage,
80
        string $conversionName,
81
        int $targetWidth,
82
        BaseTemporaryDirectory $temporaryDirectory
83
    ) {
84
        $responsiveImagePath = $this->appendToFileName($media->file_name, "___{$conversionName}_{$targetWidth}");
85
86
        $tempDestination = $temporaryDirectory->path($responsiveImagePath);
87
88
        ImageFactory::load($baseImage)
89
            ->optimize()
90
            ->width($targetWidth)
91
            ->save($tempDestination);
92
93
        $responsiveImageHeight = ImageFactory::load($tempDestination)->getHeight();
94
95
        $finalImageFileName = $this->appendToFileName($responsiveImagePath, "_{$responsiveImageHeight}");
96
97
        $finalResponsiveImagePath = $temporaryDirectory->path($finalImageFileName);
98
99
        rename($tempDestination, $finalResponsiveImagePath);
100
101
        $this->filesystem->copyToMediaLibrary($finalResponsiveImagePath, $media, 'responsiveImages');
102
103
        ResponsiveImage::register($media, $finalImageFileName, $conversionName);
104
    }
105
106
    public function generateTinyJpg(Media $media, string $originalImagePath, string $conversionName, BaseTemporaryDirectory $temporaryDirectory)
107
    {
108
        $tempDestination = $temporaryDirectory->path('tiny.jpg');
109
110
        $this->tinyPlaceholderGenerator->generateTinyPlaceholder($originalImagePath, $tempDestination);
111
112
        $this->guardAgainstInvalidTinyPlaceHolder($tempDestination);
113
114
        $tinyImageDataBase64 = base64_encode(file_get_contents($tempDestination));
115
116
        $tinyImageBase64 = 'data:image/jpeg;base64,'.$tinyImageDataBase64;
117
118
        $originalImage = ImageFactory::load($originalImagePath);
119
120
        $originalImageWidth = $originalImage->getWidth();
121
122
        $originalImageHeight = $originalImage->getHeight();
123
124
        $svg = view('medialibrary::placeholderSvg', compact(
125
            'originalImageWidth',
126
            'originalImageHeight',
127
            'tinyImageBase64'
128
        ));
129
130
        $base64Svg = 'data:image/svg+xml;base64,'.base64_encode($svg);
131
132
        ResponsiveImage::registerTinySvg($media, $base64Svg, $conversionName);
133
    }
134
135
    protected function appendToFileName(string $filePath, string $suffix): string
136
    {
137
        $baseName = pathinfo($filePath, PATHINFO_FILENAME);
138
139
        $extension = pathinfo($filePath, PATHINFO_EXTENSION);
140
141
        return $baseName.$suffix.'.'.$extension;
142
    }
143
144
    protected function guardAgainstInvalidTinyPlaceHolder(string $tinyPlaceholderPath)
145
    {
146
        if (! file_exists($tinyPlaceholderPath)) {
147
            throw InvalidTinyJpg::doesNotExist($tinyPlaceholderPath);
148
        }
149
150
        $mimeType = File::getMimetype($tinyPlaceholderPath);
151
152
        if ($mimeType !== 'image/jpeg') {
153
            throw InvalidTinyJpg::hasWrongMimeType($tinyPlaceholderPath);
154
        }
155
    }
156
157
    protected function cleanResponsiveImages(Media $media, string $conversionName = 'medialibrary_original') : Media
158
    {
159
        $responsiveImages = $media->responsive_images;
160
        $responsiveImages[$conversionName]['urls'] = [];
161
        $media->responsive_images = $responsiveImages;
162
163
        $this->filesystem->removeResponsiveImages($media, $conversionName);
164
165
        return $media;
166
    }
167
}
168