# Image

A picture at a declared size, from its own bytes or from a source, kept together as one pagination unit.

Canonical URL: https://docs.asterdoc.com/components/image/

`Image` places a picture in a document at a size you declare. Give it `bytes`
and the picture travels inside the tree; give it `src` and the render loads it
from there.

## Preview


```tsx
import { Image } from "@/components/asterdoc/image";
import { sitePhotoBytes } from "@/examples/sample-image";

export function ImageDemo() {
  return (
    <Image bytes={sitePhotoBytes} width={160} height={160} alt="Harbor yard" keepId="site-photo" />
  );
}
```


## Installation


```bash
npx shadcn@4 add @asterdoc/image
```


```bash
asterdoc add image
```


Installs to components/asterdoc/image.tsx.


## Usage


```tsx
import { Image } from "@/components/asterdoc/image";

<Image bytes={sitePhotoBytes} width={160} height={160} alt="Harbor yard" keepId="site-photo" />
```

| Prop | Type | Optional | Default | Description |
| --- | --- | --- | --- | --- |
| `src` | `string` | Yes |  | Where the render loads the picture from: the key the PDF path supplies its
bytes under, or a URL a browser preview can load. Ignored when `bytes` is
given. |
| `bytes` | `Uint8Array` | Yes |  | The picture's own bytes, embedded after the encoding is sniffed. Wins over `src`. |
| `width` | `number` | No |  | Rendered width in CSS pixels. |
| `height` | `number` | No |  | Rendered height in CSS pixels. |
| `alt` | `string` | Yes | "" | Accessible description. Leave it empty for a decorative mark the text
beside it already names. |
| `keepId` | `string` | No |  | Stable id the page plan tracks this image by; must be unique within the document. |
| `className` | `string` | Yes |  | Application-owned classes on the image. |


## Composition

**Bytes win over a source.** `bytes` are sniffed for their encoding —
PNG, JPEG, GIF, WebP or SVG — and embedded as a `data:` URI, so neither the
preview nor the PDF engine fetches anything. Bytes the engine cannot decode
fail with `UndecodableImageError` naming the image, before any bytes are
written. An image with neither fails with `MissingImageSourceError`.

A `src` string is passed through untouched, because it is a key rather than a
URL: the PDF path is handed its images as `{ src, data }` pairs and matches
them by that string, while a browser preview loads whatever the string
resolves to. The two agree on the key, not on a URL. `asterdoc check` reports
every `src` that is not a `data:` URI, because a render needs bytes behind each
one.

**The size is declared, not measured.** Neither output reads an image's
intrinsic size while it lays the page out, so an image with no `width` and
`height` would take a different amount of the page in each one and the page
plan the two share would stop agreeing.

`Image` is its own pagination unit, so it is never split across a page break,
and `keepId` is the id the page plan tracks it by. It must be unique in the
document: an image names no path and no party, so unlike `Field` or `Signature`
there is nothing to derive one from.

## Variants

### From a source

`src` names where the picture is loaded from instead of carrying it as bytes.


```tsx
import { Image } from "@/components/asterdoc/image";
import { sitePhotoDataUri } from "@/examples/sample-image";

export function ImageVariantSource() {
  return (
    <Image src={sitePhotoDataUri} width={96} height={96} alt="Harbor yard" keepId="site-photo-source" />
  );
}
```


### Attachment field

An attachment is not a field value: the artifact declares annex slots and the
filled data carries one `Attachment` per slot. `Field` with `as="image"` draws
the attachment at `annexes.<slot>` at the declared size, taking its heading
from the slot's own title. Its `src` is where a browser preview loads the
picture from; the default is the attachment's own file name, which is the key
the PDF path supplies its bytes under, and which `asterdoc check` reports as a
missing image until a render supplies them. `width` and `height` are required
whatever the slot holds — omitting either throws `MissingImageSizeError`, so a
composition cannot pass a check on a sample with nothing attached and then fail
on the day a real photograph arrives.


```tsx
import { Document } from "@/components/asterdoc/document";
import { Field } from "@/components/asterdoc/field";
import { proposalForm } from "@/examples/proposal";
import { shortProposalData } from "@/examples/proposal-data";
import { sitePhotoDataUri } from "@/examples/sample-image";

export function ImageVariantAttachmentField() {
  return (
    <Document artifact={proposalForm} data={shortProposalData} id="image-variant-attachment-field">
      <Field path="annexes.sitePhoto" as="image" width={160} height={160} src={sitePhotoDataUri} />
    </Document>
  );
}
```


### Attachment that is not a picture

The same `Field` prints the attachment's file name when its MIME type is not
an image, and `asterdoc check` reports the mismatch as `image:<path>`. Nothing
is drawn and nothing throws: the document still says truthfully what is
attached.


```tsx
import { Document } from "@/components/asterdoc/document";
import { Field } from "@/components/asterdoc/field";
import { proposalForm } from "@/examples/proposal";
import { shortProposalData } from "@/examples/proposal-data";

export function ImageVariantAttachmentName() {
  return (
    <Document artifact={proposalForm} data={shortProposalData} id="image-variant-attachment-name">
      <Field path="annexes.surveyReport" as="image" width={160} height={160} />
    </Document>
  );
}
```
