Why does Doka throw a CORS error when processing the image?

The most likely cause of these issues is an incorrectly configured CORS policy on a remote server. A resource is deemed remote when it has a different domain, subdomain, protocol, or port as the local server.

Some examples of cross-origin requests:

https://my-site.com -> https://your-site.com
https://my-site.com -> https://sub.my-site.com
https://my-site.com -> http://my-site.com
https://my-site.com -> http://my-site.com:1234

We can determine if the CORS policy is configured incorrectly by looking at the network tab of our browser developer tools and inspecting the request. If the Access-Control response headers are turned CORS is configured.

Below we can see the request information when loading a test image from the PQINA webserver:

Request Headers
  Url: https://pqina.nl/doka/test/cors/test.jpeg
  Method: GET

Response Headers
  Access-Control-Allow-Methods: GET
  Access-Control-Allow-Origin: *
  Content-Type: image/jpeg

A wildcard means that the file can be accessed from everywhere, it's best to set a specific origin.

Access-Control-Allow-Origin: https://my-site.com

If a specific origin is set (so no wildcard), we need to make sure the image is correctly cached as well. To do this we need to set the Vary header to Origin, see CORS and caching on MDN.

If for some reason the remote CORS policy can't be changed we can proxy the image request through the local server. In that situation we send the URL of the remote image to our local server, our local server then requests the remote image and returns the result to the front-end.

Additional information on setting a CORS policy:

HTML Canvas and CORS

About Canvas and CORS on MDN

Google Cloud and CORS

Google Cloud CORS

Amazon AWS S3 and CORS

An S3 bucket doesn't automatically send the Vary: Origin header, the Origin header needs to be present in the request for S3 to add it to Vary.

Azure and CORS

Azure CORS

How to apply a circular crop mask to an image?

To apply a circular crop mask we can use the postprocessImageData hook available on the createDefaultImageWriter export. This hook allows us to modify the output image data before it is turned into a file.

To show a circular overlay on top of the crop controls we can use the willRenderCanvas hook available on every editor instance. This hook allows us to precisely control what the editor renders to the screen. We can make adjustments using the Shape API.

How to upload the output image?

We can upload output images by integrating with existing file upload solutions like FilePond, Dropzone, Uppy, or jQuery File Upload.

Alternatively we can use the store property of the createDefaultImageWriter export. If we set a path to the store property the editor will POST the file data to the supplied location. If we instead supply the property with a function we have fine grained control over where and how to upload the output image.

Can I use Doka Image Editor version 6 data with version 7?

We can convert Doka Image Editor version 6 data with the legacyDataToImageState method.

import { legacyDataToImageState } from './doka.js';

const app = openEditor({
    /* editor settings */

app.on('load', ({ size }) => {
    app.imageState = legacyDataToImageState(app, size, {
        /* Doka Image Editor version 6 data here */

Can labels be changed to a different language?

Currently Doka Image Editor includes en_gb locale files. But we set our own labels by updating label properties in these locale objects.

import {
} from './doka.js';

const locale = {

locale.labelButtonExport = 'Save';

// set locale to Doka
const doka = appendEditor('.my-editor', { locale });

Does Doka Image Editor automatically correct image orientation?

Doka Image Editor will automatically correct the orientation of images when the outputCorrectImageExifOrientation is set to true (this is the default).

On export Doka will strip the EXIF header, to keep the header, please set outputStripImageHead to false

Can Doka Image Editor limit the size of the output image?

You can set the maximum size of the output image using the targetSize property on the createDefaultImageWriter method. This will limit the size of the output image to the targetSize width and height properties.

To upscale the image to fit the defined output size, set upscale to true.

    imageWriter: createDefaultImageWriter({
        targetSize: {
            width: 512,
            height: 512,
            upscale: true,

By default Doka Image Editor will 'contain' the image to the supplied width and height. If the image is in a different aspect ratio it will be scaled down (or up) to fit inside the defined size.

To force the image to the defined size, and ignore the image aspect ratio, set the fit property to 'force'.

To cover the target size with the image, set the fit property to 'cover'.

    imageWriter: createDefaultImageWriter({
        targetSize: {
            width: 512,
            height: 512,
            fit: 'cover',

How can I automatically crop the image subject

By combining Doka Image Editor with Smartcrop.js we can automatically move the crop rectangle to the most prominent subject in the image.

// create an editor
const editor = openEditor({
    src: './my-image.jpeg',

// listen for image load evevnt
editor.on('load', ({ dest }) => {
    // create a normal image and send it to smartcrop.js
    const image = new Image();
    image.src = URL.createObjectURL(dest);
    image.onload = async () => {
        // calculate the smart crop rectangle, set aspect ratio to 3:4
        const { topCrop } = await smartcrop.crop(image, {
            width: 3,
            height: 4,

        // update the editor crop
        editor.imageCrop = topCrop;

How can I generate a square thumbnail based on the output image?

We can use the processImage function to programmatically create images.

See the example below where we wait for the 'process' event to fire and the use processImage to generate a thumbnail.

import {
} from '/doka.js';

const editor = openEditor({
    src: './my-image.jpeg',
    imageReader: createDefaultImageReader(),
    imageWriter: createDefaultImageWriter(),

editor.on('process', ({ dest }) => {
    // use the output image as the source
    processImage(dest, {
        // we want a square crop
        imageCropAspectRatio: 1,

        // set the default reader
        imageReader: createDefaultImageReader(),

        // set the default writer and supply the intended size of the thumbnail
        imageWriter: createDefaultImageWriter({
            targetSize: {
                width: 256,
                height: 256,
    }).then(({ dest }) => {
        // `dest` is our thumbnail as a File object