1

I started coding a custom plugin, it takes a video file from the asset and showing the file in a video-player (CP). The user is now able to take screenshots of the video (using JS) by clicking a button. The JS code exports a base64-encoded image.

I managed it to get the video file into the plugin, but I have no clue how to save these screenshots in an asset (subfolder of the video).

I'm not really familiar with php, that's why I stuck here.

Is it even possible to save base64 images?

Looking for help, many thanks in advance. And thank you guys for all the work here on this page, it already helped my a lot.

BTW: If anyone is interested in helping me out with a proper coded custom plugin, let me know, it`s payed. ;-)

2

You need to create a Controller to handle the server-side saving of the image. The Controller should roughly perform the following steps:

  1. Receive and validate a POST request with the base64-encoded image as the request body.
  2. Convert the base64 back to binary (you can use the base64_decode function) and store it on disk in a temporary location.
  3. Create the subfolder to store the image in (the action method should also accept the ID of the original video so that it can find the video asset and put the screenshots in the right folder).
  4. Programmatically create an Asset. Check out the example code given in the documentation for craft\services\Elements::saveElement. Assets work similar, only you're creating an craft\elements\Asset object instead of an Entry. I'll include some sample code to get you started below.
  5. Save the asset (it's moved to the appropriate folder automatically if you use the sample code below). Respond to the request with the ID of the newly created asset, or with error messages in case something goes wrong.

Beyond that, make sure to check the documentation on Controllers linked above regarding the following topics:

  • Access control.
  • Parameter / POST body handling (the endpoint should only allow POST requests).
  • Validation (validate the base64-encoded image and any additional parameters like the asset ID of the video).

Once the Controller with that endpoint is in place, you can post to it from your JavaScript code once you want to save the screenshot using fetch().

Create an asset programmatically

Just some sample code for creating an asset to get you started:

<?php

use craft\elements\Asset;

$tmpPath = Craft::$app->getPath()->getTempPath() . '/tmp-screenshots/';

// generate this file from the post body using base64_decode and file_put_contents
$tmpFile = $tmpPath . 'decoded-image-file.jpg';

// create a new asset
$asset = new Asset();
$asset->tempFilePath = $tmpFile;
$asset->filename = 'screenshot-xy.jpg';
$asset->title = 'Screenshot XY';
$asset->avoidFilenameConflicts = true;
$asset->setScenario(Asset::SCENARIO_CREATE);

// you can determine $volume and $folder using the ID of the video asset
$asset->newFolderId = $folder->id;
$asset->volumeId = $volume->id;
$asset->uploaderId = $author->id;

// save the asset
$success = Craft::$app->getElements()->saveElement($asset);
if (!$success) {
    // respond with errors ($asset->getErrors())
}
1
  • 1
    thank you very much for your detailed answer. I will try to get it work the next days.
    – Crazy Haps
    Nov 24 at 15:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.