> ## Documentation Index
> Fetch the complete documentation index at: https://docs.embededitor.com/llms.txt
> Use this file to discover all available pages before exploring further.

# EditState

> The saved edits onProcess hands back and the state prop takes, field by field, with units and defaults.

`EditState` holds every edit, so the same photo reopens exactly as it was saved, every edit still editable.

```ts theme={"dark"}
onProcess: ({ dest, state }: { dest: File; state: EditState }) => void;
state: EditState | PinturaState | null;
```

## Example

```json state.json theme={"dark"}
{
	"version": 3,
	"crop": { "x": 750, "y": 562.5, "width": 2500, "height": 1875, "aspectRatio": 1.3333333333333333, "scale": 160, "intent": { "x": 750, "y": 562.5, "width": 2500, "height": 1875 } },
	"rotation": -2.5,
	"flipX": true,
	"flipY": false,
	"adjustments": { "blackPoint": 0, "brightness": 0, "brilliance": 0, "contrast": 0, "exposure": 20, "highlights": 0, "saturation": 0, "shadows": 35, "sharpness": 0, "vibrance": 0, "vignette": 0, "warmth": -10 },
	"auto": null,
	"filter": { "id": "VIVID_WARM", "intensity": 80 },
	"frame": { "style": "POLAROID", "color": "#1a1a1a" },
	"obfuscation": [{ "x": 10, "y": 20, "width": 200, "height": 120, "angle": 0, "shape": "ELLIPSE", "style": "PIXELATE", "strength": 60, "color": "#000000" }],
	"annotations": [],
	"annotationList": null,
	"size": { "width": 1080, "height": 810 },
	"marks": { "signature": {}, "watermark": {} }
}
```

## How It Is Written

* **Every field is written**, a default's too: no turn is `0`, no flip `false`, Auto, the filter, the frame and the list are `null` while off, no areas or annotations are `[]`, an area's or an annotation's `angle` is `0` when it has no turn. A default changed in a later version never changes a state saved before it.
* **Any field may be left out** when you write a state yourself. A field left out reads as its default, so a hand-written state can stay short. Only `version` and `crop` are required.
* **In the units the screen shows:** adjustments −100 to 100 (Sharpness 0 to 100), intensity and strength 0 to 100, rotation in degrees.
* **Geometry in working px:** the px of the size the editor works the photo at, `onLoad`'s `size`. That is the photo's own size up to 16.7 MP, and its working copy's past it.
* **Rounded without moving a px:** dragged geometry keeps 6 decimals and the ratio is written whole.

## Storing It

The state is plain JSON. Store it beside the file `onProcess` hands back, and pass it to `state` with the same photo to reopen the edit:

```ts upload.ts theme={"dark"}
import type { EditState } from '@embededitor/full/react';

const upload = async ({ dest, state }: { dest: File; state: EditState }) => {
	const body = new FormData();

	body.append('file', dest);
	body.append('state', JSON.stringify(state));
	await fetch('/api/photos', { body, method: 'POST' });
};
```

A state with another `version`, a value out of range or more than 64 areas is `INVALID_STATE`.

## Fields

**version** `3` *required*

The shape's version. The editor writes and reads `3`. A state with another version is `INVALID_STATE`. A state with no `version` is read as a [Pintura state](https://docs.embededitor.com/saving/pintura.md).

**crop** `object` *required*

The crop, in working px, and its ratio.

**properties**

**x** `number`

The left edge.

**y** `number`

The top edge.

**width** `number`

The width, above 0.

**height** `number`

The height, above 0.

**aspectRatio** `number | null`

The ratio, width / height. `null` while free.

**scale** `number`

The Scale of the user's crop (`intent`), in %: 100 is the photo's largest window of the crop's ratio. Written for you to read; the editor reopens from `intent`.

**intent** `\{ x: number; y: number; width: number; height: number \}`

The user's crop: the window they chose, unrounded, which no angle changes. The crop is what the photo turned by `rotation` holds of it, so straightening back to 0° gives it back. Left out, the crop is taken as the user's crop; one that no longer gives `crop` at `rotation` (you changed either) is ignored the same way.

**rotation** `number`

The turn, in degrees: its quarter turn kept within −180° to 180°, the straightening on top of it, so four turns write none. Left out, `0`.

**flipX** `boolean`

Mirrored left to right. Left out, `false`.

**flipY** `boolean`

Mirrored top to bottom. Left out, `false`.

**adjustments** `object`

The adjustments set by hand, each −100 to 100 (`sharpness` 0 to 100). One left out is at `0`.

**properties**

**exposure** `number`

**brilliance** `number`

**highlights** `number`

**shadows** `number`

**contrast** `number`

**brightness** `number`

**blackPoint** `number`

**saturation** `number`

**vibrance** `number`

**warmth** `number`

**sharpness** `number`

**vignette** `number`

**auto** `object | null`

Auto while it is on, `null` while off. It keeps the numbers the photo's analysis gave, so a reopened photo draws from them without analyzing it again, and a later change to Auto never changes a saved edit.

**properties**

**amount** `number`

Its ruler, −100 to 100.

**origin** `number`

The photo's default amount, where Auto turns on, above 0 and up to 100.

**black** `number`

Levels' black point, 0 to 1.

**white** `number`

Levels' white point, 0 to 1.

**median** `number`

The photo's middle, 0 to 1, between `black` and `white`.

**midtone** `number`

Where the middle goes, above 0 and up to 1.

**shadows** `number`

The fill light, 0 to 1.

**contrast** `number`

The S-curve's strength, 0 to 1.

**color** `number`

The color gain, above 0.

**filter** `object | null`

The filter and its intensity. `null`: none.

**properties**

**id** `string`

`VIVID`, `VIVID_WARM`, `VIVID_COOL`, `DRAMATIC`, `DRAMATIC_WARM`, `DRAMATIC_COOL`, `MONO`, `SILVERTONE` or `NOIR`.

**intensity** `number`

0 to 100.

**frame** `object | null`

The frame and its color. `null`: none.

**properties**

**style** `string`

`MAT_SHARP`, `MAT_ROUND`, `LINE_SINGLE`, `LINE_MULTIPLE`, `EDGE_CROSS`, `EDGE_SEPARATE`, `EDGE_OVERLAP`, `CORNER_HOOKS`, `POLAROID`, `FILM`, `ROUND_CORNERS`, `GALLERY` or `PHOTO_CORNERS`.

**color** `string`

`#rrggbb`, always written (a white frame writes `#ffffff`). Left out, white.

**obfuscation** `object[]`

The obfuscated areas, in working px. At most 64, as many as the Obfuscate tool draws. An area may reach past the photo's edge: only the part over the photo is drawn.

**properties**

**x, y, width, height** `number`

Its rect, in its own frame.

**angle** `number`

Its rect's turn about its middle on the photo, in degrees, 2 decimals, in the sense `rotation` turns the photo. An area is born level on the screen (the photo's turn and flips undone), then turns with the photo, and its rotate handle turns it. Left out, `0`.

**shape** `string`

`RECT`, `ROUNDED` or `ELLIPSE`. Left out, `RECT`.

**style** `string`

`BLUR`, `PIXELATE` or `SOLID`. Left out, `BLUR`.

**strength** `number`

0 to 100. Left out, `50`.

**color** `string`

A solid area's color, `#rrggbb` (any `#rgb` or `#rrggbb` reads, saved as six lowercase digits). Left out, black.

**annotations** `object[]`

The annotations: lines, rulers, texts and Numbers, shapes and lenses, in drawing order, a later one on top. Their points are in the same px as the crop. See [Annotation fields](https://docs.embededitor.com/api-reference/annotations.md).

**annotationList** `object | null`

The Numbers' list, one block. `null`: no list. See [Annotation fields](https://docs.embededitor.com/api-reference/annotations.md#the-list).

**size** `\{ width: number; height: number \} | null`

The output size, in output px. `null` while none is set: the crop draws at its own size. The output never passes 16.7 MP.

**marks** `object`

What the user changed of the host's watermark and signature, never the image nor the host's text. The editor writes both roles, each empty when nothing changed. A field a role leaves out is the host's. A saved change for a mark the host no longer gives is kept and ignored.

**properties**

**watermark** `object`

The watermark's changes.

**properties**

**size, angle, spacing** `number`

The layout's it shows in.

**opacity** `number`

10 to 100.

**color** `'AUTO' | string`

The color the user chose over the host's: `'AUTO'` or a lowercase hex. Back on the host's own, it goes.

**font** `string`

The font the user chose for a text mark over the host's, by its slug (`'pacifico'`). Back on the host's own, it goes.

**text** `string`

The text the user wrote.

**hidden** `true`

A free mark the user took out.

**layout** `'GRID' | 'SINGLE'`

The layout the user switched to. Left out while it is the host's.

**grid** `\{ angle?, size?, spacing? \}`

What the user gave the grid, kept while the mark shows single.

**single** `\{ angle?, size? \}`

What the user gave the single mark, kept while it shows as a grid.

**signature** `object`

The signature's changes.

**properties**

**size, margin, opacity** `number`

As the user set them.

**color** `'AUTO' | string`

As the watermark's.

**font** `string`

As the watermark's.

**text** `string`

The text the user wrote.

**hidden** `true`

A free mark the user took out.

**position** `string`

One of the 9 points: `TOP_LEFT`, `TOP`, `TOP_RIGHT`, `LEFT`, `CENTER`, `RIGHT`, `BOTTOM_LEFT`, `BOTTOM` or `BOTTOM_RIGHT`.

**x, y** `number`

A free place instead of `position`: its center, 0 to 1 on the final photo. Never both.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.