Used to create a custom transform extension.

Example

Below we use the createTransformExtension function to create an image editor extension powered by Pintura.

To further improve the media uploading experience we can combine this extension with the MediaResolutionValidator and ImageBitmapTransform extensions.

import { defineFilePond, createTransformExtension } from 'filepond';
import { locale } from 'filepond/locales/en-gb.js';
import { createFilePondEntryList, appendEntryImageView } from 'filepond/templates/index.js';
import { ConsoleView } from 'filepond/extensions/console-view.js';

// helper function to load stylesheets
function link(src) {
    return new Promise((resolve) => {
        // already added this link
        if (document.querySelector(`link[href="${src}"]`)) {
            resolve();
            return;
        }

        // new link
        const link = document.createElement('link');
        link.rel = 'stylesheet';
        link.onload = resolve;
        link.href = src;
        document.head.append(link);
    });
}

// our custom transform
const PinturaTransform = createTransformExtension(
    // The name of our extension
    'PinturaTransform',

    // Default settings
    {
        actionTransform: 'editMedia',
    },
    // Extension internals, these are used by `createTransformExtension`
    ({ extensionName }) => ({
        // The `canTransformEntry` is called to test if we can transform an image
        // Here we use a cheap, but not always accurate, method to test if an entry can be transformed
        canTransformEntry: (entry) => /video|image/.test(entry.type),

        // Use the `prepareTransformEntry` hook to preload dependencies
        prepareTransformEntry: async (entry, { onprogress, abortController }) => {
            // load styles
            await link('https://unpkg.com/@pqina/pintura@8/pintura.css');

            // load scripts
            await import('@pqina/pintura');
        },

        // The `transformEntry` function is called when we're ready to transform an entry
        transformEntry: async (entry, { onprogress, abortController }) => {
            // @pqina/pintura should be cached, so it's instantly available now
            const { openDefaultEditor } = await import('@pqina/pintura');

            // Get props
            const { file, extension } = entry;
            const { input, history = [] } = extension[extensionName];

            // Determine which file to edit
            const src = input || file;

            // Open the file in the editor
            const editor = openDefaultEditor({
                src,

                // We require a square crop
                imageCropAspectRatio: 1,
            });

            // Restore any previously stored history state
            if (history.length) {
                editor.on('load', () => {
                    editor.history.write(history.pop());
                });
            }

            // Returns the edited file and its image state
            const { dest, imageState } = await new Promise((resolve) => {
                editor.on('process', resolve);
                editor.on('close', () =>
                    resolve({
                        // We don't return a result
                    })
                );
            });

            // clean up the editor
            editor.destroy();

            // User closed the editor
            if (!dest) {
                return;
            }

            // Return transformed file and optionally update history
            return {
                file: dest,
                history: [...history, imageState],
            };
        },
    })
);

// Add image view to default template
const template = createFilePondEntryList();
appendEntryImageView(template);

// Now we can use `PinturaTransform` like this
const elements = defineFilePond({
    locale,

    // Load extensions
    extensions: [PinturaTransform, ConsoleView],

    // Pass custom template to EntryListView
    EntryListView: {
        template,
    },
});