ImageDefinition
ImageDefinition
is a specialized CoValue designed specifically for managing images in Jazz applications. It extends beyond basic file storage by supporting a blurry placeholder, built-in resizing, and progressive loading patterns.
Beyond ImageDefinition
, Jazz offers higher-level functions and components that make it easier to use images:
createImage()
- function to create anImageDefinition
from a fileloadImage
,loadImageBySize
,highestResAvailable
- functions to load and display images
Image
- Component to display an image
The Chat example includes an implementation of ImageDefinitions in Svelte.
Creating Images
The easiest way to create and use images in your Jazz application is with the createImage()
function:
The createImage()
function:
- Creates an
ImageDefinition
with the right properties - Generates a small placeholder for immediate display
- Creates multiple resolution variants of your image
- Returns the created
ImageDefinition
Configuration Options
declare function
createImage(
function createImage(image: Blob | File | string, options: { owner?: Group | Account; placeholder?: "blur" | false; maxSize?: number; progressive?: boolean; }): Loaded<typeof ImageDefinition, { original: true; }>
image: string | Blob | File
image: Blob | File | string,options: {
options: { owner?: Group | Account; placeholder?: "blur" | false; maxSize?: number; progressive?: boolean; }
owner?: Group | Account | undefined
owner?:class Group
Group |class Account
Account;placeholder?: false | "blur" | undefined
placeholder?: "blur" | false;maxSize?: number | undefined
maxSize?: number;progressive?: boolean | undefined
progressive?: boolean; }):Loaded< typeof
type Loaded<T extends CoValueClassOrSchema, R extends ResolveQuery<T> = true> = R extends boolean | undefined ? NonNullable<InstanceOfSchemaCoValuesNullable<T>> : [NonNullable<InstanceOfSchemaCoValuesNullable<T>>] extends [...] ? Exclude<...> extends CoValue ? R extends { ...; } ? readonly ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? readonly ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? readonly ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? readonly ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? readonly ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? readonly ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? readonly ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? readonly ((CoValue & ... 1 more ... & (ItemDepth extends boolean ...
ImageDefinition, {
const ImageDefinition: CoMapSchema<{ original: import("/vercel/path0/packages/jazz-tools/dist/tools/internal").FileStreamSchema; originalSize: ZodTuple<[ZodNumber, ZodNumber], null>; placeholderDataURL: ZodOptional<ZodString>; progressive: ZodBoolean; }, FileStreamSchema, Group | Account>
original: true
original: true } >
image
The image to create an ImageDefinition
from.
This can be a Blob
or a File
.
owner
The owner of the ImageDefinition
. This is used to control access to the image. See Groups as permission scopes for more information on how to use groups to control access to images.
placeholder
The placeholder is a base64 encoded image that is displayed while the image is loading. Currently, only "blur"
is a supported.
maxSize
The image generation process includes a maximum size setting that controls the longest side of the image. A built-in resizing feature is applied based on this setting.
progressive
The progressive loading pattern is a technique that allows images to load incrementally, starting with a small version and gradually replacing it with a larger version as it becomes available. This is useful for improving the user experience by showing a placeholder while the image is loading.
Passing progressive: true
to createImage()
will create internal smaller versions of the image for future uses.
Create multiple resized copies
To create multiple resized copies of an original image for better layout control, you can use the createImage
function multiple times with different parameters for each desired size. Here’s an example of how you might implement this:
import {
import co
co } from "jazz-tools"; import {function createImage(imageBlobOrFile: Blob | File, options?: CreateImageOptions): Promise<CreateImageReturnType> (+1 overload)
Creates an ImageDefinition from an image file or blob with built-in UX features. This function creates a specialized CoValue for managing images in Jazz applications. It supports blurry placeholders, built-in resizing, and progressive loading patterns.createImage } from "jazz-tools/media"; // Jazz Schema constProductImage =
const ProductImage: co.Map<{ image: co.Map<{ original: import("/vercel/path0/packages/jazz-tools/dist/tools/internal").FileStreamSchema; originalSize: ZodTuple<[ZodNumber, ZodNumber], null>; placeholderDataURL: ZodOptional<ZodString>; progressive: ZodBoolean; }, co.FileStream, Group | Account>; thumbnail: co.Map<...>; }, unknown, Group | Account>
import co
co.map({
map<{ image: co.Map<{ original: import("/vercel/path0/packages/jazz-tools/dist/tools/internal").FileStreamSchema; originalSize: ZodTuple<[ZodNumber, ZodNumber], null>; placeholderDataURL: ZodOptional<ZodString>; progressive: ZodBoolean; }, co.FileStream, Group | Account>; thumbnail: co.Map<...>; }>(shape: { ...; }): co.Map<...> export map
image:
image: co.Map<{ original: import("/vercel/path0/packages/jazz-tools/dist/tools/internal").FileStreamSchema; originalSize: ZodTuple<[ZodNumber, ZodNumber], null>; placeholderDataURL: ZodOptional<ZodString>; progressive: ZodBoolean; }, co.FileStream, Group | Account>
import co
co.image(),
function image(): co.Image export image
thumbnail:
thumbnail: co.Map<{ original: import("/vercel/path0/packages/jazz-tools/dist/tools/internal").FileStreamSchema; originalSize: ZodTuple<[ZodNumber, ZodNumber], null>; placeholderDataURL: ZodOptional<ZodString>; progressive: ZodBoolean; }, co.FileStream, Group | Account>
import co
co.image(), }); const
function image(): co.Image export image
mainImage = await
const mainImage: CoMapLikeLoaded<{ readonly original: FileStream | null; readonly originalSize: [number, number]; readonly placeholderDataURL: string | undefined; readonly progressive: boolean; } & { ...; } & CoMap, { ...; }, 10, []>
function createImage(imageBlobOrFile: Blob | File, options?: CreateImageOptions): Promise<CreateImageReturnType> (+1 overload)
Creates an ImageDefinition from an image file or blob with built-in UX features. This function creates a specialized CoValue for managing images in Jazz applications. It supports blurry placeholders, built-in resizing, and progressive loading patterns.createImage(const myBlob: Blob
myBlob); constthumbnail = await
const thumbnail: CoMapLikeLoaded<{ readonly original: FileStream | null; readonly originalSize: [number, number]; readonly placeholderDataURL: string | undefined; readonly progressive: boolean; } & { ...; } & CoMap, { ...; }, 10, []>
function createImage(imageBlobOrFile: Blob | File, options?: CreateImageOptions): Promise<CreateImageReturnType> (+1 overload)
Creates an ImageDefinition from an image file or blob with built-in UX features. This function creates a specialized CoValue for managing images in Jazz applications. It supports blurry placeholders, built-in resizing, and progressive loading patterns.createImage(const myBlob: Blob
myBlob, {maxSize?: number | undefined
Maximum size constraint for the image. The image will be resized to fit within this size while maintaining aspect ratio. If the image is smaller than maxSize in both dimensions, no resizing occurs.maxSize: 100, }); // or, in case of migration, you can use the original stored image. constnewThumb = await
const newThumb: CoMapLikeLoaded<{ readonly original: FileStream | null; readonly originalSize: [number, number]; readonly placeholderDataURL: string | undefined; readonly progressive: boolean; } & { ...; } & CoMap, { ...; }, 10, []>
function createImage(imageBlobOrFile: Blob | File, options?: CreateImageOptions): Promise<CreateImageReturnType> (+1 overload)
Creates an ImageDefinition from an image file or blob with built-in UX features. This function creates a specialized CoValue for managing images in Jazz applications. It supports blurry placeholders, built-in resizing, and progressive loading patterns.createImage(mainImage!.
const mainImage: CoMapLikeLoaded<{ readonly original: FileStream | null; readonly originalSize: [number, number]; readonly placeholderDataURL: string | undefined; readonly progressive: boolean; } & { ...; } & CoMap, { ...; }, 10, []>
original: FileStream
original!.toBlob()!, {
FileStream.toBlob(options?: { allowUnfinished?: boolean; }): Blob | undefined
maxSize?: number | undefined
Maximum size constraint for the image. The image will be resized to fit within this size while maintaining aspect ratio. If the image is smaller than maxSize in both dimensions, no resizing occurs.maxSize: 100, }); constimageSet =
const imageSet: { readonly image: { readonly original: FileStream; readonly originalSize: [number, number]; readonly placeholderDataURL: string | undefined; readonly progressive: boolean; } & { ...; } & CoMap; readonly thumbnail: { readonly original: FileStream; readonly originalSize: [number, number]; readonly placeholderDataURL: string | undefined; readonly progressive: boolean; } & ... 1 more ... & CoMap; } & CoMap
ProductImage.
const ProductImage: co.Map<{ image: co.Map<{ original: import("/vercel/path0/packages/jazz-tools/dist/tools/internal").FileStreamSchema; originalSize: ZodTuple<[ZodNumber, ZodNumber], null>; placeholderDataURL: ZodOptional<ZodString>; progressive: ZodBoolean; }, co.FileStream, Group | Account>; thumbnail: co.Map<...>; }, unknown, Group | Account>
create({
CoMapSchema<{ image: CoMapSchema<{ original: import("/vercel/path0/packages/jazz-tools/dist/tools/internal").FileStreamSchema; originalSize: ZodTuple<[ZodNumber, ZodNumber], null>; placeholderDataURL: ZodOptional<ZodString>; progressive: ZodBoolean; }, FileStreamSchema, Group | Account>; thumbnail: CoMapSchema<...>; }, unknown, Group | Account>.create(init: { image: ({ readonly original: FileStream | null; readonly originalSize: [number, number]; readonly placeholderDataURL: string | undefined; readonly progressive: boolean; } & { ...; } & CoMap) | { ...; }; thumbnail: ({ readonly original: FileStream | null; readonly originalSize: [number, number]; readonly placeholderDataURL: string | undefined; readonly progressive: boolean; } & ... 1 more ... & CoMap) | { ...; }; }, options?: { owner?: Group; unique?: CoValueUniqueness["uniqueness"]; } | Group): { ...; } & CoMap (+1 overload)
image:
image: ({ readonly original: FileStream | null; readonly originalSize: [number, number]; readonly placeholderDataURL: string | undefined; readonly progressive: boolean; } & { ...; } & CoMap) | { ...; }
mainImage,
const mainImage: CoMapLikeLoaded<{ readonly original: FileStream | null; readonly originalSize: [number, number]; readonly placeholderDataURL: string | undefined; readonly progressive: boolean; } & { ...; } & CoMap, { ...; }, 10, []>
thumbnail, });
thumbnail: ({ readonly original: FileStream | null; readonly originalSize: [number, number]; readonly placeholderDataURL: string | undefined; readonly progressive: boolean; } & { ...; } & CoMap) | { ...; }
Creating images on the server
We provide a createImage
function to create images from server side using the same options as the browser version, using the package jazz-tools/media/server
. Check the server worker documentation to learn more.
The resize features are based on the sharp
library, then it is requested as peer dependency in order to use it.
import fs from "node:fs"; import { createImage } from "jazz-tools/media/server"; const image = fs.readFileSync(new URL("./image.jpg", import.meta.url)); await createImage(image, { // options });
Displaying Images
To use the stored ImageDefinition, there are two ways: declaratively, using the Image
component, and imperatively, using the static methods.
The Image component is the best way to let Jazz handle the image loading.
<Image>
component
The Image
component handles:
- Showing a placeholder while loading, if generated
- Automatically selecting the appropriate resolution, if generated with progressive loading
- Progressive enhancement as higher resolutions become available, if generated with progressive loading
- Determining the correct width/height attributes to avoid layout shifting
- Cleaning up resources when unmounted
The component's props are:
export type ImageProps = Omit< HTMLImgAttributes, "src" | "srcset" | "width" | "height" > & { imageId: string; width?: number | "original"; height?: number | "original"; };
Width and Height props
The width
and height
props are used to control the best resolution to use but also the width and height attributes of the image tag.
Let's say we have an image with a width of 1920px and a height of 1080px.
<Image imageId="123" /> // Image with the highest resolution available <Image imageId="123" width="original" height="original" /> // Image with width 1920 and height 1080 <Image imageId="123" width="600" /> // Better to avoid, as may be rendered with 0 height <Image imageId="123" width="600" height="original" /> // Keeps the aspect ratio (height: 338) <Image imageId="123" width="original" height="600" /> // As above, aspect ratio is maintained, width is 1067 <Image imageId="123" width="600" height="600" /> // Renders as a 600x600 square
If the image was generated with progressive loading, the width
and height
props will determine the best resolution to use.
Lazy loading
The Image
component supports lazy loading with the [same options as the native browser loading
attribute].(https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/img#loading). It will generate the blob url for the image when the browser's viewport reaches the image.
<Image imageId="123" width="original" height="original" loading="lazy" />
Imperative Usage
Like other CoValues, ImageDefinition
can be used to load the object.
import {
ImageDefinition } from "jazz-tools"; const
type ImageDefinition = { readonly original: FileStream | null; readonly originalSize: [number, number]; readonly placeholderDataURL: string | undefined; readonly progressive: boolean; } & { ...; } & CoMap const ImageDefinition: CoMapSchema<{ original: import("/vercel/path0/packages/jazz-tools/dist/tools/internal").FileStreamSchema; originalSize: ZodTuple<[ZodNumber, ZodNumber], null>; placeholderDataURL: ZodOptional<ZodString>; progressive: ZodBoolean; }, FileStreamSchema, Group | Account>
image = await
const image: CoMapLikeLoaded<{ readonly original: FileStream | null; readonly originalSize: [number, number]; readonly placeholderDataURL: string | undefined; readonly progressive: boolean; } & CoMap, { ...; }, 10, []> | null
ImageDefinition.
const ImageDefinition: CoMapSchema<{ original: import("/vercel/path0/packages/jazz-tools/dist/tools/internal").FileStreamSchema; originalSize: ZodTuple<[ZodNumber, ZodNumber], null>; placeholderDataURL: ZodOptional<ZodString>; progressive: ZodBoolean; }, FileStreamSchema, Group | Account>
load("123", {
CoMapSchema<{ original: import("/vercel/path0/packages/jazz-tools/dist/tools/internal").FileStreamSchema; originalSize: ZodTuple<[ZodNumber, ZodNumber], null>; placeholderDataURL: ZodOptional<ZodString>; progressive: ZodBoolean; }, FileStreamSchema, Group | Account>.load<{ original: true; }>(id: string, options?: { resolve?: RefsToResolve<{ readonly original: FileStream | null; readonly originalSize: [number, number]; readonly placeholderDataURL: string | undefined; readonly progressive: boolean; } & CoMap, 10, []> | undefined; loadAs?: Account | AnonymousJazzAgent; skipRetry?: boolean; unstable_branch?: BranchDefinition; } | undefined): Promise<...>
resolve: {
resolve?: RefsToResolve<{ readonly original: FileStream | null; readonly originalSize: [number, number]; readonly placeholderDataURL: string | undefined; readonly progressive: boolean; } & CoMap, 10, []> | undefined
original?: RefsToResolve<FileStream, 10, [0]> | undefined
original: true, }, }); if(image) {
const image: CoMapLikeLoaded<{ readonly original: FileStream | null; readonly originalSize: [number, number]; readonly placeholderDataURL: string | undefined; readonly progressive: boolean; } & CoMap, { ...; }, 10, []> | null
var console: Console
The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v20.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```console.Console.log(message?: any, ...optionalParams: any[]): void (+2 overloads)
[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)log({originalSize: [number, number]
originalSize:image.
const image: CoMapLikeLoaded<{ readonly original: FileStream | null; readonly originalSize: [number, number]; readonly placeholderDataURL: string | undefined; readonly progressive: boolean; } & CoMap, { ...; }, 10, []>
originalSize: [number, number]
originalSize,placeholderDataUrl: string | undefined
placeholderDataUrl:image.
const image: CoMapLikeLoaded<{ readonly original: FileStream | null; readonly originalSize: [number, number]; readonly placeholderDataURL: string | undefined; readonly progressive: boolean; } & CoMap, { ...; }, 10, []>
placeholderDataURL: string | undefined
placeholderDataURL,original: FileStream
original:image.
const image: CoMapLikeLoaded<{ readonly original: FileStream | null; readonly originalSize: [number, number]; readonly placeholderDataURL: string | undefined; readonly progressive: boolean; } & CoMap, { ...; }, 10, []>
original: FileStream
original, // this FileStream may be not loaded yet }); }
image.original
is a FileStream
and its content can be read as described in the FileStream documentation.
Since FileStream objects are also CoValues, they must be loaded before use. To simplify loading, if you want to load the binary data saved as Original, you can use the loadImage
function.
import {
loadImage } from "jazz-tools/media"; const
function loadImage(imageOrId: ImageDefinition | string): Promise<{ width: number; height: number; image: FileStream; } | null>
image = await
const image: { width: number; height: number; image: FileStream; } | null
loadImage(
function loadImage(imageOrId: ImageDefinition | string): Promise<{ width: number; height: number; image: FileStream; } | null>
const imageDefinitionOrId: string
imageDefinitionOrId); if(image === null) { throw new
const image: { width: number; height: number; image: FileStream; } | null
Error("Image not found"); } const
var Error: ErrorConstructor new (message?: string, options?: ErrorOptions) => Error (+1 overload)
const img: HTMLImageElement
img =var document: Document
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)document.Document.createElement<"img">(tagName: "img", options?: ElementCreationOptions): HTMLImageElement (+2 overloads)
Creates an instance of the element for the specified tag.createElement("img");const img: HTMLImageElement
img.HTMLImageElement.width: number
Sets or retrieves the width of the object. [MDN Reference](https://developer.mozilla.org/docs/Web/API/HTMLImageElement/width)width =image.
const image: { width: number; height: number; image: FileStream; }
width: number
width;const img: HTMLImageElement
img.HTMLImageElement.height: number
Sets or retrieves the height of the object. [MDN Reference](https://developer.mozilla.org/docs/Web/API/HTMLImageElement/height)height =image.
const image: { width: number; height: number; image: FileStream; }
height: number
height;const img: HTMLImageElement
img.HTMLImageElement.src: string
The address or URL of the a media resource that is to be considered. [MDN Reference](https://developer.mozilla.org/docs/Web/API/HTMLImageElement/src)src =
var URL: { new (url: string | URL, base?: string | URL): URL; prototype: URL; canParse(url: string | URL, base?: string | URL): boolean; createObjectURL(obj: Blob | MediaSource): string; parse(url: string | URL, base?: string | URL): URL | null; revokeObjectURL(url: string): void; }
The URL interface represents an object providing static methods used for creating object URLs. [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL) `URL` class is a global reference for `import { URL } from 'node:url'` https://nodejs.org/api/url.html#the-whatwg-url-apiURL.function createObjectURL(obj: Blob | MediaSource): string
[MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/createObjectURL_static)createObjectURL(image.
const image: { width: number; height: number; image: FileStream; }
image: FileStream
image.toBlob()!);
FileStream.toBlob(options?: { allowUnfinished?: boolean; }): Blob | undefined
const img: HTMLImageElement
img.GlobalEventHandlers.onload: ((this: GlobalEventHandlers, ev: Event) => any) | null
Fires immediately after the browser loads the object.onload = () =>
var URL: { new (url: string | URL, base?: string | URL): URL; prototype: URL; canParse(url: string | URL, base?: string | URL): boolean; createObjectURL(obj: Blob | MediaSource): string; parse(url: string | URL, base?: string | URL): URL | null; revokeObjectURL(url: string): void; }
The URL interface represents an object providing static methods used for creating object URLs. [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL) `URL` class is a global reference for `import { URL } from 'node:url'` https://nodejs.org/api/url.html#the-whatwg-url-apiURL.function revokeObjectURL(url: string): void
[MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/revokeObjectURL_static)revokeObjectURL(const img: HTMLImageElement
img.HTMLImageElement.src: string
The address or URL of the a media resource that is to be considered. [MDN Reference](https://developer.mozilla.org/docs/Web/API/HTMLImageElement/src)src);
If the image was generated with progressive loading, and you want to access the best-fit resolution, use loadImageBySize
. It will load the image of the best resolution that fits the wanted width and height.
import {
loadImageBySize } from "jazz-tools/media"; const
function loadImageBySize(imageOrId: ImageDefinition | string, wantedWidth: number, wantedHeight: number): Promise<{ width: number; height: number; image: FileStream; } | null>
image = await
const image: { width: number; height: number; image: FileStream; } | null
loadImageBySize(
function loadImageBySize(imageOrId: ImageDefinition | string, wantedWidth: number, wantedHeight: number): Promise<{ width: number; height: number; image: FileStream; } | null>
const imageDefinitionOrId: string
imageDefinitionOrId, 600, 600); // 600x600 if(image) {
const image: { width: number; height: number; image: FileStream; } | null
var console: Console
The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v20.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```console.Console.log(message?: any, ...optionalParams: any[]): void (+2 overloads)
[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)log({width: number
width:image.
const image: { width: number; height: number; image: FileStream; }
width: number
width,height: number
height:image.
const image: { width: number; height: number; image: FileStream; }
height: number
height,image: FileStream
image:image.
const image: { width: number; height: number; image: FileStream; }
image: FileStream
image, }); }
If want to dynamically listen to the loaded resolution that best fits the wanted width and height, you can use the subscribe
and the highestResAvailable
function.
import { ImageDefinition } from "jazz-tools"; // function highestResAvailable(image: ImageDefinition, wantedWidth: number, wantedHeight: number): FileStream | null import { highestResAvailable } from "jazz-tools/media"; const image = await ImageDefinition.load(imageId); if(image === null) { throw new Error("Image not found"); } const img = document.createElement("img"); img.width = 600; img.height = 600; // start with the placeholder if(image.placeholderDataURL) { img.src = image.placeholderDataURL; } // then listen to the image changes image.$jazz.subscribe({}, (image) => { const bestImage = highestResAvailable(image, 600, 600); if(bestImage) { // bestImage is again a FileStream const blob = bestImage.image.toBlob(); if(blob) { const url = URL.createObjectURL(blob); img.src = url; img.onload = () => URL.revokeObjectURL(url); } } });
Custom image manipulation implementations
To manipulate images (like placeholders, resizing, etc.), createImage()
uses different implementations depending on the environment.
On the browser, image manipulation is done using the canvas
API.
If you want to use a custom implementation, you can use the createImageFactory
function in order create your own createImage
function and use your preferred image manipulation library.
import { createImageFactory } from "jazz-tools/media"; const createImage = createImageFactory({ createFileStreamFromSource: async (source, owner) => { // ... }, getImageSize: async (image) => { // ... }, getPlaceholderBase64: async (image) => { // ... }, resize: async (image, width, height) => { // ... }, });
Best Practices
- Set image sizes when possible to avoid layout shifts
- Use placeholders (like LQIP - Low Quality Image Placeholders) for instant rendering
- Prioritize loading the resolution appropriate for the current viewport
- Consider device pixel ratio (window.devicePixelRatio) for high-DPI displays
- Always call URL.revokeObjectURL after the image loads to prevent memory leaks