v8.90.3

Interface properties

A list of properties to read from and write to the current state of the editor UI.

Editor properties

These read only properties are available on the editor instance.

Property Description
element The root element of the editor.
history Used to access history state. See history methods for more information.

These read/write properties are available on the editor instance.

Property Default value Description
id
undefined
The id attribute set to the editor root element.
class
undefined
The class attribute set to the editor root element.
locale
undefined
The locale object to use for the editor labels.
csp
undefined
Content security policy configuration, currently only supports nonce for use with inline styles.
utils
undefined
The enabled utils and their order in the menu.
util
undefined
The active util, is automatically set to first util in utils array.
layoutDirectionPreference
'auto'
The direction preference of the editor layout, when is 'auto' the editor will automatically set it to 'vertical' for when the editor root is in portrait aspect ratio and 'horizontal' for landscape aspect ratio.
layoutHorizontalUtilsPreference
'left'
The horizontal location of the utils menu, set to either 'left' or 'right' to move the main navigation to the that side of the image.
layoutVerticalUtilsPreference
'bottom'
The vertical location of the utils menu, set to either 'bottom' or 'top' to move the main navigation to the that side of the image. Will not affect mobile presentation where the menu will always stick to the bottom.
layoutVerticalToolbarPreference
'top'
The vertical location of the toolbar menu, set to either 'bottom' or 'top' to move the toolbar to the that side of the image.
layoutVerticalControlGroupsPreference
'bottom'
The vertical position of the util controls, set to 'top' to show the controls at the top of the image instead of below.
layoutVerticalControlTabsPreference
'bottom'
The position of the util control tabs, set to 'top' to show tabs above the controls instead of below.
textDirection
'ltr'
The direction of text on UI controls, set to 'rtl' to switch to right to left text.
fixScrollDirection
false
Set to true to fix scroll direction on MacOS, by default the scroll direction is inverted.
animations
'auto'
Control if and when animations are shown.
disabled
false
Set to true to disable any interaction with the editor.
status
undefined
Set to a string to show a status message.
elasticityMultiplier
10
Controls the elasticity force of the interface.
previewUpscale
false
Should the image preview be upscaled to fit the editor stage.
previewPad
false
Should the image preview add padding around the image when a frame is rendered on the outside of the image bounds.
previewMaskOpacity
.95
The opacity of the overlay applied to frames when rendered outside of the image bounds.
previewImageData
undefined
The current data used for the image preview. Can be an ImageBitmap, ImageData, or HTMLCanvasElement. Available after 'loadpreview' event.
previewImageDataMaxSize
undefined
Maximum texture size to use for the preview image. Will default to browser max texture size.
previewImageTextPixelRatio
undefined
The pixel density to use for rendering text shapes, will default to window.devicePixelRatio
willSetMediaInitialTimeOffset
undefined
A hook to set the intial time offset shown when loading a video. Defaults to mid point of first clip.
muteAudio
true
Set to false to enable audio by default.
imageSourceToImageData
undefined
The function the editor uses to read preview image data.
enableTransparencyGrid
false
When set to true renders a grid behind the image to reveal transparent areas.
enableCanvasAlpha
false
Set to true to make canvas transparent.
enableToolbar
true
Set to false to disable the toolbar.
enableUtils
true
Set to false to disable the util tabs.
enableButtonClose
false
Set to true to show a close button, automatically set to true when using openModal.
enableButtonExport
true
Set to false to disable the export button.
enableButtonRevert
true
Set to false to disable the history revert button.
enableNavigateHistory
true
Set to false to disable the undo and redo buttons.
enableDropImage
false
Set to true to allow loading a new image by dropping it on the editor.
enablePasteImage
false
Set to true to allow pasting a new image. Editor will accept a pasted image if it's at least 75% in view.
enableBrowseImage
false
Set to true to allow clicking the editor to browse for an image when the editor is in "waiting for image" state.
enablePan
true
Set to false to disable the panning the image.
enablePanInput
undefined
Set to true to force enable pan mode.
pan
null
Set to a position to pan to, set to null to reset.
enableZoom
true
Set to false to disable the zooming the image.
enableZoomControls
true
Set to false to disable the zoom controls.
zoomLevel
null
Set to a number to force a zoom level, set to undefined to fit to view, set to null to have editor handle zoom.
zoomPresetOptions
undefined
An array of zoom levels defined as fractions. Default value is [0.25, 0.5, 1, 1.25, 1.5, 2, 3, 4, 6, 8, 16].
zoomAdjustStep
.25
The speed at which pressing the zoom buttons increases or decreases zoom.
zoomAdjustFactor
.1
The factor used to increase or decrease zoom speed when holding the zoom buttons. Increase speed is 1 + .1, decrease speed is 1 - .1.
zoomAdjustWheelFactor
1
The factor used to convert scroll wheel interactions to zoom steps, higher is faster.
zoomMaskOpacity
.85
The maximum opacity of the overlay rendered behind UI controls when zooming in.
handleEvent
undefined
A function that is called for each event. Receives event type and detail.
willRenderCanvas
undefined
Inject shapes or adjust shapes in the image preview.
willRenderToolbar
undefined
Inject custom buttons into the editor toolbar.
willRenderUtilTabs
undefined
Inject custom tabs, or reorder existing tabs.
willClose
undefined
Prevent close action from user. Only available when using modal.
willRevert
undefined
Prevent revert action from user.
willProcessImage
undefined
Prevent image processing action from user.
willRequest
undefined
Called before requesting a resource.
willRequestResource
undefined
Called before requesting a remote resource. Deprecated use willRequest instead.
willSetHistoryInitialState
undefined
Receives initial history state that is about to be set, return modified state.

locale

When not using one of the default factories the editor requires the locale property to be set to a valid locale object.

In the example below we assign the core editor locale and the crop plugin locale object.

<!DOCTYPE html>

<head>
    <link rel="stylesheet" href="./pintura.css" />
</head>

<style>
    .pintura-editor {
        height: 600px;
    }
</style>

<div id="editor"></div>

<script type="module">
    import {
        appendEditor,
        createDefaultImageReader,
        createDefaultImageWriter,
        createDefaultImageOrienter,
        setPlugins,
        plugin_crop,
        locale_en_gb,
        plugin_crop_locale_en_gb,
    } from './pintura.js';

    setPlugins(plugin_crop);

    const editor = appendEditor('#editor', {
        imageReader: createDefaultImageReader(),
        imageWriter: createDefaultImageWriter(),
        imageOrienter: createDefaultImageOrienter(),
        locale: {
            ...locale_en_gb,
            ...plugin_crop_locale_en_gb,
        },
        src: 'image.jpeg',
    });
</script>

See below for example content of the locale_en_gb object exported by the editor module.

{
    labelDefault: 'Default',
    labelReset: 'Reset',
    labelAuto: 'Auto',
    labelNone: 'None',
    labelEdit: 'Edit',
    labelClose: 'Close',

    // etc...
}

To change a label we can update one of the properties in the locale object.

// Merge the locale objects
const myLocale = {
    ...locale_en_gb,
    ...plugin_crop_locale_en_gb,
};

// Change label of export button to 'Save'
myLocale.labelButtonExport = 'Save';

When we're using one of the default factories we can set the label directly on the locale property.

<!DOCTYPE html>

<head>
    <link rel="stylesheet" href="./pintura.css" />
</head>

<style>
    .pintura-editor {
        height: 600px;
    }
</style>

<div id="editor"></div>

<script type="module">
    import { appendDefaultEditor } from './pintura.js';

    const editor = appendDefaultEditor('#editor', {
        src: 'image.jpeg',
        locale: {
            labelButtonExport: 'Save',
        },
    });
</script>

The code below logs all locale properties to the developer console so we can easily see which property to edit if we need to change labels or icons.

import {
    // core locale
    locale_en_gb,

    // plugin locale
    plugin_crop_locale_en_gb,
    plugin_finetune_locale_en_gb,
    plugin_filter_locale_en_gb,
    plugin_annotate_locale_en_gb,
    plugin_decorate_locale_en_gb,
    plugin_redact_locale_en_gb,
    plugin_resize_locale_en_gb,
    plugin_sticker_locale_en_gb,
    plugin_frame_locale_en_gb,

    // markup editor locale
    markup_editor_locale_en_gb,
} from './pintura.js';

// log merged objects to console
console.log({
    ...locale_en_gb,
    ...plugin_crop_locale_en_gb,
    ...plugin_finetune_locale_en_gb,
    ...plugin_filter_locale_en_gb,
    ...plugin_annotate_locale_en_gb,
    ...plugin_decorate_locale_en_gb,
    ...plugin_resize_locale_en_gb,
    ...plugin_sticker_locale_en_gb,
    ...markup_editor_locale_en_gb,
});

The product package includes additional locale files for other languages.

To load one of the other locales, copy the package locale folder to your project directory and import the locale like shown below.

import { openEditor } from './pintura.js';

import Core, { MarkupEditor } from './locale/de_DE/core/de_DE.js';
import Annotate from './locale/de_DE/annotate/de_DE.js';

openEditor({
    src: 'image.jpeg',
    locale: {
        ...Core,
        ...MarkupEditor,
        ...Annotate,
    },
});

When using the @pqina/pintura package we can import the locale from the package.

import Core, { MarkupEditor } from '@pqina/pintura/locale/de_DE/core';
import Annotate from '@pqina/pintura/locale/de_DE/annotate';

Or we can import all locale objects at once like shown below.

import locale_de_DE from '@pqina/pintura/locale/de_DE';

csp

Configure Content Security Policy.

At this time this prop only accepts an object with styleNonce property. When set this will add a nonce attribute to generated <style> tags.

<!DOCTYPE html>

<head>
    <link rel="stylesheet" href="./pintura.css" />
</head>

<style>
    .pintura-editor {
        height: 600px;
    }
</style>

<div id="editor"></div>

<script type="module">
    import { appendDefaultEditor } from './pintura.js';

    const editor = appendDefaultEditor('#editor', {
        src: 'image.jpeg',
        csp: { styleNonce: 'ABCD1234' },
    });
</script>

util

Updates the current active util and will trigger the editor to show the corresponding view.

<!DOCTYPE html>

<head>
    <link rel="stylesheet" href="./pintura.css" />
</head>

<style>
    .pintura-editor {
        height: 600px;
    }
</style>

<div id="editor"></div>

<script type="module">
    import { appendDefaultEditor } from './pintura.js';

    const editor = appendDefaultEditor('#editor', {
        src: 'image.jpeg',
        util: 'finetune',
    });
</script>

utils

Use to set which utils are shown and in what order they appear in the editor menu.

<!DOCTYPE html>

<head>
    <link rel="stylesheet" href="./pintura.css" />
</head>

<style>
    .pintura-editor {
        height: 600px;
    }
</style>

<div id="editor"></div>

<script type="module">
    import { appendDefaultEditor } from './pintura.js';

    const editor = appendDefaultEditor('#editor', {
        src: 'image.jpeg',
        utils: [
            'crop',
            'filter',
            'finetune',
            'annotate',
            'decorate',
            'sticker',
            'frame',
            'redact',
            'resize',
        ],
    });
</script>

layoutDirectionPreference

The direction preference of the editor layout, when is 'auto' the editor will automatically set it to 'vertical' for when the editor root is in portrait aspect ratio and 'horizontal' for landscape aspect ratio. Defaults to 'auto'.

layoutHorizontalUtilsPreference

The horizontal location of the utils menu, set to either 'left' or 'right' to move the main navigation to the that side of the image. Defaults to 'left'.

layoutVerticalUtilsPreference

The vertical location of the utils menu, set to either 'bottom' or 'top' to move the main navigation to the that side of the image. Will not affect mobile presentation where the menu will always stick to the bottom. Defaults to 'bottom'.

layoutVerticalToolbarPreference

The vertical location of the toolbar menu, set to either 'bottom' or 'top' to move the toolbar to the that side of the image. Defaults to 'top'.

layoutVerticalControlGroupsPreference

The vertical position of the util controls, set to 'top' to show the controls at the top of the image instead of below. Defaults to 'bottom'.

layoutVerticalControlTabsPreference

The position of the util control tabs, set to 'top' to show tabs above the controls instead of below. Defaults to 'bottom'.

textDirection

Toggle text direction in the editor interface.

<!DOCTYPE html>

<head>
    <link rel="stylesheet" href="./pintura.css" />
</head>

<style>
    .pintura-editor {
        height: 600px;
    }
</style>

<div id="editor"></div>

<script type="module">
    import { appendDefaultEditor } from './pintura.js';

    const editor = appendDefaultEditor('#editor', {
        src: 'image.jpeg',

        // Set to 'rtl' for right to left text
        textDirection: 'ltr',
    });
</script>

fixScrollDirection

Defaults to false.

Set to true to fix scroll direction on MacOS. By default the scroll direction on MacOS is incorrectly inverted.

This will be addressed in the next major release.

animations

Toggle if and when the editor runs animations.

'auto'
Will enable animations if user hasn't specified prefers reduced motion in system settings.
'never'
Disables all animations.
'always'
Will set the editor to ignore user preferences and always run animations.

status

Set to a string to show a custom status message.

<!DOCTYPE html>

<head>
    <link rel="stylesheet" href="./pintura.css" />
</head>

<style>
    .pintura-editor {
        height: 600px;
    }
</style>

<div id="editor"></div>

<script type="module">
    import { appendDefaultEditor } from './pintura.js';

    const editor = appendDefaultEditor('#editor', { src: 'image.jpeg' });

    editor.on('load', () => {
        editor.status = 'Doing something...';
    });
</script>

Pass a number between 0 and 1 as second argument to show and update a progress indicator. Pass Infinity to show a spinning progress indicator.

<!DOCTYPE html>

<head>
    <link rel="stylesheet" href="./pintura.css" />
</head>

<style>
    .pintura-editor {
        height: 600px;
    }
</style>

<div id="editor"></div>

<script type="module">
    import { appendDefaultEditor } from './pintura.js';

    const editor = appendDefaultEditor('#editor', { src: 'image.jpeg' });

    editor.on('load', () => {
        editor.status = ['Busy bee', Infinity];
    });
</script>

Set second argument to false to switch to error state.

<!DOCTYPE html>

<head>
    <link rel="stylesheet" href="./pintura.css" />
</head>

<style>
    .pintura-editor {
        height: 600px;
    }
</style>

<div id="editor"></div>

<script type="module">
    import { appendDefaultEditor } from './pintura.js';

    const editor = appendDefaultEditor('#editor', { src: 'image.jpeg' });

    editor.on('load', () => {
        editor.status = ['Something went wrong', false];
    });
</script>

Pass function as third argument to handle click on error state close button.

<!DOCTYPE html>

<head>
    <link rel="stylesheet" href="./pintura.css" />
</head>

<style>
    .pintura-editor {
        height: 600px;
    }
</style>

<div id="editor"></div>

<script type="module">
    import { appendDefaultEditor } from './pintura.js';

    const editor = appendDefaultEditor('#editor', { src: 'image.jpeg' });

    editor.on('load', () => {
        editor.status = [
            'Something went wrong',
            false,
            () => {
                /* clicked close button */
            },
        ];
    });
</script>

previewUpscale

If set to true the preview image will be scaled to fit the editor stage.

If false the preview image will only be scaled down to fit the stage, if the preview image is smaller than the stage it will not be upscaled.

This only affects the preview of the image in the editor, this won't affect the size of the output image.

previewImageDataMaxSize

Set to an object with a width and height value. Pintura will scale down the preview image (respecting the image aspect ratio) to fit the defined size.

<!DOCTYPE html>

<head>
    <link rel="stylesheet" href="./pintura.css" />
</head>

<style>
    .pintura-editor {
        height: 600px;
    }
</style>

<div id="editor"></div>

<script type="module">
    import { appendDefaultEditor } from './pintura.js';

    const editor = appendDefaultEditor('#editor', {
        src: 'image.jpeg',
        previewImageDataMaxSize: { width: 1024, height: 1024 },
    });
</script>

willSetMediaInitialTimeOffset

A hook to set the intial time shown when loading a video.

Because video's can have a black first frame this currently defaults to the mid point of first clip.

To move the video current time to the first first we can use willSetMediaInitialTimeOffset

<!DOCTYPE html>

<head>
    <link rel="stylesheet" href="./pintura.css" />
</head>

<button type="button" id="buttonOpenEditor">Open editor</button>

<script type="module">
    import { openDefaultEditor } from './pintura.js';

    const buttonOpenEditor = document.querySelector('#buttonOpenEditor');

    buttonOpenEditor.addEventListener('click', () => {
        const editor = openDefaultEditor({
            src: 'image.jpeg',
            willSetMediaInitialTimeOffset: () => {
                // set to 0 seconds
                return 0;
            },
        });
    });
</script>

muteAudio

Toggles audio on video's on/off. By default Pintura mutes videos.

imageSourceToImageData

A helper method to correctly read custom preview image data.

The image formats that Pintura Image Editor can read and write depend on which images are supported by the clients browser. In general these image types are supported by all major browsers.

  • image/gif
  • image/png
  • image/jpeg
  • image/webp
  • image/bmp
  • image/svg

If we want to be able to read additional image formats (for example HEIC/HEIF) inside the editor we can supply our own image reader using the imageSourceToImageData property.

Please note that this function is used for all image resources inside the editor, if we only need to load additional image formats for editing it's better to set the preprocessImageFile hook of the imageReader property.

<!DOCTYPE html>

<head>
    <link rel="stylesheet" href="./pintura.css" />
</head>

<button type="button" id="buttonOpenEditor">Open editor</button>

<script type="module">
    import { openDefaultEditor } from './pintura.js';

    const buttonOpenEditor = document.querySelector('#buttonOpenEditor');

    buttonOpenEditor.addEventListener('click', () => {
        const editor = openDefaultEditor({
            src: 'image.jpeg',
            imageSourceToImageData: (src) => {
                return fetch(src)
                    .then((res) => res.blob())
                    .then(
                        (blob) =>
                            new Promise((resolve, reject) => {
                                // Turn blob into image data here

                                // resolve with ImageData object
                                resolve(imageData);
                            })
                    );
            },
        });
    });
</script>

enableTransparencyGrid

Set to true to render a grid behind the image to reveal transparent areas.

Use --grid-color-even, --grid-color-odd, and --grid-size on the .pintura-editor element to style the grid.

.pintura-editor {
    /* even cell color */
    --grid-color-even: rgba(0, 0, 0, 0.1);

    /* odd cell color */
    --grid-color-odd: rgba(1, 1, 1, 0.1);

    /* cell size */
    --grid-size: 32;
}

enableCanvasAlpha

Set to true to make editor background transparent.

This is an experimental feature, the API isn't final yet and might be changed in a future release.

enableToolbar

Defaults to true, set to false to disable the toolbar.

enableUtils

Defaults to true, set to false to disable the util tabs.

enableButtonClose

Defaults to false, set to true to show a close button, automatically set to true when using openModal.

enableButtonExport

Defaults to true, set to false to disable the export button.

enableButtonRevert

Defaults to true, set to false to disable the history revert button.

enableNavigateHistory

Defaults to true, set to false to disable the undo and redo buttons.

enableDropImage

Default to false, set to true to allow loading a new image by dropping it on the editor.

enablePasteImage

Default to false, set to true to allow pasting a new image. Editor will accept a pasted image if it's at least 75% in view.

enableBrowseImage

Default to false, set to true to allow clicking the editor to browse for an image when the editor is in "waiting for image" state.

enablePan

Set to false to disable panning the image in the markup editor.

enablePanInput

Set to true to force enable pan mode.

pan

Set to a position (for example { x: 100, y: 100 }) to pan to, set to null to reset.

enableZoom

Set to false to disable zooming the image in the markup editor.

enableZoomControls

Set to false to disable the zoom controls. true

zoomLevel

Set to a number to force a zoom level, set to undefined to fit to view, set to null to have editor handle zoom.

zoomPresetOptions

An array of zoom levels defined as fractions. Default value is [0.25, 0.5, 1, 1.25, 1.5, 2, 3, 4, 6, 8, 16].

zoomAdjustStep

The speed at which pressing the zoom buttons increases or decreases zoom. Defaults to .25

zoomAdjustFactor

The factor used to increase or decrease zoom speed when holding the zoom buttons. Default value is .1, increase speed is 1 + .1, decrease speed is 1 - .1.

zoomAdjustWheelFactor

The factor used to convert scroll wheel interactions to zoom steps, higher is faster, defaults to 1.

zoomMaskOpacity

The maximum opacity of the overlay rendered behind UI controls when zooming in, value between 0 and 1, defaults to .85.

handleEvent

Set to a function to route events. The handleEvent callback runs for each public event the editor dispatches, it receives the event type and detail.

<!DOCTYPE html>

<head>
    <link rel="stylesheet" href="./pintura.css" />
</head>

<style>
    .pintura-editor {
        height: 600px;
    }
</style>

<div id="editor"></div>

<script type="module">
    import { appendDefaultEditor } from './pintura.js';

    const editor = appendDefaultEditor('#editor', {
        src: 'image.jpeg',
        handleEvent: (type, detail) => {
            // Log all editor events to console
            console.log(type, detail);
        },
    });
</script>

willClose

Set to an async method.

Resolve with false to prevent closing the modal, resolve with true to continue closing the modal.

<!DOCTYPE html>

<head>
    <link rel="stylesheet" href="./pintura.css" />
</head>

<button type="button" id="buttonOpenEditor">Open editor</button>

<script type="module">
    import { openDefaultEditor } from './pintura.js';

    const buttonOpenEditor = document.querySelector('#buttonOpenEditor');

    buttonOpenEditor.addEventListener('click', () => {
        const editor = openDefaultEditor({
            src: 'image.jpeg',
            willClose: async () => {
                // return false to prevent closing modal
                return false;
            },
        });
    });
</script>

willRevert

Set to an async method.

Resolve with false to prevent the revert of all user actions, resolve with true to revert the editor to the initial state.

<!DOCTYPE html>

<head>
    <link rel="stylesheet" href="./pintura.css" />
</head>

<style>
    .pintura-editor {
        height: 600px;
    }
</style>

<div id="editor"></div>

<script type="module">
    import { appendDefaultEditor } from './pintura.js';

    const editor = appendDefaultEditor('#editor', {
        src: 'image.jpeg',
        willRevert: async () => {
            // return false to prevent revert action
            return false;
        },
    });
</script>

willProcessImage

Set to an async method.

Resolve with false to prevent the image processing action, resolve with true to continue processing the image.

<!DOCTYPE html>

<head>
    <link rel="stylesheet" href="./pintura.css" />
</head>

<style>
    .pintura-editor {
        height: 600px;
    }
</style>

<div id="editor"></div>

<script type="module">
    import { appendDefaultEditor } from './pintura.js';

    const editor = appendDefaultEditor('#editor', {
        src: 'image.jpeg',
        willProcessImage: async () => {
            // return false to prevent image processing action
            return false;
        },
    });
</script>

Optionally use the status property to update the editor status text.

<!DOCTYPE html>

<head>
    <link rel="stylesheet" href="./pintura.css" />
</head>

<style>
    .pintura-editor {
        height: 600px;
    }
</style>

<div id="editor"></div>

<script type="module">
    import { appendDefaultEditor } from './pintura.js';

    const editor = appendDefaultEditor('#editor', {
        src: 'image.jpeg',
        willProcessImage: async () => {
            // show a status message
            editor.status = 'waiting for user input';

            // wait for a second before showing dialog
            await new Promise((r) => setTimeout(r, 1000));

            // show some sort of dialog to request user input
            const shouldProcess = confirm('Should we process the image?');

            // hide the status after we got user input
            editor.status = undefined;

            // ready to process?
            return shouldProcess;
        },
    });
</script>

willRequest

Use to alter request objects or prevent requests. Requests include images like the main images and images used to render shapes, additionally the editor loads stylesheets to determine font resources.

Please note this hook is only used for resources like stylesheets, stickers, and shape background images.

To pass custom headers to the request that loads the main image you can use the request property on the imageReader.

Receives request url and request info object.

<!DOCTYPE html>

<head>
    <link rel="stylesheet" href="./pintura.css" />
</head>

<style>
    .pintura-editor {
        height: 600px;
    }
</style>

<div id="editor"></div>

<script type="module">
    import { appendDefaultEditor } from './pintura.js';

    const editor = appendDefaultEditor('#editor', {
        src: 'image.jpeg',
        willRequest: (url, info) => {
            const { resourceType } = info;

            // add custom request header to image requests
            if (resourceType === 'image') {
                return {
                    headers: {
                        myRequestHeader: 'Hello World',
                    },
                };
            }

            // only load stylesheets if is absolute URL to pqina.nl
            if (resourceType === 'stylesheet' && !url.includes('pqina.nl')) {
                return false;
            }

            // don't alter other requests
        },
    });
</script>

willRequestResource

Deprecated, use willRequest instead.

Use to prevent loading remote resources. Receives remote stylesheet URL, return false to prevent loading the resource.

willRenderCanvas

We can use the willRenderCanvas hook to alter what Pintura Image Editor renders to the screen.

The willRenderCanvas hook receives two parameters, the shapes that are about to be drawn, and the current state.

Example draw state object.

{
    // is user currently interacting
    isInteracting: false,

    // will animate from 0 to 1 when interacting
    isInteractingFraction: 0,

    // opacity of the image from 0 to 1
    opacity: 1,

    // rotation of image
    rotation: {
        x: 0,
        y: 0,
        z: 0,
    },

    // scale of image
    scale: 0.615625,

    // size of canvas
    size: {
        width: 1040,
        height: 510,
    },

    // foreground color of canvas
    foregroundColor: [0, 0, 0],

    // background color of canvas
    backgroundColor: [1, 1, 1],

    // line color used in canvas
    lineColor: [0, 0, 0],

    // rectangle of editor root
    rootRect: {
        x: 0,
        y: 0,
        width: 1040,
        height: 510,
    },

    // rectangle of crop selection
    selectionRect: {
        x: 322,
        y: 60,
        height: 394,
        width: 522,
    },

    // rectangle of util
    stageRect: {
        x: 144,
        y: 60,
        width: 880,
        height: 394,
    },

    // opacity of each util, from 0 to 1
    utilVisibility: {
        annotate: 0,
        crop: 1,
        decorate: 0,
        filter: 0,
        finetune: 0,
        resize: 0,
        sticker: 0,
    },
};

Example shapes object.

{
    // these are drawn relative to the preview image
    annotationShapes: [
        {
            backgroundColor: [0, 1, 1],
            cornerRadius: 0,
            disableErase: true,
            height: 200,
            id: 'dgyf5b4cu',
            opacity: 1,
            rotation: 0,
            strokeColor: [0, 0, 0],
            strokeWidth: 0,
            width: 200,
            x: 20,
            y: 20,
        },
    ],

    // these are drawn relative to the crop selection
    decorationShapes: [],

    // these are drawn on top of the user interface
    interfaceShapes: [
        {
            id: 'image-selection-guide-row-0',
            opacity: 1,
            points: [
                { x: 322.475, y: 60 },
                { x: 844.525, y: 60 },
            ],
            strokeColor: [0, 0, 0],
            strokeWidth: 1,
        },
        // ...and some more shapes
    ],
};

In the snippet below we draw a circular overlay on top of the crop selection, see crop overlay example for a live preview.

<!DOCTYPE html>

<head>
    <link rel="stylesheet" href="./pintura.css" />
</head>

<style>
    .pintura-editor {
        height: 600px;
    }
</style>

<div id="editor"></div>

<script type="module">
    import { appendDefaultEditor } from './pintura.js';

    const editor = appendDefaultEditor('#editor', {
        src: 'image.jpeg',
        willRenderCanvas: (shapes, state) => {
            const {
                utilVisibility,
                selectionRect,
                backgroundColor,
                lineColor,
            } = state;

            // exit if crop utils is not visible
            if (utilVisibility.crop <= 0) return shapes;

            // shortcuts to selection rect
            const { x, y, width, height } = selectionRect;

            // return updated shapes
            return {
                // copy props from shapes param
                ...shapes,

                // add an 'ellipse' shape
                interfaceShapes: [
                    {
                        x: x + width * 0.5,
                        y: y + height * 0.5,
                        rx: width * 0.5,
                        ry: height * 0.5,
                        opacity: utilVisibility.crop,
                        inverted: true,
                        backgroundColor: [...backgroundColor, 0.5],
                        strokeWidth: 1,
                        strokeColor: [...lineColor],
                    },
                    ...shapes.interfaceShapes,
                ],
            };
        },
    });
</script>

willRenderToolbar

The willRenderToolbar hook receives the current toolbar definition and editor environment parameters. The hook allows injecting custom controls into the toolbar using the createNode helper function.

The willRenderToolbar hook should always return an array. If the returned array is empty the toolbar is hidden.

<!DOCTYPE html>

<head>
    <link rel="stylesheet" href="./pintura.css" />
</head>

<style>
    .pintura-editor {
        height: 600px;
    }
</style>

<div id="editor"></div>

<script type="module">
    import { appendDefaultEditor, createNode } from './pintura.js';

    const editor = appendDefaultEditor('#editor', {
        src: 'image.jpeg',
        willRenderToolbar: (toolbar, env, redraw) => {
            console.log(toolbar);
            // logs: [ Array(4), Array(4), Array(4) ]

            console.log(env);
            // logs: { orientation: "landscape", verticalSpace: "short", … }

            // call redraw to trigger a redraw of the editor state

            // insert your item
            return [
                createNode('div', 'my-div', { textContent: 'Hello world' }),
                ...toolbar,
            ];
        },
    });
</script>

willRenderUtilTabs

Use to customize the util tabs. Allows ordering, removing, or updating the received array of tab objects.

Return either the tab objects or a PinturaNode array to render instead of the default tabs.

<!DOCTYPE html>

<head>
    <link rel="stylesheet" href="./pintura.css" />
</head>

<style>
    .my-tab-group button span {
        font-size: 1em;
        visibility: visible !important;
    }
</style>

<div id="editor"></div>

<script type="module">
    import { appendDefaultEditor } from './pintura.js';

    const editor = appendDefaultEditor('#editor', {
        src: 'image.jpeg',
        willRenderUtilTabs: (tabs, env, redraw) => {
            console.log(tabs);
            // logs: [ { id: 'crop', … }, … ]

            console.log(env);
            // logs: { orientation: "landscape", … }

            // call redraw to trigger a redraw of the editor state

            // returns custom node menu
            return [
                [
                    // node to use for tab group
                    'div',

                    // unique id for the group node
                    'tab-group',

                    // so tab direction switches with view orientation change
                    {
                        class: 'my-tab-group',
                        style:
                            'display:flex; flex-direction:' +
                            (env.orientation === 'landscape'
                                ? 'column'
                                : 'row'),
                    },

                    // map tabs to child nodes
                    tabs.map((tab) => [
                        'Button',
                        tab.id,
                        {
                            // add * if is selected tab
                            label: tab.label + (tab.selected ? ' *' : ''),

                            // handle clicks on this button
                            onclick: () => {
                                // change active tab on click
                                editor.util = tab.id;
                            },
                        },
                    ]),
                ],
            ];
        },
    });
</script>