# Image Editor Exported Methods And Properties

The functions, properties, and defaults related to image editing that are exported by the Pintura module.

| Export                                                                                 | Description                                                                                                                                        |
| -------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| [createDefaultImageOrienter()](#createdefaultimageorienter)                            | Creates a helper object to correctly orient images.                                                                                                |
| [createDefaultImageReader(options)](#createdefaultimagereader)                         | Creates the default image reader. This is the array of processes the editor uses to read image data.                                               |
| [createDefaultImageWriter(options)](#createdefaultimagewriter)                         | Creates the default image writer. This is the array of processes the editor uses to write image data.                                              |
| [createDefaultMediaWriter(options)](#createdefaultmediawriter)                         | Creates a default media writer. This method groups image and video writers.                                                                        |
| [createDefaultImageScrambler(options)](#createdefaultimagescrambler)                   | Creates the default image scrambler. This is a function that receives an ImageBitmap or ImageData object and returns a canvas with scrambled data. |
| [createDefaultShapePreprocessor()](#createdefaultshapepreprocessor)                    | Creates the default shape preprocessor used for parsing lineEnd styles and frame styles.                                                           |
| [createShapePreprocessor(processors\[\])](#createshapepreprocessor)                    | Accepts a shape processor configuration and returns a function that can be assigned to the editor shapePreprocessor property.                      |
| [createDefaultFrameStyles()](#createdefaultframestyles)                                | Generates the default frame style object.                                                                                                          |
| [createDefaultLineEndStyles()](#createdefaultlineendstyles)                            | Generates the default line style object.                                                                                                           |
| [createFrameStyleProcessor(styles)](#createframestyleprocessor)                        | Merge custom frame styles with the default frame styles.                                                                                           |
| [createLineEndProcessor(styles)](#createlineendprocessor)                              | Merge custom line end styles with the default line end styles.                                                                                     |
| [processImage(file, options)](#processimage)                                           | processes the file with supplied properties.                                                                                                       |
| [processDefaultImage(file, options)](#processdefaultimage)                             | Same as processImage but sets default image reader, image writer and image orienter.                                                               |
| [imageStateToCanvas(src, imageState, options)](#imagestatetocanvas)                    | A helper function to draw the current imageState to a target canvas.                                                                               |
| [legacyDataToImageState(editorRef, imageSize, legacyDataObj)](#legacydatatoimagestate) | Converts a Pintura Image Editor legacy data object to an [imageState](../properties/#imagestate) object.                                           |
| [selectionToMask(selection, imageSize, imageState, options)](#selectiontomask)         | Converts a selection array to a mask blob or canvas.                                                                                               |

### createDefaultImageOrienter

The `createDefaultImageOrienter` function returns a default image orientation helper object containing a `read` and an `apply` method to read EXIF orientation information and to write EXIF orientation information.

```js
const imageOrienter = createDefaultImageOrienter();

console.log(imageOrienter);
// logs: { read: function, apply: function }
```

The returned object should be assigned to the [imageOrienter](../properties/#imageorienter) property on your editor instance.

### createDefaultImageReader

The `createDefaultImageReader` function returns the default image reader steps. This is an array of processes the editor runs to read image data.

It can read resources of type `File`, `Blob`, `Data URL`, `URL`, `HTMLCanvasElement`, and `HTMLImageElement`. It will also automatically correct mobile photo orientation when needed.

The default image reader can read [images that are supported by the clients browser](https://en.wikipedia.org/wiki/Comparison%5Fof%5Fweb%5Fbrowsers#Image%5Fformat%5Fsupport). In general these image formats are supported by all major browsers.

* `image/gif`
* `image/png`
* `image/jpeg`
* `image/webp`
* `image/bmp`
* `image/svg`

If needed we can use the `preprocessImageFile` hook to [read additional image formats](#preprocessimagefile) (for example HEIC).

The returned image reader object should be assigned to the editor [imageReader](../properties/#imagereader) property.

| Export                                      | Default value             | Description                                                                                                  |
| ------------------------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------ |
| orientImage                                 | true                      | Auto corrects the orientation of mobile photos.                                                              |
| outputProps                                 | \['src', 'dest', 'size'\] | Which properties to retain on the output data object.                                                        |
| [request](#request)                         | {}                        | Add custom headers to the XMLHttpRequest and set the credentials property.                                   |
| [preprocessImageFile](#preprocessimagefile) | async (file) \=> (file)   | Allows preprocessing the image file, for example to turn a HEIC image into a browser supported image format. |

* [ ![](/pintura/static/assets/technologies-mono/javascript.svg)JavaScript](#javascript-panel-5)
* [ ![](/pintura/static/assets/technologies-mono/react.svg)React](#react-panel-5)
* [ ![](/pintura/static/assets/technologies-mono/vue.svg)Vue](#vue-panel-5)
* [ ![](/pintura/static/assets/technologies-mono/svelte.svg)Svelte](#svelte-panel-5)
* [ ![](/pintura/static/assets/technologies-mono/angular.svg)Angular](#angular-panel-5)
* [ ![](/pintura/static/assets/technologies-mono/jquery.svg)jQuery](#jquery-panel-5)

* [index.html](#index-html-panel-5)

`<!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,
        createDefaultImageReader,
    } from './pintura.js';

    const editor = appendDefaultEditor('#editor', {
        src: 'image.jpeg',
        imageReader: createDefaultImageReader({
            // Fix image orientation
            orientImage: true,

            // Disable output prop filter
            outputProps: [],

            // Set request properties
            request: {
                credentials: 'same-origin',
                headers: {
                    'X-My-Header': 'Hello World',
                },
            },
        }),
    });
</script>
`

* [App.jsx](#App-jsx-panel-5)
* [App.css](#App-css-panel-5)

`import '@pqina/pintura/pintura.css';
import './App.css';
import { PinturaEditor } from '@pqina/react-pintura';
import { getEditorDefaults, createDefaultImageReader } from '@pqina/pintura';

const editorDefaults = getEditorDefaults({
    imageReader: createDefaultImageReader({
        // Fix image orientation
        orientImage: true,

        // Disable output prop filter
        outputProps: [],

        // Set request properties
        request: {
            credentials: 'same-origin',
            headers: {
                'X-My-Header': 'Hello World',
            },
        },
    }),
});

function App() {
    return (
        <div className="App">
            <PinturaEditor {...editorDefaults} src={'image.jpeg'} />
        </div>
    );
}

export default App;
`

```css
.pintura-editor {
    height: 600px;
}

```

* [App.vue](#App-vue-panel-5)

`<template>
    <div>
        <PinturaEditor v-bind="editorDefaults" src="image.jpeg" />
    </div>
</template>
<script>
import { PinturaEditor } from '@pqina/vue-pintura';
import { getEditorDefaults, createDefaultImageReader } from '@pqina/pintura';

export default {
    name: 'App',

    components: {
        PinturaEditor,
    },

    data() {
        return {
            editorDefaults: getEditorDefaults({
                imageReader: createDefaultImageReader({
                    // Fix image orientation
                    orientImage: true,

                    // Disable output prop filter
                    outputProps: [],

                    // Set request properties
                    request: {
                        credentials: 'same-origin',
                        headers: {
                            'X-My-Header': 'Hello World',
                        },
                    },
                }),
            }),
        };
    },

    methods: {},
};
</script>
<style>
@import '@pqina/pintura/pintura.css';

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

* [App.svelte](#App-svelte-panel-5)

`<script>
    import { PinturaEditor } from '@pqina/svelte-pintura';
    import {
        getEditorDefaults,
        createDefaultImageReader,
    } from '@pqina/pintura';
    import '@pqina/pintura/pintura.css';

    let editorDefaults = getEditorDefaults({
        imageReader: createDefaultImageReader({
            // Fix image orientation
            orientImage: true,

            // Disable output prop filter
            outputProps: [],

            // Set request properties
            request: {
                credentials: 'same-origin',
                headers: {
                    'X-My-Header': 'Hello World',
                },
            },
        }),
    });
</script>

<div>
    <PinturaEditor {...editorDefaults} src={'image.jpeg'} />
</div>

<style>
    div :global(.pintura-editor) {
        height: 600px;
    }
</style>
`

* [app.component.ts](#app-component-ts-panel-5)
* [app.component.html](#app-component-html-panel-5)
* [app.component.css](#app-component-css-panel-5)
* [app.module.ts](#app-module-ts-panel-5)

`import { Component } from '@angular/core';

import { getEditorDefaults, createDefaultImageReader } from '@pqina/pintura';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
})
export class AppComponent {
    editorDefaults: any = getEditorDefaults({
        imageReader: createDefaultImageReader({
            // Fix image orientation
            orientImage: true,

            // Disable output prop filter
            outputProps: [],

            // Set request properties
            request: {
                credentials: 'same-origin',
                headers: {
                    'X-My-Header': 'Hello World',
                },
            },
        }),
    });
}
`

```html
<pintura-editor [options]="editorDefaults" src="image.jpeg"></pintura-editor>

```

```css
::ng-deep .pintura-editor {
    height: 600px;
}

```

```javascript
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AngularPinturaModule } from '@pqina/angular-pintura';

@NgModule({
    declarations: [AppComponent],
    imports: [BrowserModule, AngularPinturaModule],
    exports: [AppComponent],
    providers: [],
    bootstrap: [AppComponent],
})
export class AppModule {}

```

* [index.html](#index-html-panel-5)

`<!DOCTYPE html>
<head>
    <link rel="stylesheet" href="./pintura/pintura.css" />
</head>

<script src="./jquery.js"></script>
<script src="./jquery-pintura/useEditorWithJQuery-iife.js"></script>
<script src="./pintura/pintura-iife.js"></script>

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

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

<script>
    useEditorWithJQuery(jQuery, pintura);

    $(function () {
        var { createDefaultImageReader } = $.fn.pintura;

        var editor = $('#editor').pinturaDefault({
            src: 'image.jpeg',
            imageReader: createDefaultImageReader({
                // Fix image orientation
                orientImage: true,

                // Disable output prop filter
                outputProps: [],

                // Set request properties
                request: {
                    credentials: 'same-origin',
                    headers: {
                        'X-My-Header': 'Hello World',
                    },
                },
            }),
        });
    });
</script>
`

The `createDefaultImageReader` result object is passed along with the ['load'](../events/#load) event, see an example of this object below.

```js
{
    // the resulting file
    dest: {
        name: 'image.jpeg',
        lastModified: 1605802185485,
        size: 128000,
        type: 'image/jpeg',
    },
    // the image size
    size: {
        width: 1280,
        height: 1024,
    },
    // the original source
    src: 'image.jpeg',
}
```

#### request

Set custom request `headers` and control the `credentials` property.

Please note this hook is only used for loading the main image.

To pass custom headers to the requests that load stylesheets, and shape background images, you can use the [willRequest](../../ui/properties/#willrequest) hook.

* [ ![](/pintura/static/assets/technologies-mono/javascript.svg)JavaScript](#javascript-panel-7)
* [ ![](/pintura/static/assets/technologies-mono/react.svg)React](#react-panel-7)
* [ ![](/pintura/static/assets/technologies-mono/vue.svg)Vue](#vue-panel-7)
* [ ![](/pintura/static/assets/technologies-mono/svelte.svg)Svelte](#svelte-panel-7)
* [ ![](/pintura/static/assets/technologies-mono/angular.svg)Angular](#angular-panel-7)
* [ ![](/pintura/static/assets/technologies-mono/jquery.svg)jQuery](#jquery-panel-7)

* [index.html](#index-html-panel-7)

`<!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,
        createDefaultImageReader,
    } from './pintura.js';

    const editor = appendDefaultEditor('#editor', {
        src: 'image.jpeg',
        imageReader: createDefaultImageReader({
            request: {
                credentials: 'same-origin',
                headers: {
                    'X-My-Header': 'Hello World',
                },
            },
        }),
    });
</script>
`

* [App.jsx](#App-jsx-panel-7)
* [App.css](#App-css-panel-7)

`import '@pqina/pintura/pintura.css';
import './App.css';
import { PinturaEditor } from '@pqina/react-pintura';
import { getEditorDefaults, createDefaultImageReader } from '@pqina/pintura';

const editorDefaults = getEditorDefaults({
    imageReader: createDefaultImageReader({
        request: {
            credentials: 'same-origin',
            headers: {
                'X-My-Header': 'Hello World',
            },
        },
    }),
});

function App() {
    return (
        <div className="App">
            <PinturaEditor {...editorDefaults} src={'image.jpeg'} />
        </div>
    );
}

export default App;
`

```css
.pintura-editor {
    height: 600px;
}

```

* [App.vue](#App-vue-panel-7)

`<template>
    <div>
        <PinturaEditor v-bind="editorDefaults" src="image.jpeg" />
    </div>
</template>
<script>
import { PinturaEditor } from '@pqina/vue-pintura';
import { getEditorDefaults, createDefaultImageReader } from '@pqina/pintura';

export default {
    name: 'App',

    components: {
        PinturaEditor,
    },

    data() {
        return {
            editorDefaults: getEditorDefaults({
                imageReader: createDefaultImageReader({
                    request: {
                        credentials: 'same-origin',
                        headers: {
                            'X-My-Header': 'Hello World',
                        },
                    },
                }),
            }),
        };
    },

    methods: {},
};
</script>
<style>
@import '@pqina/pintura/pintura.css';

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

* [App.svelte](#App-svelte-panel-7)

`<script>
    import { PinturaEditor } from '@pqina/svelte-pintura';
    import {
        getEditorDefaults,
        createDefaultImageReader,
    } from '@pqina/pintura';
    import '@pqina/pintura/pintura.css';

    let editorDefaults = getEditorDefaults({
        imageReader: createDefaultImageReader({
            request: {
                credentials: 'same-origin',
                headers: {
                    'X-My-Header': 'Hello World',
                },
            },
        }),
    });
</script>

<div>
    <PinturaEditor {...editorDefaults} src={'image.jpeg'} />
</div>

<style>
    div :global(.pintura-editor) {
        height: 600px;
    }
</style>
`

* [app.component.ts](#app-component-ts-panel-7)
* [app.component.html](#app-component-html-panel-7)
* [app.component.css](#app-component-css-panel-7)
* [app.module.ts](#app-module-ts-panel-7)

`import { Component } from '@angular/core';

import { getEditorDefaults, createDefaultImageReader } from '@pqina/pintura';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
})
export class AppComponent {
    editorDefaults: any = getEditorDefaults({
        imageReader: createDefaultImageReader({
            request: {
                credentials: 'same-origin',
                headers: {
                    'X-My-Header': 'Hello World',
                },
            },
        }),
    });
}
`

```html
<pintura-editor [options]="editorDefaults" src="image.jpeg"></pintura-editor>

```

```css
::ng-deep .pintura-editor {
    height: 600px;
}

```

```javascript
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AngularPinturaModule } from '@pqina/angular-pintura';

@NgModule({
    declarations: [AppComponent],
    imports: [BrowserModule, AngularPinturaModule],
    exports: [AppComponent],
    providers: [],
    bootstrap: [AppComponent],
})
export class AppModule {}

```

* [index.html](#index-html-panel-7)

`<!DOCTYPE html>
<head>
    <link rel="stylesheet" href="./pintura/pintura.css" />
</head>

<script src="./jquery.js"></script>
<script src="./jquery-pintura/useEditorWithJQuery-iife.js"></script>
<script src="./pintura/pintura-iife.js"></script>

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

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

<script>
    useEditorWithJQuery(jQuery, pintura);

    $(function () {
        var { createDefaultImageReader } = $.fn.pintura;

        var editor = $('#editor').pinturaDefault({
            src: 'image.jpeg',
            imageReader: createDefaultImageReader({
                request: {
                    credentials: 'same-origin',
                    headers: {
                        'X-My-Header': 'Hello World',
                    },
                },
            }),
        });
    });
</script>
`

#### preprocessImageFile

The example below shows how to load HEIC/HEIF images using [Heic2any](https://github.com/alexcorvi/heic2any) in the `preprocessImageFile` hook.

* [ ![](/pintura/static/assets/technologies-mono/javascript.svg)JavaScript](#javascript-panel-8)
* [ ![](/pintura/static/assets/technologies-mono/react.svg)React](#react-panel-8)
* [ ![](/pintura/static/assets/technologies-mono/vue.svg)Vue](#vue-panel-8)
* [ ![](/pintura/static/assets/technologies-mono/svelte.svg)Svelte](#svelte-panel-8)
* [ ![](/pintura/static/assets/technologies-mono/angular.svg)Angular](#angular-panel-8)
* [ ![](/pintura/static/assets/technologies-mono/jquery.svg)jQuery](#jquery-panel-8)

* [index.html](#index-html-panel-8)

`<!DOCTYPE html>

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

<script src="./heic2any.js"></script>

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

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

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

    const editor = appendDefaultEditor('#editor', {
        src: 'image.jpeg',
        imageReader: createDefaultImageReader({
            preprocessImageFile: async (file, options, onprogress) => {
                // If is not of type HEIC we skip the file
                if (!/heic/.test(file.type)) return file;

                // Let's turn the HEIC image into JPEG so the browser can read it
                const blob = await heic2any({
                    blob: file,
                    toType: 'image/jpeg',
                    quality: 0.94,
                });

                // The editor expects a File so let's convert our Blob
                return blobToFile(blob, file.name);
            },
        }),
    });
</script>
`

* [App.jsx](#App-jsx-panel-8)
* [App.css](#App-css-panel-8)

`import '@pqina/pintura/pintura.css';
import './App.css';
import { PinturaEditor } from '@pqina/react-pintura';
import {
    processImage,
    getEditorDefaults,
    createDefaultImageReader,
    blobToFile,
} from '@pqina/pintura';

import heic2any from 'heic2any';

const editorDefaults = getEditorDefaults({
    imageReader: createDefaultImageReader({
        preprocessImageFile: async (file, options, onprogress) => {
            // If is not of type HEIC we skip the file
            if (!/heic/.test(file.type)) return file;

            // Let's turn the HEIC image into JPEG so the browser can read it
            const blob = await heic2any({
                blob: file,
                toType: 'image/jpeg',
                quality: 0.94,
            });

            // The editor expects a File so let's convert our Blob
            return blobToFile(blob, file.name);
        },
    }),
});

function App() {
    return (
        <div className="App">
            <PinturaEditor {...editorDefaults} src={'image.jpeg'} />
        </div>
    );
}

export default App;
`

```css
.pintura-editor {
    height: 600px;
}

```

* [App.vue](#App-vue-panel-8)

`<template>
    <div>
        <PinturaEditor v-bind="editorDefaults" src="image.jpeg" />
    </div>
</template>
<script>
import { PinturaEditor } from '@pqina/vue-pintura';
import {
    processImage,
    getEditorDefaults,
    createDefaultImageReader,
    blobToFile,
} from '@pqina/pintura';

import heic2any from 'heic2any';

export default {
    name: 'App',

    components: {
        PinturaEditor,
    },

    data() {
        return {
            editorDefaults: getEditorDefaults({
                imageReader: createDefaultImageReader({
                    preprocessImageFile: async (file, options, onprogress) => {
                        // If is not of type HEIC we skip the file
                        if (!/heic/.test(file.type)) return file;

                        // Let's turn the HEIC image into JPEG so the browser can read it
                        const blob = await heic2any({
                            blob: file,
                            toType: 'image/jpeg',
                            quality: 0.94,
                        });

                        // The editor expects a File so let's convert our Blob
                        return blobToFile(blob, file.name);
                    },
                }),
            }),
        };
    },

    methods: {},
};
</script>
<style>
@import '@pqina/pintura/pintura.css';

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

* [App.svelte](#App-svelte-panel-8)

`<script>
    import { PinturaEditor } from '@pqina/svelte-pintura';
    import {
        processImage,
        getEditorDefaults,
        createDefaultImageReader,
        blobToFile,
    } from '@pqina/pintura';
    import '@pqina/pintura/pintura.css';

    import heic2any from 'heic2any';

    let editorDefaults = getEditorDefaults({
        imageReader: createDefaultImageReader({
            preprocessImageFile: async (file, options, onprogress) => {
                // If is not of type HEIC we skip the file
                if (!/heic/.test(file.type)) return file;

                // Let's turn the HEIC image into JPEG so the browser can read it
                const blob = await heic2any({
                    blob: file,
                    toType: 'image/jpeg',
                    quality: 0.94,
                });

                // The editor expects a File so let's convert our Blob
                return blobToFile(blob, file.name);
            },
        }),
    });
</script>

<div>
    <PinturaEditor {...editorDefaults} src={'image.jpeg'} />
</div>

<style>
    div :global(.pintura-editor) {
        height: 600px;
    }
</style>
`

* [app.component.ts](#app-component-ts-panel-8)
* [app.component.html](#app-component-html-panel-8)
* [app.component.css](#app-component-css-panel-8)
* [app.module.ts](#app-module-ts-panel-8)

`import { Component } from '@angular/core';

import {
    processImage,
    getEditorDefaults,
    createDefaultImageReader,
    blobToFile,
} from '@pqina/pintura';

import heic2any from 'heic2any';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
})
export class AppComponent {
    editorDefaults: any = getEditorDefaults({
        imageReader: createDefaultImageReader({
            preprocessImageFile: async (file, options, onprogress) => {
                // If is not of type HEIC we skip the file
                if (!/heic/.test(file.type)) return file;

                // Let's turn the HEIC image into JPEG so the browser can read it
                const blob = await heic2any({
                    blob: file,
                    toType: 'image/jpeg',
                    quality: 0.94,
                });

                // The editor expects a File so let's convert our Blob
                return blobToFile(blob, file.name);
            },
        }),
    });
}
`

```html
<pintura-editor [options]="editorDefaults" src="image.jpeg"></pintura-editor>

```

```css
::ng-deep .pintura-editor {
    height: 600px;
}

```

```javascript
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AngularPinturaModule } from '@pqina/angular-pintura';

@NgModule({
    declarations: [AppComponent],
    imports: [BrowserModule, AngularPinturaModule],
    exports: [AppComponent],
    providers: [],
    bootstrap: [AppComponent],
})
export class AppModule {}

```

* [index.html](#index-html-panel-8)

`<!DOCTYPE html>
<head>
    <link rel="stylesheet" href="./pintura/pintura.css" />
</head>

<script src="./jquery.js"></script>
<script src="./jquery-pintura/useEditorWithJQuery-iife.js"></script>
<script src="./pintura/pintura-iife.js"></script>

<script src="./heic2any.js"></script>

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

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

<script>
    useEditorWithJQuery(jQuery, pintura);

    $(function () {
        var { processImage, createDefaultImageReader, blobToFile } =
            $.fn.pintura;

        var editor = $('#editor').pinturaDefault({
            src: 'image.jpeg',
            imageReader: createDefaultImageReader({
                preprocessImageFile: async (file, options, onprogress) => {
                    // If is not of type HEIC we skip the file
                    if (!/heic/.test(file.type)) return file;

                    // Let's turn the HEIC image into JPEG so the browser can read it
                    const blob = await heic2any({
                        blob: file,
                        toType: 'image/jpeg',
                        quality: 0.94,
                    });

                    // The editor expects a File so let's convert our Blob
                    return blobToFile(blob, file.name);
                },
            }),
        });
    });
</script>
`

### createDefaultImageWriter

The `createDefaultImageWriter` function returns a default image writer array. This is an array of processes the editor runs to write the output image data.

By default it will output the `src` image file, the `dest` image file, and the [imageState](../properties/#imagestate). If a `store` has been defined it will also return the store object.

When using the editor UI the output is available in the editor ['process'](../events/#process) event. When using [processImage](#processimage) or [processDefaultImage](#processdefaultimage) the output is returned when the returned `Promise` resolves.

| Export                                          | Default value                               | Description                                                                                                                                                                                                                                                                           |
| ----------------------------------------------- | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [canvasMemoryLimit](#canvasmemorylimit)         | isIOS() ? 4096 \* 4096 : Infinity           | Memory limit to keep in account while drawing to canvas.                                                                                                                                                                                                                              |
| orientImage                                     | true                                        | Auto corrects the orientation of mobile photos.                                                                                                                                                                                                                                       |
| copyImageHead                                   | true                                        | Copy the image head of the origin image to the output image. Only used when format is set to 'file'.                                                                                                                                                                                  |
| [mimeType](#mimetype)                           | undefined                                   | Image mime type as a string, by default uses input image mime type.                                                                                                                                                                                                                   |
| [quality](#quality)                             | undefined                                   | A Number between 0 and 1 indicating image quality if the requested type is image/jpeg or image/webp. If this argument is anything else, the default values 0.92 and 0.80 are used for image/jpeg and image/webp respectively. Setting the value to 1 will result in very large files. |
| [renameFile](#renamefile)                       | undefined                                   | A synchronous function that receives the input file and expects a filename in return. Only called for 'file' format.                                                                                                                                                                  |
| [targetSize](#targetsize)                       | undefined                                   | The output size of the image                                                                                                                                                                                                                                                          |
| [imageDataResizer](#imagedataresizer)           | undefined                                   | The function to use for resizing the imageData.                                                                                                                                                                                                                                       |
| format                                          | 'file'                                      | Format of dest property, can be set to 'file', 'imageData', or 'canvas'.                                                                                                                                                                                                              |
| [store](#store)                                 | undefined                                   | URL to POST FormData to, object to finetune FormData, or async function for custom file upload or storage solution. URL and object modes are only used when format is set to 'file', for other output formats use async function.                                                     |
| outputProps                                     | \['src', 'dest', 'imageState', 'store'\]    | Which properties to retain on the output data object.                                                                                                                                                                                                                                 |
| [preprocessImageSource](#preprocessimagesource) | async (imageSource) \=> (imageSource)       | Allows preprocessing the source image data, for example to apply third party image optimisations or converting the file format before applying the [imageState](../properties/#imagestate).                                                                                           |
| [preprocessImageState](#preprocessimagestate)   | async (imageState) \=> (imageState)         | Allows preprocessing the [imageState](../properties/#imagestate), for example to replace shape placeholder text with actual content.                                                                                                                                                  |
| [postprocessImageData](#postprocessimagedata)   | async (imageData) \=> (imageData)           | Allows postprocessing the image data, for example to apply a circular crop mask.                                                                                                                                                                                                      |
| [postprocessImageBlob](#postprocessimageblob)   | async ({ src, blob, imageData }) \=> (blob) | Allows postprocessing the image blob, for example to convert an image to a format that isn't natively supported by the browser.                                                                                                                                                       |

An example implementation of `createDefaultImageWriter`.

* [ ![](/pintura/static/assets/technologies-mono/javascript.svg)JavaScript](#javascript-panel-24)
* [ ![](/pintura/static/assets/technologies-mono/react.svg)React](#react-panel-24)
* [ ![](/pintura/static/assets/technologies-mono/vue.svg)Vue](#vue-panel-24)
* [ ![](/pintura/static/assets/technologies-mono/svelte.svg)Svelte](#svelte-panel-24)
* [ ![](/pintura/static/assets/technologies-mono/angular.svg)Angular](#angular-panel-24)
* [ ![](/pintura/static/assets/technologies-mono/jquery.svg)jQuery](#jquery-panel-24)

* [index.html](#index-html-panel-24)

`<!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,
        createDefaultImageWriter,
    } from './pintura.js';

    const editor = appendDefaultEditor('#editor', {
        src: 'image.jpeg',
        imageWriter: createDefaultImageWriter({
            // Scale all input canvas data to fit a 4096 * 4096 rectangle
            canvasMemoryLimit: 4096 * 4096,

            // Fix image orientation
            orientImage: true,

            // Don't retain image EXIF data
            copyImageHead: false,

            // Convert all input images to jpegs
            mimeType: 'image/jpeg',

            // Reduce quality to 50%
            quality: 0.5,

            // Post images to API at './upload'
            store: './upload',

            // Limit size of output to this size
            targetSize: {
                width: 640,
                height: 480,
                fit: 'contain',
                upscale: false,
            },

            // Show all output props
            outputProps: [],
        }),
    });
</script>
`

* [App.jsx](#App-jsx-panel-24)
* [App.css](#App-css-panel-24)

`import '@pqina/pintura/pintura.css';
import './App.css';
import { PinturaEditor } from '@pqina/react-pintura';
import { getEditorDefaults, createDefaultImageWriter } from '@pqina/pintura';

const editorDefaults = getEditorDefaults({
    imageWriter: createDefaultImageWriter({
        // Scale all input canvas data to fit a 4096 * 4096 rectangle
        canvasMemoryLimit: 4096 * 4096,

        // Fix image orientation
        orientImage: true,

        // Don't retain image EXIF data
        copyImageHead: false,

        // Convert all input images to jpegs
        mimeType: 'image/jpeg',

        // Reduce quality to 50%
        quality: 0.5,

        // Post images to API at './upload'
        store: './upload',

        // Limit size of output to this size
        targetSize: {
            width: 640,
            height: 480,
            fit: 'contain',
            upscale: false,
        },

        // Show all output props
        outputProps: [],
    }),
});

function App() {
    return (
        <div className="App">
            <PinturaEditor {...editorDefaults} src={'image.jpeg'} />
        </div>
    );
}

export default App;
`

```css
.pintura-editor {
    height: 600px;
}

```

* [App.vue](#App-vue-panel-24)

`<template>
    <div>
        <PinturaEditor v-bind="editorDefaults" src="image.jpeg" />
    </div>
</template>
<script>
import { PinturaEditor } from '@pqina/vue-pintura';
import { getEditorDefaults, createDefaultImageWriter } from '@pqina/pintura';

export default {
    name: 'App',

    components: {
        PinturaEditor,
    },

    data() {
        return {
            editorDefaults: getEditorDefaults({
                imageWriter: createDefaultImageWriter({
                    // Scale all input canvas data to fit a 4096 * 4096 rectangle
                    canvasMemoryLimit: 4096 * 4096,

                    // Fix image orientation
                    orientImage: true,

                    // Don't retain image EXIF data
                    copyImageHead: false,

                    // Convert all input images to jpegs
                    mimeType: 'image/jpeg',

                    // Reduce quality to 50%
                    quality: 0.5,

                    // Post images to API at './upload'
                    store: './upload',

                    // Limit size of output to this size
                    targetSize: {
                        width: 640,
                        height: 480,
                        fit: 'contain',
                        upscale: false,
                    },

                    // Show all output props
                    outputProps: [],
                }),
            }),
        };
    },

    methods: {},
};
</script>
<style>
@import '@pqina/pintura/pintura.css';

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

* [App.svelte](#App-svelte-panel-24)

`<script>
    import { PinturaEditor } from '@pqina/svelte-pintura';
    import {
        getEditorDefaults,
        createDefaultImageWriter,
    } from '@pqina/pintura';
    import '@pqina/pintura/pintura.css';

    let editorDefaults = getEditorDefaults({
        imageWriter: createDefaultImageWriter({
            // Scale all input canvas data to fit a 4096 * 4096 rectangle
            canvasMemoryLimit: 4096 * 4096,

            // Fix image orientation
            orientImage: true,

            // Don't retain image EXIF data
            copyImageHead: false,

            // Convert all input images to jpegs
            mimeType: 'image/jpeg',

            // Reduce quality to 50%
            quality: 0.5,

            // Post images to API at './upload'
            store: './upload',

            // Limit size of output to this size
            targetSize: {
                width: 640,
                height: 480,
                fit: 'contain',
                upscale: false,
            },

            // Show all output props
            outputProps: [],
        }),
    });
</script>

<div>
    <PinturaEditor {...editorDefaults} src={'image.jpeg'} />
</div>

<style>
    div :global(.pintura-editor) {
        height: 600px;
    }
</style>
`

* [app.component.ts](#app-component-ts-panel-24)
* [app.component.html](#app-component-html-panel-24)
* [app.component.css](#app-component-css-panel-24)
* [app.module.ts](#app-module-ts-panel-24)

`import { Component } from '@angular/core';

import { getEditorDefaults, createDefaultImageWriter } from '@pqina/pintura';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
})
export class AppComponent {
    editorDefaults: any = getEditorDefaults({
        imageWriter: createDefaultImageWriter({
            // Scale all input canvas data to fit a 4096 * 4096 rectangle
            canvasMemoryLimit: 4096 * 4096,

            // Fix image orientation
            orientImage: true,

            // Don't retain image EXIF data
            copyImageHead: false,

            // Convert all input images to jpegs
            mimeType: 'image/jpeg',

            // Reduce quality to 50%
            quality: 0.5,

            // Post images to API at './upload'
            store: './upload',

            // Limit size of output to this size
            targetSize: {
                width: 640,
                height: 480,
                fit: 'contain',
                upscale: false,
            },

            // Show all output props
            outputProps: [],
        }),
    });
}
`

```html
<pintura-editor [options]="editorDefaults" src="image.jpeg"></pintura-editor>

```

```css
::ng-deep .pintura-editor {
    height: 600px;
}

```

```javascript
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AngularPinturaModule } from '@pqina/angular-pintura';

@NgModule({
    declarations: [AppComponent],
    imports: [BrowserModule, AngularPinturaModule],
    exports: [AppComponent],
    providers: [],
    bootstrap: [AppComponent],
})
export class AppModule {}

```

* [index.html](#index-html-panel-24)

`<!DOCTYPE html>
<head>
    <link rel="stylesheet" href="./pintura/pintura.css" />
</head>

<script src="./jquery.js"></script>
<script src="./jquery-pintura/useEditorWithJQuery-iife.js"></script>
<script src="./pintura/pintura-iife.js"></script>

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

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

<script>
    useEditorWithJQuery(jQuery, pintura);

    $(function () {
        var { createDefaultImageWriter } = $.fn.pintura;

        var editor = $('#editor').pinturaDefault({
            src: 'image.jpeg',
            imageWriter: createDefaultImageWriter({
                // Scale all input canvas data to fit a 4096 * 4096 rectangle
                canvasMemoryLimit: 4096 * 4096,

                // Fix image orientation
                orientImage: true,

                // Don't retain image EXIF data
                copyImageHead: false,

                // Convert all input images to jpegs
                mimeType: 'image/jpeg',

                // Reduce quality to 50%
                quality: 0.5,

                // Post images to API at './upload'
                store: './upload',

                // Limit size of output to this size
                targetSize: {
                    width: 640,
                    height: 480,
                    fit: 'contain',
                    upscale: false,
                },

                // Show all output props
                outputProps: [],
            }),
        });
    });
</script>
`

#### canvasMemoryLimit

The amount of memory in pixels the browser can allocate to a canvas element. By default this is limited to `4096 * 4096` on iOS.

#### mimeType

The output image format. By default Pintura Image Editor can output in the image formats supported by the Canvas [toBlob](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob) method. In general these image formats are supported by all major browsers.

* `image/png`
* `image/jpeg`
* `image/webp`

The following snippet converts all files to JPEGs and applies a slight compression to the result.

```js
createDefaultImageWriter({
    mimeType: 'image/jpeg',
    quality: 80,
});
```

#### quality

A Number between `0` and `1` indicating image quality if the requested type is image/jpeg or image/webp.

If `quality` is set to any other value, the default values `0.92` and `0.80` are used for image/jpeg and image/webp respectively.

Images are re-compressed. The input image compression doesn't matter as the output image is based on Bitmap data. This means depending on the compression settings and the compression of the input image the output image can be larger than the input image.

Please note that setting the value to `1` will result in very large image files as at that point no compression is applied.

#### renameFile

Allows dynamic renaming of the output file.

```js
createDefaultImageWriter({
    renameFile: (file) =>
        `output_${file.name.substring(0, file.name.lastIndexOf('.'))}.jpeg`,
});
```

#### targetSize

Limit the output size of images to the defined `width` and `height`.

| Export  | Default value | Description                                                                           |
| ------- | ------------- | ------------------------------------------------------------------------------------- |
| width   | undefined     | The target width of the output image.                                                 |
| height  | undefined     | The target height of the output image.                                                |
| fit     | 'contain'     | The method of resizing the input image, can be set to 'contain', 'cover', or 'force'. |
| upscale | false         | Should the input image data be upscaled to the supplied width and height.             |

Make sure output images are contained within a `640` × `640` rectangle. If images are smaller they won't be upscaled.

```js
createDefaultImageWriter({
    targetSize: {
        width: 640,
        height: 640,
        fit: 'contain',
        upscale: false,
    },
});
```

#### imageDataResizer

By default Pintura resizes images with a compact and relatively fast bilinear algorithm. While this results in perfectly fine output for most graphics, it can be sub-optimal when we're resizing high contrast imagery (like logo's) to very small sizes.

To work around this the `imageDataResizer` property enables us to supply our own resizing logic.

In the example below we configure [pica](https://github.com/nodeca/pica) to resize imageData.

* [ ![](/pintura/static/assets/technologies-mono/javascript.svg)JavaScript](#javascript-panel-32)
* [ ![](/pintura/static/assets/technologies-mono/react.svg)React](#react-panel-32)
* [ ![](/pintura/static/assets/technologies-mono/vue.svg)Vue](#vue-panel-32)
* [ ![](/pintura/static/assets/technologies-mono/svelte.svg)Svelte](#svelte-panel-32)
* [ ![](/pintura/static/assets/technologies-mono/angular.svg)Angular](#angular-panel-32)
* [ ![](/pintura/static/assets/technologies-mono/jquery.svg)jQuery](#jquery-panel-32)

* [index.html](#index-html-panel-32)

`<!DOCTYPE html>

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

<script src="./pica.js"></script>

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

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

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

    const editor = appendDefaultEditor('#editor', {
        src: 'image.jpeg',
        imageWriter: createDefaultImageWriter({
            targetSize: {
                width: 640,
                height: 640,
                fit: 'contain',
                upscale: false,
            },
            // use our custom pica resizer
            imageDataResizer: (imageData, outputWidth, outputHeight) =>
                new Promise((resolve) => {
                    pica()
                        .resizeBuffer({
                            // source data
                            src: imageData.data,

                            // source source width and height
                            width: imageData.width,
                            height: imageData.height,

                            // output width and height
                            toWidth: outputWidth,
                            toHeight: outputHeight,
                        })
                        .then((buffer) => {
                            // turn ArrayBuffer into new image data object and return to Pintura
                            const imageData = new ImageData(
                                outputWidth,
                                outputHeight
                            );
                            imageData.data.set(buffer);
                            resolve(imageData);
                        });
                }),
        }),
    });
</script>
`

* [App.jsx](#App-jsx-panel-32)
* [App.css](#App-css-panel-32)

`import '@pqina/pintura/pintura.css';
import './App.css';
import { PinturaEditor } from '@pqina/react-pintura';
import { getEditorDefaults, createDefaultImageWriter } from '@pqina/pintura';

import pica from 'pica';

const editorDefaults = getEditorDefaults({
    imageWriter: createDefaultImageWriter({
        targetSize: {
            width: 640,
            height: 640,
            fit: 'contain',
            upscale: false,
        },
        // use our custom pica resizer
        imageDataResizer: (imageData, outputWidth, outputHeight) =>
            new Promise((resolve) => {
                pica()
                    .resizeBuffer({
                        // source data
                        src: imageData.data,

                        // source source width and height
                        width: imageData.width,
                        height: imageData.height,

                        // output width and height
                        toWidth: outputWidth,
                        toHeight: outputHeight,
                    })
                    .then((buffer) => {
                        // turn ArrayBuffer into new image data object and return to Pintura
                        const imageData = new ImageData(
                            outputWidth,
                            outputHeight
                        );
                        imageData.data.set(buffer);
                        resolve(imageData);
                    });
            }),
    }),
});

function App() {
    return (
        <div className="App">
            <PinturaEditor {...editorDefaults} src={'image.jpeg'} />
        </div>
    );
}

export default App;
`

```css
.pintura-editor {
    height: 600px;
}

```

* [App.vue](#App-vue-panel-32)

`<template>
    <div>
        <PinturaEditor v-bind="editorDefaults" src="image.jpeg" />
    </div>
</template>
<script>
import { PinturaEditor } from '@pqina/vue-pintura';
import { getEditorDefaults, createDefaultImageWriter } from '@pqina/pintura';

import pica from 'pica';

export default {
    name: 'App',

    components: {
        PinturaEditor,
    },

    data() {
        return {
            editorDefaults: getEditorDefaults({
                imageWriter: createDefaultImageWriter({
                    targetSize: {
                        width: 640,
                        height: 640,
                        fit: 'contain',
                        upscale: false,
                    },
                    // use our custom pica resizer
                    imageDataResizer: (imageData, outputWidth, outputHeight) =>
                        new Promise((resolve) => {
                            pica()
                                .resizeBuffer({
                                    // source data
                                    src: imageData.data,

                                    // source source width and height
                                    width: imageData.width,
                                    height: imageData.height,

                                    // output width and height
                                    toWidth: outputWidth,
                                    toHeight: outputHeight,
                                })
                                .then((buffer) => {
                                    // turn ArrayBuffer into new image data object and return to Pintura
                                    const imageData = new ImageData(
                                        outputWidth,
                                        outputHeight
                                    );
                                    imageData.data.set(buffer);
                                    resolve(imageData);
                                });
                        }),
                }),
            }),
        };
    },

    methods: {},
};
</script>
<style>
@import '@pqina/pintura/pintura.css';

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

* [App.svelte](#App-svelte-panel-32)

`<script>
    import { PinturaEditor } from '@pqina/svelte-pintura';
    import {
        getEditorDefaults,
        createDefaultImageWriter,
    } from '@pqina/pintura';
    import '@pqina/pintura/pintura.css';

    import pica from 'pica';

    let editorDefaults = getEditorDefaults({
        imageWriter: createDefaultImageWriter({
            targetSize: {
                width: 640,
                height: 640,
                fit: 'contain',
                upscale: false,
            },
            // use our custom pica resizer
            imageDataResizer: (imageData, outputWidth, outputHeight) =>
                new Promise((resolve) => {
                    pica()
                        .resizeBuffer({
                            // source data
                            src: imageData.data,

                            // source source width and height
                            width: imageData.width,
                            height: imageData.height,

                            // output width and height
                            toWidth: outputWidth,
                            toHeight: outputHeight,
                        })
                        .then((buffer) => {
                            // turn ArrayBuffer into new image data object and return to Pintura
                            const imageData = new ImageData(
                                outputWidth,
                                outputHeight
                            );
                            imageData.data.set(buffer);
                            resolve(imageData);
                        });
                }),
        }),
    });
</script>

<div>
    <PinturaEditor {...editorDefaults} src={'image.jpeg'} />
</div>

<style>
    div :global(.pintura-editor) {
        height: 600px;
    }
</style>
`

* [app.component.ts](#app-component-ts-panel-32)
* [app.component.html](#app-component-html-panel-32)
* [app.component.css](#app-component-css-panel-32)
* [app.module.ts](#app-module-ts-panel-32)

`import { Component } from '@angular/core';

import { getEditorDefaults, createDefaultImageWriter } from '@pqina/pintura';

import pica from 'pica';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
})
export class AppComponent {
    editorDefaults: any = getEditorDefaults({
        imageWriter: createDefaultImageWriter({
            targetSize: {
                width: 640,
                height: 640,
                fit: 'contain',
                upscale: false,
            },
            // use our custom pica resizer
            imageDataResizer: (imageData, outputWidth, outputHeight) =>
                new Promise((resolve) => {
                    pica()
                        .resizeBuffer({
                            // source data
                            src: imageData.data,

                            // source source width and height
                            width: imageData.width,
                            height: imageData.height,

                            // output width and height
                            toWidth: outputWidth,
                            toHeight: outputHeight,
                        })
                        .then((buffer) => {
                            // turn ArrayBuffer into new image data object and return to Pintura
                            const imageData = new ImageData(
                                outputWidth,
                                outputHeight
                            );
                            imageData.data.set(buffer);
                            resolve(imageData);
                        });
                }),
        }),
    });
}
`

```html
<pintura-editor [options]="editorDefaults" src="image.jpeg"></pintura-editor>

```

```css
::ng-deep .pintura-editor {
    height: 600px;
}

```

```javascript
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AngularPinturaModule } from '@pqina/angular-pintura';

@NgModule({
    declarations: [AppComponent],
    imports: [BrowserModule, AngularPinturaModule],
    exports: [AppComponent],
    providers: [],
    bootstrap: [AppComponent],
})
export class AppModule {}

```

* [index.html](#index-html-panel-32)

`<!DOCTYPE html>
<head>
    <link rel="stylesheet" href="./pintura/pintura.css" />
</head>

<script src="./jquery.js"></script>
<script src="./jquery-pintura/useEditorWithJQuery-iife.js"></script>
<script src="./pintura/pintura-iife.js"></script>

<script src="./pica.js"></script>

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

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

<script>
    useEditorWithJQuery(jQuery, pintura);

    $(function () {
        var { createDefaultImageWriter } = $.fn.pintura;

        var editor = $('#editor').pinturaDefault({
            src: 'image.jpeg',
            imageWriter: createDefaultImageWriter({
                targetSize: {
                    width: 640,
                    height: 640,
                    fit: 'contain',
                    upscale: false,
                },
                // use our custom pica resizer
                imageDataResizer: (imageData, outputWidth, outputHeight) =>
                    new Promise((resolve) => {
                        pica()
                            .resizeBuffer({
                                // source data
                                src: imageData.data,

                                // source source width and height
                                width: imageData.width,
                                height: imageData.height,

                                // output width and height
                                toWidth: outputWidth,
                                toHeight: outputHeight,
                            })
                            .then((buffer) => {
                                // turn ArrayBuffer into new image data object and return to Pintura
                                const imageData = new ImageData(
                                    outputWidth,
                                    outputHeight
                                );
                                imageData.data.set(buffer);
                                resolve(imageData);
                            });
                    }),
            }),
        });
    });
</script>
`

#### store

The `store` property accepts a URL, a store configuration object, or a Function.

If we set a URL the editor will POST the output file and image state to that location as `FormData`. It will use `"dest"` as name for the file field, and `"imageState"` as name for the JSON string of the [imageState](../properties/#imagestate) object.

The XMLHttpRequest instance used to POST the data will be stored in the `store` property of the image writer output data object.

* [ ![](/pintura/static/assets/technologies-mono/javascript.svg)JavaScript](#javascript-panel-33)
* [ ![](/pintura/static/assets/technologies-mono/react.svg)React](#react-panel-33)
* [ ![](/pintura/static/assets/technologies-mono/vue.svg)Vue](#vue-panel-33)
* [ ![](/pintura/static/assets/technologies-mono/svelte.svg)Svelte](#svelte-panel-33)
* [ ![](/pintura/static/assets/technologies-mono/angular.svg)Angular](#angular-panel-33)
* [ ![](/pintura/static/assets/technologies-mono/jquery.svg)jQuery](#jquery-panel-33)

* [index.html](#index-html-panel-33)

`<!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',
        imageWriter: {
            store: './my-custom-upload',
        },
    });

    editor.on('process', (imageWriterResult) => {
        const { store, dest } = imageWriterResult;
        // 'store' is the XMLHttpRequest instance used
        // for uploading the file, it contains
        // all XHR request information
    });
</script>
`

* [App.jsx](#App-jsx-panel-33)
* [App.css](#App-css-panel-33)

`import '@pqina/pintura/pintura.css';
import './App.css';
import { PinturaEditor } from '@pqina/react-pintura';
import { getEditorDefaults } from '@pqina/pintura';

const editorDefaults = getEditorDefaults({
    imageWriter: {
        store: './my-custom-upload',
    },
});

function App() {
    const handleEditorProcess = (imageWriterResult) => {
        const { store, dest } = imageWriterResult;
        // 'store' is the XMLHttpRequest instance used
        // for uploading the file, it contains
        // all XHR request information
    };

    return (
        <div className="App">
            <PinturaEditor
                {...editorDefaults}
                src={'image.jpeg'}
                onProcess={handleEditorProcess}
            />
        </div>
    );
}

export default App;
`

```css
.pintura-editor {
    height: 600px;
}

```

* [App.vue](#App-vue-panel-33)

`<template>
    <div>
        <PinturaEditor
            v-bind="editorDefaults"
            src="image.jpeg"
            v-on:pintura:process="handleEditorProcess($event)"
        />
    </div>
</template>
<script>
import { PinturaEditor } from '@pqina/vue-pintura';
import { getEditorDefaults } from '@pqina/pintura';

export default {
    name: 'App',

    components: {
        PinturaEditor,
    },

    data() {
        return {
            editorDefaults: getEditorDefaults({
                imageWriter: {
                    store: './my-custom-upload',
                },
            }),
        };
    },

    methods: {
        handleEditorProcess: function (imageWriterResult) {
            const { store, dest } = imageWriterResult;
            // 'store' is the XMLHttpRequest instance used
            // for uploading the file, it contains
            // all XHR request information
        },
    },
};
</script>
<style>
@import '@pqina/pintura/pintura.css';

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

* [App.svelte](#App-svelte-panel-33)

`<script>
    import { PinturaEditor } from '@pqina/svelte-pintura';
    import { getEditorDefaults } from '@pqina/pintura';
    import '@pqina/pintura/pintura.css';

    let editorDefaults = getEditorDefaults({
        imageWriter: {
            store: './my-custom-upload',
        },
    });

    const handleEditorProcess = (event) => {
        const imageWriterResult = event.detail;

        const { store, dest } = imageWriterResult;
        // 'store' is the XMLHttpRequest instance used
        // for uploading the file, it contains
        // all XHR request information
    };
</script>

<div>
    <PinturaEditor
        {...editorDefaults}
        src={'image.jpeg'}
        on:process={handleEditorProcess}
    />
</div>

<style>
    div :global(.pintura-editor) {
        height: 600px;
    }
</style>
`

* [app.component.ts](#app-component-ts-panel-33)
* [app.component.html](#app-component-html-panel-33)
* [app.component.css](#app-component-css-panel-33)
* [app.module.ts](#app-module-ts-panel-33)

`import { Component } from '@angular/core';

import { getEditorDefaults } from '@pqina/pintura';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
})
export class AppComponent {
    editorDefaults: any = getEditorDefaults({
        imageWriter: {
            store: './my-custom-upload',
        },
    });

    handleEditorProcess(imageWriterResult: any): void {
        const { store, dest } = imageWriterResult;
        // 'store' is the XMLHttpRequest instance used
        // for uploading the file, it contains
        // all XHR request information
    }
}
`

```html
<pintura-editor
    [options]="editorDefaults"
    src="image.jpeg"
    (process)="handleEditorProcess($event)"
></pintura-editor>

```

```css
::ng-deep .pintura-editor {
    height: 600px;
}

```

```javascript
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AngularPinturaModule } from '@pqina/angular-pintura';

@NgModule({
    declarations: [AppComponent],
    imports: [BrowserModule, AngularPinturaModule],
    exports: [AppComponent],
    providers: [],
    bootstrap: [AppComponent],
})
export class AppModule {}

```

* [index.html](#index-html-panel-33)

`<!DOCTYPE html>
<head>
    <link rel="stylesheet" href="./pintura/pintura.css" />
</head>

<script src="./jquery.js"></script>
<script src="./jquery-pintura/useEditorWithJQuery-iife.js"></script>
<script src="./pintura/pintura-iife.js"></script>

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

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

<script>
    useEditorWithJQuery(jQuery, pintura);

    $(function () {
        var editor = $('#editor').pinturaDefault({
            src: 'image.jpeg',
            imageWriter: {
                store: './my-custom-upload',
            },
        });

        editor.on('pintura:process', function (event) {
            const imageWriterResult = event.detail;

            const { store, dest } = imageWriterResult;
            // 'store' is the XMLHttpRequest instance used
            // for uploading the file, it contains
            // all XHR request information
        });
    });
</script>
`

We can pass a configuration object to alter the defaults fields, add additional fields, or add custom headers and set credentials.

It still allows us to set the `url` but now we can set a `dataset` Function. This Function receives the state and allows selecting data and naming fields.

* [ ![](/pintura/static/assets/technologies-mono/javascript.svg)JavaScript](#javascript-panel-34)
* [ ![](/pintura/static/assets/technologies-mono/react.svg)React](#react-panel-34)
* [ ![](/pintura/static/assets/technologies-mono/vue.svg)Vue](#vue-panel-34)
* [ ![](/pintura/static/assets/technologies-mono/svelte.svg)Svelte](#svelte-panel-34)
* [ ![](/pintura/static/assets/technologies-mono/angular.svg)Angular](#angular-panel-34)
* [ ![](/pintura/static/assets/technologies-mono/jquery.svg)jQuery](#jquery-panel-34)

* [index.html](#index-html-panel-34)

`<!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',
        imageWriter: {
            store: {
                url: './my-custom-upload',
                dataset: (state) => [
                    ['imageFile', state.dest, state.dest.name],
                    ['imageState', state.imageState],
                ],
                credentials: 'same-origin',
                headers: {
                    'X-My-Header': 'Hello World',
                },
            },
        },
    });
</script>
`

* [App.jsx](#App-jsx-panel-34)
* [App.css](#App-css-panel-34)

`import '@pqina/pintura/pintura.css';
import './App.css';
import { PinturaEditor } from '@pqina/react-pintura';
import { getEditorDefaults } from '@pqina/pintura';

const editorDefaults = getEditorDefaults({
    imageWriter: {
        store: {
            url: './my-custom-upload',
            dataset: (state) => [
                ['imageFile', state.dest, state.dest.name],
                ['imageState', state.imageState],
            ],
            credentials: 'same-origin',
            headers: {
                'X-My-Header': 'Hello World',
            },
        },
    },
});

function App() {
    return (
        <div className="App">
            <PinturaEditor {...editorDefaults} src={'image.jpeg'} />
        </div>
    );
}

export default App;
`

```css
.pintura-editor {
    height: 600px;
}

```

* [App.vue](#App-vue-panel-34)

`<template>
    <div>
        <PinturaEditor v-bind="editorDefaults" src="image.jpeg" />
    </div>
</template>
<script>
import { PinturaEditor } from '@pqina/vue-pintura';
import { getEditorDefaults } from '@pqina/pintura';

export default {
    name: 'App',

    components: {
        PinturaEditor,
    },

    data() {
        return {
            editorDefaults: getEditorDefaults({
                imageWriter: {
                    store: {
                        url: './my-custom-upload',
                        dataset: (state) => [
                            ['imageFile', state.dest, state.dest.name],
                            ['imageState', state.imageState],
                        ],
                        credentials: 'same-origin',
                        headers: {
                            'X-My-Header': 'Hello World',
                        },
                    },
                },
            }),
        };
    },

    methods: {},
};
</script>
<style>
@import '@pqina/pintura/pintura.css';

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

* [App.svelte](#App-svelte-panel-34)

`<script>
    import { PinturaEditor } from '@pqina/svelte-pintura';
    import { getEditorDefaults } from '@pqina/pintura';
    import '@pqina/pintura/pintura.css';

    let editorDefaults = getEditorDefaults({
        imageWriter: {
            store: {
                url: './my-custom-upload',
                dataset: (state) => [
                    ['imageFile', state.dest, state.dest.name],
                    ['imageState', state.imageState],
                ],
                credentials: 'same-origin',
                headers: {
                    'X-My-Header': 'Hello World',
                },
            },
        },
    });
</script>

<div>
    <PinturaEditor {...editorDefaults} src={'image.jpeg'} />
</div>

<style>
    div :global(.pintura-editor) {
        height: 600px;
    }
</style>
`

* [app.component.ts](#app-component-ts-panel-34)
* [app.component.html](#app-component-html-panel-34)
* [app.component.css](#app-component-css-panel-34)
* [app.module.ts](#app-module-ts-panel-34)

`import { Component } from '@angular/core';

import { getEditorDefaults } from '@pqina/pintura';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
})
export class AppComponent {
    editorDefaults: any = getEditorDefaults({
        imageWriter: {
            store: {
                url: './my-custom-upload',
                dataset: (state) => [
                    ['imageFile', state.dest, state.dest.name],
                    ['imageState', state.imageState],
                ],
                credentials: 'same-origin',
                headers: {
                    'X-My-Header': 'Hello World',
                },
            },
        },
    });
}
`

```html
<pintura-editor [options]="editorDefaults" src="image.jpeg"></pintura-editor>

```

```css
::ng-deep .pintura-editor {
    height: 600px;
}

```

```javascript
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AngularPinturaModule } from '@pqina/angular-pintura';

@NgModule({
    declarations: [AppComponent],
    imports: [BrowserModule, AngularPinturaModule],
    exports: [AppComponent],
    providers: [],
    bootstrap: [AppComponent],
})
export class AppModule {}

```

* [index.html](#index-html-panel-34)

`<!DOCTYPE html>
<head>
    <link rel="stylesheet" href="./pintura/pintura.css" />
</head>

<script src="./jquery.js"></script>
<script src="./jquery-pintura/useEditorWithJQuery-iife.js"></script>
<script src="./pintura/pintura-iife.js"></script>

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

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

<script>
    useEditorWithJQuery(jQuery, pintura);

    $(function () {
        var editor = $('#editor').pinturaDefault({
            src: 'image.jpeg',
            imageWriter: {
                store: {
                    url: './my-custom-upload',
                    dataset: (state) => [
                        ['imageFile', state.dest, state.dest.name],
                        ['imageState', state.imageState],
                    ],
                    credentials: 'same-origin',
                    headers: {
                        'X-My-Header': 'Hello World',
                    },
                },
            },
        });
    });
</script>
`

If we need more control we can set a Function to the store property. This Function should return a Promise.

In the example below we run a custom upload function to store data in the [imageState](../properties/#imagestate).

* [ ![](/pintura/static/assets/technologies-mono/javascript.svg)JavaScript](#javascript-panel-35)
* [ ![](/pintura/static/assets/technologies-mono/react.svg)React](#react-panel-35)
* [ ![](/pintura/static/assets/technologies-mono/vue.svg)Vue](#vue-panel-35)
* [ ![](/pintura/static/assets/technologies-mono/svelte.svg)Svelte](#svelte-panel-35)
* [ ![](/pintura/static/assets/technologies-mono/angular.svg)Angular](#angular-panel-35)
* [ ![](/pintura/static/assets/technologies-mono/jquery.svg)jQuery](#jquery-panel-35)

* [index.html](#index-html-panel-35)

`<!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',
        imageWriter: {
            store: (state, options, onprogress) =>
                new Promise((resolve, reject) => {
                    const { dest } = state;

                    // create a formdata object to send to the server
                    const formData = new FormData();
                    formData.append('image', dest, dest.name);

                    // create a request object
                    const request = new XMLHttpRequest();
                    request.open('POST', './upload');

                    // show progress in interface
                    request.upload.onprogress = onprogress;

                    // catch errors
                    request.onerror = () =>
                        reject('oh no something went wrong!');
                    request.ontimeout = () =>
                        reject('oh no request timed out!');

                    // handle success state
                    request.onload = () => {
                        if (request.status >= 200 && request.status < 300) {
                            // store request in state so it can be accessed by other processes
                            state.store = request;
                            resolve(state);
                        } else {
                            reject('oh no something went wrong!');
                        }
                    };

                    // start uploading the image
                    request.send(formData);
                }),
        },
    });
</script>
`

* [App.jsx](#App-jsx-panel-35)
* [App.css](#App-css-panel-35)

`import '@pqina/pintura/pintura.css';
import './App.css';
import { PinturaEditor } from '@pqina/react-pintura';
import { getEditorDefaults } from '@pqina/pintura';

const editorDefaults = getEditorDefaults({
    imageWriter: {
        store: (state, options, onprogress) =>
            new Promise((resolve, reject) => {
                const { dest } = state;

                // create a formdata object to send to the server
                const formData = new FormData();
                formData.append('image', dest, dest.name);

                // create a request object
                const request = new XMLHttpRequest();
                request.open('POST', './upload');

                // show progress in interface
                request.upload.onprogress = onprogress;

                // catch errors
                request.onerror = () => reject('oh no something went wrong!');
                request.ontimeout = () => reject('oh no request timed out!');

                // handle success state
                request.onload = () => {
                    if (request.status >= 200 && request.status < 300) {
                        // store request in state so it can be accessed by other processes
                        state.store = request;
                        resolve(state);
                    } else {
                        reject('oh no something went wrong!');
                    }
                };

                // start uploading the image
                request.send(formData);
            }),
    },
});

function App() {
    return (
        <div className="App">
            <PinturaEditor {...editorDefaults} src={'image.jpeg'} />
        </div>
    );
}

export default App;
`

```css
.pintura-editor {
    height: 600px;
}

```

* [App.vue](#App-vue-panel-35)

`<template>
    <div>
        <PinturaEditor v-bind="editorDefaults" src="image.jpeg" />
    </div>
</template>
<script>
import { PinturaEditor } from '@pqina/vue-pintura';
import { getEditorDefaults } from '@pqina/pintura';

export default {
    name: 'App',

    components: {
        PinturaEditor,
    },

    data() {
        return {
            editorDefaults: getEditorDefaults({
                imageWriter: {
                    store: (state, options, onprogress) =>
                        new Promise((resolve, reject) => {
                            const { dest } = state;

                            // create a formdata object to send to the server
                            const formData = new FormData();
                            formData.append('image', dest, dest.name);

                            // create a request object
                            const request = new XMLHttpRequest();
                            request.open('POST', './upload');

                            // show progress in interface
                            request.upload.onprogress = onprogress;

                            // catch errors
                            request.onerror = () =>
                                reject('oh no something went wrong!');
                            request.ontimeout = () =>
                                reject('oh no request timed out!');

                            // handle success state
                            request.onload = () => {
                                if (
                                    request.status >= 200 &&
                                    request.status < 300
                                ) {
                                    // store request in state so it can be accessed by other processes
                                    state.store = request;
                                    resolve(state);
                                } else {
                                    reject('oh no something went wrong!');
                                }
                            };

                            // start uploading the image
                            request.send(formData);
                        }),
                },
            }),
        };
    },

    methods: {},
};
</script>
<style>
@import '@pqina/pintura/pintura.css';

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

* [App.svelte](#App-svelte-panel-35)

`<script>
    import { PinturaEditor } from '@pqina/svelte-pintura';
    import { getEditorDefaults } from '@pqina/pintura';
    import '@pqina/pintura/pintura.css';

    let editorDefaults = getEditorDefaults({
        imageWriter: {
            store: (state, options, onprogress) =>
                new Promise((resolve, reject) => {
                    const { dest } = state;

                    // create a formdata object to send to the server
                    const formData = new FormData();
                    formData.append('image', dest, dest.name);

                    // create a request object
                    const request = new XMLHttpRequest();
                    request.open('POST', './upload');

                    // show progress in interface
                    request.upload.onprogress = onprogress;

                    // catch errors
                    request.onerror = () =>
                        reject('oh no something went wrong!');
                    request.ontimeout = () =>
                        reject('oh no request timed out!');

                    // handle success state
                    request.onload = () => {
                        if (request.status >= 200 && request.status < 300) {
                            // store request in state so it can be accessed by other processes
                            state.store = request;
                            resolve(state);
                        } else {
                            reject('oh no something went wrong!');
                        }
                    };

                    // start uploading the image
                    request.send(formData);
                }),
        },
    });
</script>

<div>
    <PinturaEditor {...editorDefaults} src={'image.jpeg'} />
</div>

<style>
    div :global(.pintura-editor) {
        height: 600px;
    }
</style>
`

* [app.component.ts](#app-component-ts-panel-35)
* [app.component.html](#app-component-html-panel-35)
* [app.component.css](#app-component-css-panel-35)
* [app.module.ts](#app-module-ts-panel-35)

`import { Component } from '@angular/core';

import { getEditorDefaults } from '@pqina/pintura';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
})
export class AppComponent {
    editorDefaults: any = getEditorDefaults({
        imageWriter: {
            store: (state, options, onprogress) =>
                new Promise((resolve, reject) => {
                    const { dest } = state;

                    // create a formdata object to send to the server
                    const formData = new FormData();
                    formData.append('image', dest, dest.name);

                    // create a request object
                    const request = new XMLHttpRequest();
                    request.open('POST', './upload');

                    // show progress in interface
                    request.upload.onprogress = onprogress;

                    // catch errors
                    request.onerror = () =>
                        reject('oh no something went wrong!');
                    request.ontimeout = () =>
                        reject('oh no request timed out!');

                    // handle success state
                    request.onload = () => {
                        if (request.status >= 200 && request.status < 300) {
                            // store request in state so it can be accessed by other processes
                            state.store = request;
                            resolve(state);
                        } else {
                            reject('oh no something went wrong!');
                        }
                    };

                    // start uploading the image
                    request.send(formData);
                }),
        },
    });
}
`

```html
<pintura-editor [options]="editorDefaults" src="image.jpeg"></pintura-editor>

```

```css
::ng-deep .pintura-editor {
    height: 600px;
}

```

```javascript
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AngularPinturaModule } from '@pqina/angular-pintura';

@NgModule({
    declarations: [AppComponent],
    imports: [BrowserModule, AngularPinturaModule],
    exports: [AppComponent],
    providers: [],
    bootstrap: [AppComponent],
})
export class AppModule {}

```

* [index.html](#index-html-panel-35)

`<!DOCTYPE html>
<head>
    <link rel="stylesheet" href="./pintura/pintura.css" />
</head>

<script src="./jquery.js"></script>
<script src="./jquery-pintura/useEditorWithJQuery-iife.js"></script>
<script src="./pintura/pintura-iife.js"></script>

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

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

<script>
    useEditorWithJQuery(jQuery, pintura);

    $(function () {
        var editor = $('#editor').pinturaDefault({
            src: 'image.jpeg',
            imageWriter: {
                store: (state, options, onprogress) =>
                    new Promise((resolve, reject) => {
                        const { dest } = state;

                        // create a formdata object to send to the server
                        const formData = new FormData();
                        formData.append('image', dest, dest.name);

                        // create a request object
                        const request = new XMLHttpRequest();
                        request.open('POST', './upload');

                        // show progress in interface
                        request.upload.onprogress = onprogress;

                        // catch errors
                        request.onerror = () =>
                            reject('oh no something went wrong!');
                        request.ontimeout = () =>
                            reject('oh no request timed out!');

                        // handle success state
                        request.onload = () => {
                            if (request.status >= 200 && request.status < 300) {
                                // store request in state so it can be accessed by other processes
                                state.store = request;
                                resolve(state);
                            } else {
                                reject('oh no something went wrong!');
                            }
                        };

                        // start uploading the image
                        request.send(formData);
                    }),
            },
        });
    });
</script>
`

#### preprocessImageSource

Allows preprocessing the source image data, for example to apply third party image optimisations or converting the file format before applying the [imageState](../properties/#imagestate).

* [ ![](/pintura/static/assets/technologies-mono/javascript.svg)JavaScript](#javascript-panel-36)
* [ ![](/pintura/static/assets/technologies-mono/react.svg)React](#react-panel-36)
* [ ![](/pintura/static/assets/technologies-mono/vue.svg)Vue](#vue-panel-36)
* [ ![](/pintura/static/assets/technologies-mono/svelte.svg)Svelte](#svelte-panel-36)
* [ ![](/pintura/static/assets/technologies-mono/angular.svg)Angular](#angular-panel-36)
* [ ![](/pintura/static/assets/technologies-mono/jquery.svg)jQuery](#jquery-panel-36)

* [index.html](#index-html-panel-36)

`<!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, processImage } from './pintura.js';

    const editor = appendDefaultEditor('#editor', {
        src: 'image.jpeg',
        imageWriter: {
            preprocessImageSource: async (
                src,
                options,
                onprogress,
                imageState
            ) => {
                // upload src to third-party service and return new File object
                return src;
            },
        },
    });
</script>
`

* [App.jsx](#App-jsx-panel-36)
* [App.css](#App-css-panel-36)

`import '@pqina/pintura/pintura.css';
import './App.css';
import { PinturaEditor } from '@pqina/react-pintura';
import { processImage, getEditorDefaults } from '@pqina/pintura';

const editorDefaults = getEditorDefaults({
    imageWriter: {
        preprocessImageSource: async (src, options, onprogress, imageState) => {
            // upload src to third-party service and return new File object
            return src;
        },
    },
});

function App() {
    return (
        <div className="App">
            <PinturaEditor {...editorDefaults} src={'image.jpeg'} />
        </div>
    );
}

export default App;
`

```css
.pintura-editor {
    height: 600px;
}

```

* [App.vue](#App-vue-panel-36)

`<template>
    <div>
        <PinturaEditor v-bind="editorDefaults" src="image.jpeg" />
    </div>
</template>
<script>
import { PinturaEditor } from '@pqina/vue-pintura';
import { processImage, getEditorDefaults } from '@pqina/pintura';

export default {
    name: 'App',

    components: {
        PinturaEditor,
    },

    data() {
        return {
            editorDefaults: getEditorDefaults({
                imageWriter: {
                    preprocessImageSource: async (
                        src,
                        options,
                        onprogress,
                        imageState
                    ) => {
                        // upload src to third-party service and return new File object
                        return src;
                    },
                },
            }),
        };
    },

    methods: {},
};
</script>
<style>
@import '@pqina/pintura/pintura.css';

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

* [App.svelte](#App-svelte-panel-36)

`<script>
    import { PinturaEditor } from '@pqina/svelte-pintura';
    import { processImage, getEditorDefaults } from '@pqina/pintura';
    import '@pqina/pintura/pintura.css';

    let editorDefaults = getEditorDefaults({
        imageWriter: {
            preprocessImageSource: async (
                src,
                options,
                onprogress,
                imageState
            ) => {
                // upload src to third-party service and return new File object
                return src;
            },
        },
    });
</script>

<div>
    <PinturaEditor {...editorDefaults} src={'image.jpeg'} />
</div>

<style>
    div :global(.pintura-editor) {
        height: 600px;
    }
</style>
`

* [app.component.ts](#app-component-ts-panel-36)
* [app.component.html](#app-component-html-panel-36)
* [app.component.css](#app-component-css-panel-36)
* [app.module.ts](#app-module-ts-panel-36)

`import { Component } from '@angular/core';

import { processImage, getEditorDefaults } from '@pqina/pintura';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
})
export class AppComponent {
    editorDefaults: any = getEditorDefaults({
        imageWriter: {
            preprocessImageSource: async (
                src,
                options,
                onprogress,
                imageState
            ) => {
                // upload src to third-party service and return new File object
                return src;
            },
        },
    });
}
`

```html
<pintura-editor [options]="editorDefaults" src="image.jpeg"></pintura-editor>

```

```css
::ng-deep .pintura-editor {
    height: 600px;
}

```

```javascript
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AngularPinturaModule } from '@pqina/angular-pintura';

@NgModule({
    declarations: [AppComponent],
    imports: [BrowserModule, AngularPinturaModule],
    exports: [AppComponent],
    providers: [],
    bootstrap: [AppComponent],
})
export class AppModule {}

```

* [index.html](#index-html-panel-36)

`<!DOCTYPE html>
<head>
    <link rel="stylesheet" href="./pintura/pintura.css" />
</head>

<script src="./jquery.js"></script>
<script src="./jquery-pintura/useEditorWithJQuery-iife.js"></script>
<script src="./pintura/pintura-iife.js"></script>

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

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

<script>
    useEditorWithJQuery(jQuery, pintura);

    $(function () {
        var { processImage } = $.fn.pintura;

        var editor = $('#editor').pinturaDefault({
            src: 'image.jpeg',
            imageWriter: {
                preprocessImageSource: async (
                    src,
                    options,
                    onprogress,
                    imageState
                ) => {
                    // upload src to third-party service and return new File object
                    return src;
                },
            },
        });
    });
</script>
`

#### preprocessImageState

This hook allows us to pre-process the [imageState](../properties/#imagestate) object before it's used to generate the output image.

In the example below we replace all name placeholders in annotation text values with the name "John Connor".

* [ ![](/pintura/static/assets/technologies-mono/javascript.svg)JavaScript](#javascript-panel-37)
* [ ![](/pintura/static/assets/technologies-mono/react.svg)React](#react-panel-37)
* [ ![](/pintura/static/assets/technologies-mono/vue.svg)Vue](#vue-panel-37)
* [ ![](/pintura/static/assets/technologies-mono/svelte.svg)Svelte](#svelte-panel-37)
* [ ![](/pintura/static/assets/technologies-mono/angular.svg)Angular](#angular-panel-37)
* [ ![](/pintura/static/assets/technologies-mono/jquery.svg)jQuery](#jquery-panel-37)

* [index.html](#index-html-panel-37)

`<!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, processImage } from './pintura.js';

    const editor = appendDefaultEditor('#editor', {
        src: 'image.jpeg',
        imageWriter: {
            preprocessImageState: (imageState) => {
                // create new annotation array
                imageState.annotation = imageState.annotation.map((shape) => {
                    // this is not a text shape so skip
                    if (!shape.text) return shape;

                    // replace placeholders in text properties
                    shape.text = shape.text.replace(/{name}/g, 'John Connor');

                    return shape;
                });

                // return updated image state
                return imageState;
            },
        },
    });
</script>
`

* [App.jsx](#App-jsx-panel-37)
* [App.css](#App-css-panel-37)

`import '@pqina/pintura/pintura.css';
import './App.css';
import { PinturaEditor } from '@pqina/react-pintura';
import { processImage, getEditorDefaults } from '@pqina/pintura';

const editorDefaults = getEditorDefaults({
    imageWriter: {
        preprocessImageState: (imageState) => {
            // create new annotation array
            imageState.annotation = imageState.annotation.map((shape) => {
                // this is not a text shape so skip
                if (!shape.text) return shape;

                // replace placeholders in text properties
                shape.text = shape.text.replace(/{name}/g, 'John Connor');

                return shape;
            });

            // return updated image state
            return imageState;
        },
    },
});

function App() {
    return (
        <div className="App">
            <PinturaEditor {...editorDefaults} src={'image.jpeg'} />
        </div>
    );
}

export default App;
`

```css
.pintura-editor {
    height: 600px;
}

```

* [App.vue](#App-vue-panel-37)

`<template>
    <div>
        <PinturaEditor v-bind="editorDefaults" src="image.jpeg" />
    </div>
</template>
<script>
import { PinturaEditor } from '@pqina/vue-pintura';
import { processImage, getEditorDefaults } from '@pqina/pintura';

export default {
    name: 'App',

    components: {
        PinturaEditor,
    },

    data() {
        return {
            editorDefaults: getEditorDefaults({
                imageWriter: {
                    preprocessImageState: (imageState) => {
                        // create new annotation array
                        imageState.annotation = imageState.annotation.map(
                            (shape) => {
                                // this is not a text shape so skip
                                if (!shape.text) return shape;

                                // replace placeholders in text properties
                                shape.text = shape.text.replace(
                                    /{name}/g,
                                    'John Connor'
                                );

                                return shape;
                            }
                        );

                        // return updated image state
                        return imageState;
                    },
                },
            }),
        };
    },

    methods: {},
};
</script>
<style>
@import '@pqina/pintura/pintura.css';

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

* [App.svelte](#App-svelte-panel-37)

`<script>
    import { PinturaEditor } from '@pqina/svelte-pintura';
    import { processImage, getEditorDefaults } from '@pqina/pintura';
    import '@pqina/pintura/pintura.css';

    let editorDefaults = getEditorDefaults({
        imageWriter: {
            preprocessImageState: (imageState) => {
                // create new annotation array
                imageState.annotation = imageState.annotation.map((shape) => {
                    // this is not a text shape so skip
                    if (!shape.text) return shape;

                    // replace placeholders in text properties
                    shape.text = shape.text.replace(/{name}/g, 'John Connor');

                    return shape;
                });

                // return updated image state
                return imageState;
            },
        },
    });
</script>

<div>
    <PinturaEditor {...editorDefaults} src={'image.jpeg'} />
</div>

<style>
    div :global(.pintura-editor) {
        height: 600px;
    }
</style>
`

* [app.component.ts](#app-component-ts-panel-37)
* [app.component.html](#app-component-html-panel-37)
* [app.component.css](#app-component-css-panel-37)
* [app.module.ts](#app-module-ts-panel-37)

`import { Component } from '@angular/core';

import { processImage, getEditorDefaults } from '@pqina/pintura';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
})
export class AppComponent {
    editorDefaults: any = getEditorDefaults({
        imageWriter: {
            preprocessImageState: (imageState) => {
                // create new annotation array
                imageState.annotation = imageState.annotation.map((shape) => {
                    // this is not a text shape so skip
                    if (!shape.text) return shape;

                    // replace placeholders in text properties
                    shape.text = shape.text.replace(/{name}/g, 'John Connor');

                    return shape;
                });

                // return updated image state
                return imageState;
            },
        },
    });
}
`

```html
<pintura-editor [options]="editorDefaults" src="image.jpeg"></pintura-editor>

```

```css
::ng-deep .pintura-editor {
    height: 600px;
}

```

```javascript
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AngularPinturaModule } from '@pqina/angular-pintura';

@NgModule({
    declarations: [AppComponent],
    imports: [BrowserModule, AngularPinturaModule],
    exports: [AppComponent],
    providers: [],
    bootstrap: [AppComponent],
})
export class AppModule {}

```

* [index.html](#index-html-panel-37)

`<!DOCTYPE html>
<head>
    <link rel="stylesheet" href="./pintura/pintura.css" />
</head>

<script src="./jquery.js"></script>
<script src="./jquery-pintura/useEditorWithJQuery-iife.js"></script>
<script src="./pintura/pintura-iife.js"></script>

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

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

<script>
    useEditorWithJQuery(jQuery, pintura);

    $(function () {
        var { processImage } = $.fn.pintura;

        var editor = $('#editor').pinturaDefault({
            src: 'image.jpeg',
            imageWriter: {
                preprocessImageState: (imageState) => {
                    // create new annotation array
                    imageState.annotation = imageState.annotation.map(
                        (shape) => {
                            // this is not a text shape so skip
                            if (!shape.text) return shape;

                            // replace placeholders in text properties
                            shape.text = shape.text.replace(
                                /{name}/g,
                                'John Connor'
                            );

                            return shape;
                        }
                    );

                    // return updated image state
                    return imageState;
                },
            },
        });
    });
</script>
`

#### postprocessImageData

Run post image processing on the `imageData` the editor outputs. The example snippet below will apply a circular crop mask to the image.

* [ ![](/pintura/static/assets/technologies-mono/javascript.svg)JavaScript](#javascript-panel-38)
* [ ![](/pintura/static/assets/technologies-mono/react.svg)React](#react-panel-38)
* [ ![](/pintura/static/assets/technologies-mono/vue.svg)Vue](#vue-panel-38)
* [ ![](/pintura/static/assets/technologies-mono/svelte.svg)Svelte](#svelte-panel-38)
* [ ![](/pintura/static/assets/technologies-mono/angular.svg)Angular](#angular-panel-38)
* [ ![](/pintura/static/assets/technologies-mono/jquery.svg)jQuery](#jquery-panel-38)

* [index.html](#index-html-panel-38)

`<!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, processImage } from './pintura.js';

    const editor = appendDefaultEditor('#editor', {
        src: 'image.jpeg',
        imageWriter: {
            postprocessImageData: (imageData) =>
                new Promise((resolve) => {
                    // create a canvas element to handle the imageData
                    const canvas = document.createElement('canvas');
                    canvas.width = imageData.width;
                    canvas.height = imageData.height;
                    const ctx = canvas.getContext('2d');
                    ctx.putImageData(imageData, 0, 0);

                    // only draw image where we render our circular mask
                    ctx.globalCompositeOperation = 'destination-in';

                    // draw our circular mask
                    ctx.fillStyle = 'black';
                    ctx.beginPath();
                    ctx.arc(
                        imageData.width * 0.5,
                        imageData.height * 0.5,
                        imageData.width * 0.5,
                        0,
                        2 * Math.PI
                    );
                    ctx.fill();

                    // returns the modified imageData
                    resolve(
                        ctx.getImageData(0, 0, canvas.width, canvas.height)
                    );
                }),
        },
    });
</script>
`

* [App.jsx](#App-jsx-panel-38)
* [App.css](#App-css-panel-38)

`import '@pqina/pintura/pintura.css';
import './App.css';
import { PinturaEditor } from '@pqina/react-pintura';
import { processImage, getEditorDefaults } from '@pqina/pintura';

const editorDefaults = getEditorDefaults({
    imageWriter: {
        postprocessImageData: (imageData) =>
            new Promise((resolve) => {
                // create a canvas element to handle the imageData
                const canvas = document.createElement('canvas');
                canvas.width = imageData.width;
                canvas.height = imageData.height;
                const ctx = canvas.getContext('2d');
                ctx.putImageData(imageData, 0, 0);

                // only draw image where we render our circular mask
                ctx.globalCompositeOperation = 'destination-in';

                // draw our circular mask
                ctx.fillStyle = 'black';
                ctx.beginPath();
                ctx.arc(
                    imageData.width * 0.5,
                    imageData.height * 0.5,
                    imageData.width * 0.5,
                    0,
                    2 * Math.PI
                );
                ctx.fill();

                // returns the modified imageData
                resolve(ctx.getImageData(0, 0, canvas.width, canvas.height));
            }),
    },
});

function App() {
    return (
        <div className="App">
            <PinturaEditor {...editorDefaults} src={'image.jpeg'} />
        </div>
    );
}

export default App;
`

```css
.pintura-editor {
    height: 600px;
}

```

* [App.vue](#App-vue-panel-38)

`<template>
    <div>
        <PinturaEditor v-bind="editorDefaults" src="image.jpeg" />
    </div>
</template>
<script>
import { PinturaEditor } from '@pqina/vue-pintura';
import { processImage, getEditorDefaults } from '@pqina/pintura';

export default {
    name: 'App',

    components: {
        PinturaEditor,
    },

    data() {
        return {
            editorDefaults: getEditorDefaults({
                imageWriter: {
                    postprocessImageData: (imageData) =>
                        new Promise((resolve) => {
                            // create a canvas element to handle the imageData
                            const canvas = document.createElement('canvas');
                            canvas.width = imageData.width;
                            canvas.height = imageData.height;
                            const ctx = canvas.getContext('2d');
                            ctx.putImageData(imageData, 0, 0);

                            // only draw image where we render our circular mask
                            ctx.globalCompositeOperation = 'destination-in';

                            // draw our circular mask
                            ctx.fillStyle = 'black';
                            ctx.beginPath();
                            ctx.arc(
                                imageData.width * 0.5,
                                imageData.height * 0.5,
                                imageData.width * 0.5,
                                0,
                                2 * Math.PI
                            );
                            ctx.fill();

                            // returns the modified imageData
                            resolve(
                                ctx.getImageData(
                                    0,
                                    0,
                                    canvas.width,
                                    canvas.height
                                )
                            );
                        }),
                },
            }),
        };
    },

    methods: {},
};
</script>
<style>
@import '@pqina/pintura/pintura.css';

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

* [App.svelte](#App-svelte-panel-38)

`<script>
    import { PinturaEditor } from '@pqina/svelte-pintura';
    import { processImage, getEditorDefaults } from '@pqina/pintura';
    import '@pqina/pintura/pintura.css';

    let editorDefaults = getEditorDefaults({
        imageWriter: {
            postprocessImageData: (imageData) =>
                new Promise((resolve) => {
                    // create a canvas element to handle the imageData
                    const canvas = document.createElement('canvas');
                    canvas.width = imageData.width;
                    canvas.height = imageData.height;
                    const ctx = canvas.getContext('2d');
                    ctx.putImageData(imageData, 0, 0);

                    // only draw image where we render our circular mask
                    ctx.globalCompositeOperation = 'destination-in';

                    // draw our circular mask
                    ctx.fillStyle = 'black';
                    ctx.beginPath();
                    ctx.arc(
                        imageData.width * 0.5,
                        imageData.height * 0.5,
                        imageData.width * 0.5,
                        0,
                        2 * Math.PI
                    );
                    ctx.fill();

                    // returns the modified imageData
                    resolve(
                        ctx.getImageData(0, 0, canvas.width, canvas.height)
                    );
                }),
        },
    });
</script>

<div>
    <PinturaEditor {...editorDefaults} src={'image.jpeg'} />
</div>

<style>
    div :global(.pintura-editor) {
        height: 600px;
    }
</style>
`

* [app.component.ts](#app-component-ts-panel-38)
* [app.component.html](#app-component-html-panel-38)
* [app.component.css](#app-component-css-panel-38)
* [app.module.ts](#app-module-ts-panel-38)

`import { Component } from '@angular/core';

import { processImage, getEditorDefaults } from '@pqina/pintura';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
})
export class AppComponent {
    editorDefaults: any = getEditorDefaults({
        imageWriter: {
            postprocessImageData: (imageData) =>
                new Promise((resolve) => {
                    // create a canvas element to handle the imageData
                    const canvas = document.createElement('canvas');
                    canvas.width = imageData.width;
                    canvas.height = imageData.height;
                    const ctx = canvas.getContext('2d');
                    ctx.putImageData(imageData, 0, 0);

                    // only draw image where we render our circular mask
                    ctx.globalCompositeOperation = 'destination-in';

                    // draw our circular mask
                    ctx.fillStyle = 'black';
                    ctx.beginPath();
                    ctx.arc(
                        imageData.width * 0.5,
                        imageData.height * 0.5,
                        imageData.width * 0.5,
                        0,
                        2 * Math.PI
                    );
                    ctx.fill();

                    // returns the modified imageData
                    resolve(
                        ctx.getImageData(0, 0, canvas.width, canvas.height)
                    );
                }),
        },
    });
}
`

```html
<pintura-editor [options]="editorDefaults" src="image.jpeg"></pintura-editor>

```

```css
::ng-deep .pintura-editor {
    height: 600px;
}

```

```javascript
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AngularPinturaModule } from '@pqina/angular-pintura';

@NgModule({
    declarations: [AppComponent],
    imports: [BrowserModule, AngularPinturaModule],
    exports: [AppComponent],
    providers: [],
    bootstrap: [AppComponent],
})
export class AppModule {}

```

* [index.html](#index-html-panel-38)

`<!DOCTYPE html>
<head>
    <link rel="stylesheet" href="./pintura/pintura.css" />
</head>

<script src="./jquery.js"></script>
<script src="./jquery-pintura/useEditorWithJQuery-iife.js"></script>
<script src="./pintura/pintura-iife.js"></script>

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

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

<script>
    useEditorWithJQuery(jQuery, pintura);

    $(function () {
        var { processImage } = $.fn.pintura;

        var editor = $('#editor').pinturaDefault({
            src: 'image.jpeg',
            imageWriter: {
                postprocessImageData: (imageData) =>
                    new Promise((resolve) => {
                        // create a canvas element to handle the imageData
                        const canvas = document.createElement('canvas');
                        canvas.width = imageData.width;
                        canvas.height = imageData.height;
                        const ctx = canvas.getContext('2d');
                        ctx.putImageData(imageData, 0, 0);

                        // only draw image where we render our circular mask
                        ctx.globalCompositeOperation = 'destination-in';

                        // draw our circular mask
                        ctx.fillStyle = 'black';
                        ctx.beginPath();
                        ctx.arc(
                            imageData.width * 0.5,
                            imageData.height * 0.5,
                            imageData.width * 0.5,
                            0,
                            2 * Math.PI
                        );
                        ctx.fill();

                        // returns the modified imageData
                        resolve(
                            ctx.getImageData(0, 0, canvas.width, canvas.height)
                        );
                    }),
            },
        });
    });
</script>
`

#### postprocessImageBlob

Run postprocessing on the image blob, for example to convert an image to a format that isn't natively supported by the browser. [For example to save GIF images](../../../examples/save-gif-image/)

### outputProps

Which properties to retain on the output data object.

Defaults to `['src', 'dest', 'imageState', 'store']`, leave empty to not remove any properties of the output data object.

### createDefaultMediaWriter

Use to group image and video writers. Pass generic options to multiple writers. Assign to `imageWriter` property.

```js
createDefaultMediaWriter(
    {
        // Shared options
    },
    [
        creatDefaultImageWriter({
            // Image writer specific options
        }),
        createDefaultVideoWriter({
            // Video writer specific options
        }),
    ]
);
```

### createDefaultImageScrambler

Creates the default image scrambler that is used with the [imageScrambler](../properties/#imagescrambler) property for created redacted images.

The default image scrambler first scales down the original image to create a mosaic effect, it then scrambles the pixels by offsetting them randomly, and finally it applies a blur. These steps prevent [de-blurring the image](https://cseweb.ucsd.edu//~saul/papers/pets16-redact.pdf) and recovering the redacted information.

| Export         | Default value | Description                                              |
| -------------- | ------------- | -------------------------------------------------------- |
| scrambleAmount | 2             | The amount to scramble the image pixels before blurring. |
| blurAmount     | 6             | The amount of blur to apply to the scrambled image.      |

```js
createDefaultImageScrambler({
    scrambleAmount: 2,
    blurAmount: 6,
});
```

### createDefaultShapePreprocessor

Creates the default [shapePreprocessor](#createshapepreprocessor) used for parsing line styles and frame styles.

```js
openEditor({
    src: 'my-image.jpeg',
    shapePreprocessor: createDefaultShapePreprocessor(),
});
```

We can add custom shape processors by passing them as an array to `createDefaultShapePreprocessor`, see below:

```js
openEditor({
    src: 'my-image.jpeg',
    shapePreprocessor: createDefaultShapePreprocessor([
        (shape, options) => {
            // shape preprocessor logc here
        },
    ]),
});
```

When using a default constructor like `openDefaultEditor` or `getEditorDefaults` the `shapePreprocessor` array is automatically expanded with the default shape preprocessors.

#### LineStart and LineEnd style preprocessors

LineStart and LineEnd style preprocessors process shapes that have the `lineStart` or `lineEnd` property set to one of the following values.

| Style          | Description                     |
| -------------- | ------------------------------- |
| 'none'         | Don't render a decorative shape |
| 'bar'          | Render a bar.                   |
| 'arrow'        | Renders an open arrow.          |
| 'arrow-solid'  | Renders a solid arrow.          |
| 'circle'       | Render a open circle.           |
| 'circle-solid' | Renders a solid circle.         |
| 'square'       | Render a open square.           |
| 'square-solid' | Renders a solid square.         |

#### Frame style preprocessors

Frame style preprocessors process shapes that have the `frameStyle` property set to one of the following values.

| Style      | Description                                                  |
| ---------- | ------------------------------------------------------------ |
| 'solid'    | Renders a solid border around the crop.                      |
| 'hook'     | Renders corners in hook of the crop.                         |
| 'line'     | Renders a line alongside the edge of the crop.               |
| 'edge'     | Renders a separate line alongside each edge of the crop.     |
| 'nine'     | Renders 9-slice frames, pass image with frameImage property. |
| 'polaroid' | Renders the image inside a classic polaroid.                 |

Depending on the frame style additional properties can be set to finetune the look and feel of the frame.

| Property                    | Description                                                                                                                                                                                                                  |
| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| frameColor                  | Determines the [color](../../markup-editor/shapes/#colors) of the frame. Defaults to \[1, 1, 1\].                                                                                                                            |
| frameInset                  | Determines the distance between the crop edge and the line. Only available for 'line', 'edge' and 'hook' frame styles. Value should be set to a percentage. Defaults to '2.5%'.                                              |
| frameOffset                 | Determines the distance between the lines when using the 'line' frame style. Determines the draw offset from the intersecting edge when using the 'edge' frame style. Value should be set to a percentage. Defaults to '5%'. |
| frameAmount                 | Determines how many lines are drawn when using the 'line' frame. Value should be set to a number. Defaults to 1.                                                                                                             |
| frameSize                   | Determines the width of the frame. Value should be set to a percentage. Defaults to '0.25%'.                                                                                                                                 |
| frameLength                 | Determines the length of the hook lines when using the 'hook' frame style. Value should be set to a percentage. Defaults to '2.5%'.                                                                                          |
| frameRadius                 | Determines the corner radius of the frame. Only available on 'solid' and 'line' frame styles. Value should be set to a percentage. Defaults to 0.                                                                            |
| frameImage                  | The image used in the 'nine' frameStyle.                                                                                                                                                                                     |
| [frameSlices](#frameslices) | An object describing the positions of the slices used to select images for each part of the 9-slice image frame.                                                                                                             |

#### frameSlices

The coordinates set to the `frameSlices` property below describe 4 slices inside an image (see visual below code snippet).

They are set to values between `0` and `1`, `.2` in the example below means the slice will be positioned at `20%` offset from the `frameImage` width.

* [ ![](/pintura/static/assets/technologies-mono/javascript.svg)JavaScript](#javascript-panel-59)
* [ ![](/pintura/static/assets/technologies-mono/react.svg)React](#react-panel-59)
* [ ![](/pintura/static/assets/technologies-mono/vue.svg)Vue](#vue-panel-59)
* [ ![](/pintura/static/assets/technologies-mono/svelte.svg)Svelte](#svelte-panel-59)
* [ ![](/pintura/static/assets/technologies-mono/angular.svg)Angular](#angular-panel-59)
* [ ![](/pintura/static/assets/technologies-mono/jquery.svg)jQuery](#jquery-panel-59)

* [index.html](#index-html-panel-59)

`<!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',
        imageFrame: {
            frameStyle: 'nine',
            frameImage: 'my-frame.png',
            frameSlices: {
                x1: 0.2, // red
                y1: 0.2, // green
                x2: 0.8, // blue
                y2: 0.8, // yellow
            },
        },
    });
</script>
`

* [App.jsx](#App-jsx-panel-59)
* [App.css](#App-css-panel-59)

`import '@pqina/pintura/pintura.css';
import './App.css';
import { PinturaEditor } from '@pqina/react-pintura';
import { getEditorDefaults } from '@pqina/pintura';

const editorDefaults = getEditorDefaults();

function App() {
    return (
        <div className="App">
            <PinturaEditor
                {...editorDefaults}
                src={'image.jpeg'}
                imageFrame={{
                    frameStyle: 'nine',
                    frameImage: 'my-frame.png',
                    frameSlices: {
                        x1: 0.2, // red
                        y1: 0.2, // green
                        x2: 0.8, // blue
                        y2: 0.8, // yellow
                    },
                }}
            />
        </div>
    );
}

export default App;
`

```css
.pintura-editor {
    height: 600px;
}

```

* [App.vue](#App-vue-panel-59)

`<template>
    <div>
        <PinturaEditor
            v-bind="editorDefaults"
            src="image.jpeg"
            :imageFrame="imageFrame"
        />
    </div>
</template>
<script>
import { PinturaEditor } from '@pqina/vue-pintura';
import { getEditorDefaults } from '@pqina/pintura';

export default {
    name: 'App',

    components: {
        PinturaEditor,
    },

    data() {
        return {
            editorDefaults: getEditorDefaults(),

            imageFrame: {
                frameStyle: 'nine',
                frameImage: 'my-frame.png',
                frameSlices: {
                    x1: 0.2, // red
                    y1: 0.2, // green
                    x2: 0.8, // blue
                    y2: 0.8, // yellow
                },
            },
        };
    },

    methods: {},
};
</script>
<style>
@import '@pqina/pintura/pintura.css';

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

* [App.svelte](#App-svelte-panel-59)

`<script>
    import { PinturaEditor } from '@pqina/svelte-pintura';
    import { getEditorDefaults } from '@pqina/pintura';
    import '@pqina/pintura/pintura.css';

    let editorDefaults = getEditorDefaults();
</script>

<div>
    <PinturaEditor
        {...editorDefaults}
        src={'image.jpeg'}
        imageFrame={{
            frameStyle: 'nine',
            frameImage: 'my-frame.png',
            frameSlices: {
                x1: 0.2, // red
                y1: 0.2, // green
                x2: 0.8, // blue
                y2: 0.8, // yellow
            },
        }}
    />
</div>

<style>
    div :global(.pintura-editor) {
        height: 600px;
    }
</style>
`

* [app.component.ts](#app-component-ts-panel-59)
* [app.component.html](#app-component-html-panel-59)
* [app.component.css](#app-component-css-panel-59)
* [app.module.ts](#app-module-ts-panel-59)

`import { Component } from '@angular/core';

import { getEditorDefaults } from '@pqina/pintura';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
})
export class AppComponent {
    editorDefaults: any = getEditorDefaults();

    imageFrame: any = {
        frameStyle: 'nine',
        frameImage: 'my-frame.png',
        frameSlices: {
            x1: 0.2, // red
            y1: 0.2, // green
            x2: 0.8, // blue
            y2: 0.8, // yellow
        },
    };
}
`

`<pintura-editor
    [options]="editorDefaults"
    src="image.jpeg"
    [imageFrame]="imageFrame"
></pintura-editor>
`

```css
::ng-deep .pintura-editor {
    height: 600px;
}

```

```javascript
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AngularPinturaModule } from '@pqina/angular-pintura';

@NgModule({
    declarations: [AppComponent],
    imports: [BrowserModule, AngularPinturaModule],
    exports: [AppComponent],
    providers: [],
    bootstrap: [AppComponent],
})
export class AppModule {}

```

* [index.html](#index-html-panel-59)

`<!DOCTYPE html>
<head>
    <link rel="stylesheet" href="./pintura/pintura.css" />
</head>

<script src="./jquery.js"></script>
<script src="./jquery-pintura/useEditorWithJQuery-iife.js"></script>
<script src="./pintura/pintura-iife.js"></script>

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

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

<script>
    useEditorWithJQuery(jQuery, pintura);

    $(function () {
        var editor = $('#editor').pinturaDefault({
            src: 'image.jpeg',
            imageFrame: {
                frameStyle: 'nine',
                frameImage: 'my-frame.png',
                frameSlices: {
                    x1: 0.2, // red
                    y1: 0.2, // green
                    x2: 0.8, // blue
                    y2: 0.8, // yellow
                },
            },
        });
    });
</script>
`

As we can see in the image below the 4 slices result in 9 individual images which Pintura will automatically assign to the correct frame shapes.

`x1` `x2` `y1` `y2` ![](/pintura/demo/image.jpeg) 

### createShapePreprocessor

Accepts a shape processor array and returns a function that can be assigned to the editor `shapePreprocessor` property.

The single parameter should be an array of functions. Each function receives the `inputShape` and an `options` object. The function can then return an array of shapes or undefined if it can't process the shape.

If the function can preprocess the shape it should then make sure it doesn't preprocess the shape twice, in the example below this means removing the `style` property from the output shape.

The `option` object contains a property called `isPreview` which is set to `true` when rendering the preview image and is set to `false` when rendering the output image. It also contains the current `flipX`, `flipY`, and `rotation` state and visual `scale` of the image.

```js
// Array of shape preprocessors
[
    (inputShape, options) => [
        outputShape,
        outputShape,
        outputShape /* more shapes ...*/,
    ],
    (inputShape, options) => [outputShape],
    // ... another processor here
];
```

In the example below we pick up shapes that have a custom `style` property. If it's set to `'white'` we apply a white `backgroundColor`.

```js
import {
    openDefaultEditor,
    createDefaultFrameStyles,
    createDefaultLineEndStyles,
    createShapePreprocessor,
    createLineEndProcessor,
    createFrameStyleProcessor,
} from './pintura.js';

openDefaultEditor({
    src: 'image.jpeg',

    // Add a square to the image with a custom `style` property
    imageAnnotation: [
        {
            x: 0,
            y: 0,
            width: 200,
            height: 200,
            style: 'white',
        },
    ],

    // Set our custom shape preprocessor
    shapePreprocessor: createShapePreprocessor([
        // set default line end styles
        createLineEndProcessor(createDefaultLineEndStyles()),

        // set default frame styles
        createFrameStyleProcessor(createDefaultFrameStyles()),

        // our custom processor
        (shape, options) => {
            // Should return undefined if no match
            if (!shape.style) return;

            // Should then make sure it no longer matches after processing, here we remove the style property from the clone
            const { style, ...clone } = shape;

            // Make changes to the output shape
            if (style === 'white') clone.backgroundColor = [1, 1, 1];

            // Return new shapes
            return [clone];
        },
    ]),
});
```

Note that the shapeProcessor runs before rendering the shape to the screen and before rendering the shape to the output image, it doesn't modify the original shape data.

In the example above this means that the new `backgroundColor` value won't be reflected in the editor style controls. We can use [shape.disableStyle](../../markup-editor/shapes/#disablestyle) to disable style controls.

### createDefaultFrameStyles

export to generate the default frame style object.

### createDefaultLineEndStyles

export to generate the default line end styles object.

### createFrameStyleProcessor

export to merge custom frame styles with the default frame styles.

### createLineEndProcessor

export to merge custom line end styles with the default line end styles.

### processImage

Use the `processImage` function to generate images without loading the editor interface.

```js
import {
    processImage,
    createDefaultImageReader,
    createDefaultImageWriter,
} from './pintura.js';

const res = await processImage('image.jpeg', {
    imageReader: createDefaultImageReader(),
    imageWriter: createDefaultImageWriter(),
    imageCrop: {
        x: 64,
        y: 64,
        width: 512,
        height: 512,
    },
    imageRotation: 0.25,
});

console.log(res);
// logs: { src:…, dest:… , imageState:…, store:… }
```

### processDefaultImage

Use the `processDefaultImage` function to generate images without loading the editor interface, this function is the same as [processImage](#processimage) but automatically sets all the defaults like `imageReader`, `imageWriter`, `imageOrienter` and `shapePreprocessor`.

```js
import { processDefaultImage } from './pintura.js';

const res = await processDefaultImage('image.jpeg', {
    imageCrop: {
        x: 64,
        y: 64,
        width: 512,
        height: 512,
    },
    imageRotation: 0.25,
});

console.log(res);
// logs: { src:…, dest:… , imageState:…, store:… }
```

### imageStateToCanvas

A helper function to draw the current `imageState` to a target canvas.

```js
import { imageStateToCanvas } from './pintura.js';

// src is either a canvas, video, or image element

// imageState is a Pintura generated imageState object

// third argument is an optional options object

const drawer = imageStateToCanvas(src, imageState, {
    // an optional target canvas, if not supplied one will be returned
    targetCanvas: undefined,

    // optional target size object of the output
    targetSize: undefined,

    // should automatically draw or wait for draw call
    disableDraw: false,

    // force target size to be even, automatically set to true when source is a video
    forceEventSize: undefined,
});

// if disableDraw is false call `draw()` to update the canvas
drawer.draw();

// get reference to the canvas element
const canvasElement = drawer.canvas;
```

### legacyDataToImageState

Converts legacy v6 data objects to `imageState` objects.

Needs the image size and a reference to the editor instance to correctly calculate the imageState.

```js
import { legacyDataToImageState } from '@pqina/pintura';

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

editor.on('load', ({ size }) => {
    editor.imageState = legacyDataToImageState(editor, size, legacyDataObject);
});
```

### selectionToMask

Converts a selection array to a mask blob or canvas.

Should be supplied with an array of selections, the size of the context, an object containing the `rotation`, `flipX`, and `flipY` state of the context (the editor imageState can be passed as well).

The last parameter is an optional `options` parameter with the following props.

| Property          | Default value | Description                                                                                                    |
| ----------------- | ------------- | -------------------------------------------------------------------------------------------------------------- |
| format            | 'canvas'      | The returned format, either 'canvas' or 'blob'                                                                 |
| backgroundColor   | \[0, 0, 0\]   | The color to fill the canvas with, defaults to black.                                                          |
| foregroundColor   | \[1, 1, 1\]   | The color to fill the masked area with, defaults to white. Set to undefined or \[0, 0, 0, 0\] for transparent. |
| forceSquareCanvas | false         | Set to true to force the mask canvas to a square.                                                              |
| scope             | 'mask'        | If is mask returns a canvas that fits the mask, else returns mask in image space.                              |
| padding           | 0             | Padding to apply around mask.                                                                                  |
| maxSize           | ImageSize     | The maximum mask size, defaults to imag size.                                                                  |
| targetSize        | ImageSize     | The target size of the mask.                                                                                   |
| precision         | 7             | Precision to use when calculating the mask rectangle, a lower value is more precise but slower.                |

```js
import { selectionToMask } from '@pqina/pintura';

// `editor` is a reference to a Pintura editor instance

const maskBlob = await selectionToMask(
    editor.imageSelection,
    editor.imageSize,
    editor.imageState,
    {
        format: 'blob'
        padding: 10
    })
```