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() |
Creates a helper object to correctly orient images. |
createDefaultImageReader(options) |
Creates the default image reader. This is the array of processes the editor uses to read image data. |
createDefaultImageWriter(options) |
Creates the default image writer. This is the array of processes the editor uses to write image data. |
createDefaultMediaWriter(options) |
Creates a default media writer. This method groups image and video writers. |
createDefaultImageScrambler(options) |
Creates the default image scrambler. This is a function that receives an ImageBitmap or ImageData object and returns a canvas with scrambled data. |
createDefaultShapePreprocessor() |
Creates the default shape preprocessor used for parsing lineEnd styles and frame styles. |
createShapePreprocessor(processors[]) |
Accepts a shape processor configuration and returns a function that can be assigned to the editor shapePreprocessor property.
|
createDefaultFrameStyles() |
Generates the default frame style object. |
createDefaultLineEndStyles() |
Generates the default line style object. |
createFrameStyleProcessor(styles) |
Merge custom frame styles with the default frame styles. |
createLineEndProcessor(styles) |
Merge custom line end styles with the default line end styles. |
processImage(file, options) |
processes the file with supplied properties. |
processDefaultImage(file, options) |
Same as processImage but sets default image reader, image writer and image orienter.
|
imageStateToCanvas(src, imageState, options) |
A helper function to draw the current imageState to a target canvas. |
legacyDataToImageState(editorRef, imageSize, legacyDataObj) |
Converts a Pintura Image Editor legacy data object to an imageState object.
|
selectionToMask(selection, imageSize, imageState, options) |
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.
const imageOrienter = createDefaultImageOrienter();
console.log(imageOrienter);
// logs: { read: function, apply: function }
The returned object should be assigned to the 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. 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 (for example HEIC).
The returned image reader object should be assigned to the editor imageReader
property.
Export | Default value | Description |
---|---|---|
orientImage |
|
Auto corrects the orientation of mobile photos. |
outputProps |
|
Which properties to retain on the output data object. |
request |
|
Add custom headers to the XMLHttpRequest and set the credentials property.
|
preprocessImageFile |
|
Allows preprocessing the image file, for example to turn a HEIC image into a browser supported image format. |
<!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>
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;
.pintura-editor {
height: 600px;
}
<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>
<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>
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',
},
},
}),
});
}
<pintura-editor [options]="editorDefaults" src="image.jpeg"></pintura-editor>
::ng-deep .pintura-editor {
height: 600px;
}
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 {}
<!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'
event, see an example of this object below.
{
// 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
hook.
<!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>
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;
.pintura-editor {
height: 600px;
}
<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>
<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>
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',
},
},
}),
});
}
<pintura-editor [options]="editorDefaults" src="image.jpeg"></pintura-editor>
::ng-deep .pintura-editor {
height: 600px;
}
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 {}
<!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 in the preprocessImageFile
hook.
<!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>
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;
.pintura-editor {
height: 600px;
}
<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>
<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>
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);
},
}),
});
}
<pintura-editor [options]="editorDefaults" src="image.jpeg"></pintura-editor>
::ng-deep .pintura-editor {
height: 600px;
}
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 {}
<!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
. 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'
event. When using processImage
or processDefaultImage
the output is returned when the returned Promise
resolves.
Export | Default value | Description |
---|---|---|
canvasMemoryLimit |
|
Memory limit to keep in account while drawing to canvas. |
orientImage |
|
Auto corrects the orientation of mobile photos. |
copyImageHead |
|
Copy the image head of the origin image to the output image. Only used when format is set to 'file' .
|
mimeType |
|
Image mime type as a string, by default uses input image mime type. |
quality |
|
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. Other arguments are ignored. |
renameFile |
|
A synchronous function that receives the input file and expects a filename in return. Only called for 'file' format.
|
targetSize |
|
The output size of the image |
imageDataResizer |
|
The function to use for resizing the imageData .
|
format |
|
Format of dest property, can be set to 'file' , 'imageData' , or 'canvas' .
|
store |
|
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 |
|
Which properties to retain on the output data object. |
preprocessImageSource |
|
Allows preprocessing the source image data, for example to apply third party image optimisations or converting the file format before applying the imageState .
|
preprocessImageState |
|
Allows preprocessing the imageState , for example to replace shape placeholder text with actual content.
|
postprocessImageData |
|
Allows postprocessing the image data, for example to apply a circular crop mask. |
postprocessImageBlob |
|
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
.
<!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>
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;
.pintura-editor {
height: 600px;
}
<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>
<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>
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: [],
}),
});
}
<pintura-editor [options]="editorDefaults" src="image.jpeg"></pintura-editor>
::ng-deep .pintura-editor {
height: 600px;
}
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 {}
<!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
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.
createDefaultImageWriter({
mimeType: 'image/jpeg',
quality: 80,
});
renameFile
Allows dynamic renaming of the output file.
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 |
|
The target width of the output image. |
height |
|
The target height of the output image. |
fit |
|
The method of resizing the input image, can be set to 'contain' , 'cover' , or 'force' .
|
upscale |
|
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.
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 to resize imageData.
<!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>
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;
.pintura-editor {
height: 600px;
}
<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>
<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>
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);
});
}),
}),
});
}
<pintura-editor [options]="editorDefaults" src="image.jpeg"></pintura-editor>
::ng-deep .pintura-editor {
height: 600px;
}
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 {}
<!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
object.
The XMLHttpRequest instance used to POST the data will be stored in the store
property of the image writer output data object.
<!DOCTYPE html>
<head>
<link rel="stylesheet" href="./pintura.css" />
</head>
<style>
.pintura-editor {
height: 600px;
}
</style>
<div id="editor"></div>
<script type="module">
import { appendDefaultEditor } from './pintura.js';
const editor = appendDefaultEditor('#editor', {
src: 'image.jpeg',
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>
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;
.pintura-editor {
height: 600px;
}
<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>
<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>
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
}
}
<pintura-editor
[options]="editorDefaults"
src="image.jpeg"
(process)="handleEditorProcess($event)"
></pintura-editor>
::ng-deep .pintura-editor {
height: 600px;
}
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 {}
<!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.
<!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>
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;
.pintura-editor {
height: 600px;
}
<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>
<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>
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',
},
},
},
});
}
<pintura-editor [options]="editorDefaults" src="image.jpeg"></pintura-editor>
::ng-deep .pintura-editor {
height: 600px;
}
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 {}
<!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
.
<!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>
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;
.pintura-editor {
height: 600px;
}
<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>
<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>
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);
}),
},
});
}
<pintura-editor [options]="editorDefaults" src="image.jpeg"></pintura-editor>
::ng-deep .pintura-editor {
height: 600px;
}
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 {}
<!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>
preprocessImageState
This hook allows us to pre-process the 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".
<!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>
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;
.pintura-editor {
height: 600px;
}
<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>
<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>
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;
},
},
});
}
<pintura-editor [options]="editorDefaults" src="image.jpeg"></pintura-editor>
::ng-deep .pintura-editor {
height: 600px;
}
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 {}
<!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.
<!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>
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;
.pintura-editor {
height: 600px;
}
<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>
<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>
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)
);
}),
},
});
}
<pintura-editor [options]="editorDefaults" src="image.jpeg"></pintura-editor>
::ng-deep .pintura-editor {
height: 600px;
}
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 {}
<!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
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.
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
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 and recovering the redacted information.
Export | Default value | Description |
---|---|---|
scrambleAmount |
|
The amount to scramble the image pixels before blurring. |
blurAmount |
|
The amount of blur to apply to the scrambled image. |
createDefaultImageScrambler({
scrambleAmount: 2,
blurAmount: 6,
});
createDefaultShapePreprocessor
Creates the default shapePreprocessor used for parsing line styles and frame styles.
openEditor({
src: 'my-image.jpeg',
shapePreprocessor: createDefaultShapePreprocessor(),
});
We can add custom shape processors by passing them as an array to createDefaultShapePreprocessor
, see below:
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 |
---|---|
|
Don't render a decorative shape |
|
Render a bar. |
|
Renders an open arrow. |
|
Renders a solid arrow. |
|
Render a open circle. |
|
Renders a solid circle. |
|
Render a open square. |
|
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 |
---|---|
|
Renders a solid border around the crop. |
|
Renders corners in hook of the crop. |
|
Renders a line alongside the edge of the crop. |
|
Renders a separate line alongside each edge of the crop. |
|
Renders 9-slice frames, pass image with frameImage property.
|
|
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 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 |
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.
<!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>
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;
.pintura-editor {
height: 600px;
}
<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>
<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>
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>
::ng-deep .pintura-editor {
height: 600px;
}
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 {}
<!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
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.
// 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
.
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
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.
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
but automatically sets all the defaults like imageReader
, imageWriter
, imageOrienter
and shapePreprocessor
.
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.
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,
});
// 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.
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 |
|
The returned format, either 'canvas' or 'blob'
|
backgroundColor |
|
The color to fill the canvas with, defaults to black. |
foregroundColor |
|
The color to fill the masked area with, defaults to white. Set to undefined or [0, 0, 0, 0] for transparent.
|
forceSquareCanvas |
|
Set to true to force the mask canvas to a square. |
scope |
|
If is mask returns a canvas that fits the mask, else returns mask in image space. |
padding |
|
Padding to apply around mask. |
maxSize |
|
The maximum mask size, defaults to imag size. |
targetSize |
|
The target size of the mask. |
precision |
|
Precision to use when calculating the mask rectangle, a lower value is more precise but slower. |
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
})