<p>As far as I know, Craft only provides two controller endpoints that can be used by anonymous users to transform images, both of which won't work well in your case:</p>
<ol>
<li><a href="https://docs.craftcms.com/api/v3/craft-controllers-assetscontroller.html#method-actionthumb" rel="nofollow noreferrer">AssetsController::actionThumb()</a> – This one takes a width and a height argument, but is geared towards generating thumbnails and doesn't work well for a general purpose image resizer, and it doesn't accept a quality argument.</li>
<li><a href="https://docs.craftcms.com/api/v3/craft-controllers-assetscontroller.html#method-actiongeneratetransform" rel="nofollow noreferrer">AssetsController::actionGenerateTransform()</a> – This one generates a transform based on a transform ID or an asset ID &amp; transform handle, but you can only use predefined transforms, it doesn't allow dynamic width/height parameters.</li>
</ol>
<p>So you're probably stuck building your own. But that's quite doable:</p>
<ol>
<li>Create a <a href="https://craftcms.com/docs/3.x/extend/controllers.html" rel="nofollow noreferrer">custom controller</a>, either in a plugin or a module.</li>
<li>Set the controller to allow anonymous requests and don't use CSRF validation (see the sample code below).</li>
<li>Add an action-method with arguments for the asset, width, height and any other parameters you want, like the quality. This methods needs to find the asset in question, transform it with the given arguments and return the resulting file as binary data.</li>
</ol>
<p>One thing that might be a bit tricky is to find the correct asset if you're passing a path instead of an ID. You could either make your frontend handle assets by their IDs instead of their path, which would simplify the backend code. Or deconstruct the path in your controller to determine the folder / volume and <a href="https://craftcms.com/docs/3.x/assets.html#querying-assets" rel="nofollow noreferrer">query by those</a>.</p>
<p>Here's some sample code to get you started (assuming you're writing your controller as a module, not a plugin):</p>
<pre class="lang-php prettyprint-override"><code>&lt;?php
namespace modules\Assets;

use Craft;
use craft\web\Controller;

class TransformController extends Controller
{
    protected $allowAnonymous = self::ALLOW_ANONYMOUS_LIVE;

    public $enableCsrfValidation = false;

    public function actionTransformAsset(int $assetId, int $width, int $height) {
        // 1. find asset based on the parameter
        $asset = Asset::find()-&gt;id($assetId)-&gt;one();
        if (!$asset) {
            throw new BadRequestHttpException('Invalid asset ID');
        }

        // 2. transform the asset with the given width &amp; height parameters
        $asset-&gt;setTransform(['width' =&gt; $width, 'height' =&gt; $height]);

        // 3. return the transformed asset as binary stream
        // Tip: Ensure asset transforms are executed immediately like this:
        Craft::$app-&gt;getConfig()-&gt;getGeneral()-&gt;generateTransformsBeforePageLoad = true;
    }
}
</code></pre>

CC BY-SA 4.0
2021-06-15T14:17:38.177Z
2021-06-17T15:33:38.203Z
2021-06-17T15:33:38.203Z
MoritzLost
<p>NextJS has a really nice <a href="https://nextjs.org/docs/basic-features/image-optimization#image-component" rel="nofollow noreferrer">image</a> component. To implement this I need to create a custom serialiser to get the image sizes from Craft . I can define a custom <a href="https://nextjs.org/docs/api-reference/next/image#loader" rel="nofollow noreferrer">loader</a>, however I'm not sure how feasible this is in Craft.</p>
<p>Here's an example loader function:</p>
<pre class="lang-js prettyprint-override"><code>const craftImageLoader = ({ src, width, quality }) =&gt;
  `https://example.com/${src}?w=${width}&amp;q=${quality || 75}`;
</code></pre>
<p>Does Craft have an image endpoint that accepts these arguments? Perhaps even just src and width? If not then I will probably just write a module to handle this for me.</p>

CC BY-SA 4.0
2021-08-16T17:13:25.513Z
Can you use graphql? I've used next/image with craftcms via graphql with zero issues
magicspon
<image-transforms><image>
Using NextJS image component with CraftCMS
# Using NextJS image component with CraftCMS

(Asked by: username_0 on 2021-06-10)

NextJS has a really nice image component. To implement this I need to create a custom serialiser to get the image sizes from Craft . I can define a custom loader, however I'm not sure how feasible this is in Craft.
Here's an example loader function:
const craftImageLoader = ({ src, width, quality }) =>
  `https://example.com/${src}?w=${width}&q=${quality || 75}`;

Does Craft have an image endpoint that accepts these arguments? Perhaps even just src and width? If not then I will probably just write a module to handle this for me.

**Tags:** image-transforms, image

> **Comments:**
> **username_1**: Can you use graphql? I've used next/image with craftcms via graphql with zero issues  

---

## 1 answers

### Answer by username_2 on 2021-06-15. Score: 2

As far as I know, Craft only provides two controller endpoints that can be used by anonymous users to transform images, both of which won't work well in your case:

AssetsController::actionThumb() – This one takes a width and a height argument, but is geared towards generating thumbnails and doesn't work well for a general purpose image resizer, and it doesn't accept a quality argument.
AssetsController::actionGenerateTransform() – This one generates a transform based on a transform ID or an asset ID & transform handle, but you can only use predefined transforms, it doesn't allow dynamic width/height parameters.

So you're probably stuck building your own. But that's quite doable:

Create a custom controller, either in a plugin or a module.
Set the controller to allow anonymous requests and don't use CSRF validation (see the sample code below).
Add an action-method with arguments for the asset, width, height and any other parameters you want, like the quality. This methods needs to find the asset in question, transform it with the given arguments and return the resulting file as binary data.

One thing that might be a bit tricky is to find the correct asset if you're passing a path instead of an ID. You could either make your frontend handle assets by their IDs instead of their path, which would simplify the backend code. Or deconstruct the path in your controller to determine the folder / volume and query by those.
Here's some sample code to get you started (assuming you're writing your controller as a module, not a plugin):
id($assetId)->one();
        if (!$asset) {
            throw new BadRequestHttpException('Invalid asset ID');
        }

        // 2. transform the asset with the given width & height parameters
        $asset->setTransform(['width' => $width, 'height' => $height]);

        // 3. return the transformed asset as binary stream
        // Tip: Ensure asset transforms are executed immediately like this:
        Craft::$app->getConfig()->getGeneral()->generateTransformsBeforePageLoad = true;
    }
}


---

