silverstripe / silverstripe-assets

Silverstripe Assets component
BSD 3-Clause "New" or "Revised" License
9 stars 65 forks source link

NEW Allow file variants with different extensions #585

Closed GuySartorelli closed 5 months ago

GuySartorelli commented 5 months ago

Description

Provides a low-level API for generating a file variant which has a different extension than the original file. e.g. could be used for:

Manual testing steps

  1. Upload a video file.
  2. Upload a document file.
  3. Use this code for PageController. Replace /var/www/html/.eddev/samples/snickers.jpg with the absolute path to some arbitrary image file your site can access (or replace that logic with something to actually generate a file from the video - I'm taking some shortcuts in that regard) Replace /var/www/html/.eddev/samples/client-pdf2.pdf with the absolute path to some arbitrary pdf file your site can access (or replace that logic with something to actually generate a pdf from the document - I'm taking some shortcuts in that regard)

    use SilverStripe\Assets\Storage\AssetStore;
    use SilverStripe\Assets\File;
    use SilverStripe\Assets\Image_Backend;
    use SilverStripe\CMS\Controllers\ContentController;
    use SilverStripe\Core\Injector\Injector;
    
    class PageController extends ContentController
    {
        public function getVideoImage()
        {
            $file = File::get()->find('FileFilename:EndsWith', File::get_category_extensions('video'));
            return $file->manipulateExtension('jpg', function (AssetStore $store, string $filename, string $hash, string $variant) {
                $backend = Injector::inst()->create(Image_Backend::class);
                $backend->loadFrom('/var/www/html/.eddev/samples/snickers.jpg');
                $tuple = $backend->writeToStore($store, $filename, $hash, $variant, ['conflict' => AssetStore::CONFLICT_USE_EXISTING]);
                return [$tuple, $backend];
            });
        }
    
        public function getPdfFromDoc()
        {
            $file = File::get()->find('FileFilename:EndsWith', File::get_category_extensions('document'));
            return $file->manipulateExtension('pdf', function (AssetStore $store, string $filename, string $hash, string $variant) {
                $tuple = $store->setFromString(
                    file_get_contents('/var/www/html/.eddev/samples/client-pdf2.pdf'),
                    $filename,
                    $hash,
                    $variant,
                    ['conflict' => AssetStore::CONFLICT_USE_EXISTING]
                );
                return [$tuple, null];
            });
        }
    }
  4. Add this to a page template:
    <a href="$VideoImage.ScaleMaxHeight(200).CropHeight(50).Link">Link to the resized, cropped thumbnail</a> - ID=$VideoImage.ID
    <br>
    <a href="$PdfFromDoc.Link">Link to the "converted" pdf</a> - ID=$PdfFromDoc.ID
  5. Visit a page and click on the links.
    • For the image, you should see an appropriately scaled and cropped copy of your dummy thumbnail image.
    • For the pdf, you should see the pdf file you pointed your code to.
    • The URL should be obviously a variant of the original file
    • The displayed ID numbers should be the original file IDs

You can also try the documentation example of converting one image to another image (e.g. a .jpg to .webp) and see that it also works correctly, even with chained image manipulations.

Issues

Pull request checklist

GuySartorelli commented 5 months ago

Moved the refactoring into https://github.com/silverstripe/silverstripe-assets/pull/587

Marking this as draft because it'll have conflicts once that is merged.

GuySartorelli commented 5 months ago

I'm not even sure if that's viable, to be honest. Each variant is a file. Here you have one variant for the file conversion, and another variant for scaling the image - and because those are discrete steps, they create discrete files.

I'm pretty sure the same thing would happen if you scaled and then rotated an image - you'd have one variant (and therefore one file) for the scaling operation and one for the rotation operation.

I don't think changing that is really feasible - or at least with my current limited understanding of the assets system I can't think of a way to tackle it.