Skip to content

optiq-image / index

index ​

optiq-image — compress images in a Web Worker and get the smallest output that meets a lossless or perceptual (SSIM) constraint. Start with compressImage.

Classes ​

OptiqError ​

Extends ​

  • Error

Constructors ​

Constructor ​
ts
new OptiqError(
   code, 
   message, 
   details?
): OptiqError;
Parameters ​
ParameterType
codeOptiqErrorCode
messagestring
details?Record<string, unknown>
Returns ​

OptiqError

Overrides ​

Error.constructor

Properties ​

code ​
ts
readonly code: OptiqErrorCode;
details? ​
ts
readonly details?: Record<string, unknown>;

Interfaces ​

CandidateReport ​

Properties ​

PropertyTypeDescription
bytesnumber-
codecstring-
durationMsnumber-
format"jpeg" | "png" | "webp" | "avif" | "gif" | "heif" | "svg"-
note?string-
passedbooleanSatisfies the quality constraint (and is exact, for lossless).
proxy?booleanEncoded from the tile mosaic used for quality search on large images; never selected as output.
quality?numberSSIM for perceptual candidates, 1 for verified-exact candidates. Undefined if not evaluated.
qualityMetric?QualityMetricName-
settingsRecord<string, number | boolean | string>-

CompressCallOptions ​

Extends ​

Properties ​

PropertyTypeDescriptionInherited from
allowFormatConversion?booleanDefault true when targetFormat is auto. When false, the output keeps the input format.OptiqOptions.allowFormatConversion
allowLossyResize?booleanExplicitly permit resizing in lossless mode (the result is then no longer pixel-identical to the input).OptiqOptions.allowLossyResize
autoFormats?OutputFormat[]Formats considered when targetFormat is auto. Default: jpeg, png, webp, avif. Remove avif if your audience includes browsers without AVIF decoding or encode time matters most.OptiqOptions.autoFormats
markOutput?booleanMark lossy JPEG/WebP outputs with a small comment/chunk (~20 bytes) so a later run recognises them and does not re-encode them again (each lossy pass is checked against its own input, so repeated passes compound the loss). Default false in the library; the CLI enables it. AVIF and lossless outputs are not marked.OptiqOptions.markOutput
maxCandidates?numberMaximum number of encodes (candidates) per image. Defaults: visually-lossless 18, balanced 10, lossless 4.OptiqOptions.maxCandidates
maxInputBytes?numberReject inputs larger than this many bytes before reading them. Default 100 MiB.OptiqOptions.maxInputBytes
maxInputPixels?numberReject inputs whose header declares more pixels than this (decompression-bomb guard). Default 50 MP.OptiqOptions.maxInputPixels
maxOutputBytes?numberUpper bound for output size. Not a promise: reported in unmetConstraints if impossible.OptiqOptions.maxOutputBytes
maxWidthOrHeight?numberDownscale so that the longest side is at most this. Never applied in lossless mode unless allowLossyResize.OptiqOptions.maxWidthOrHeight
minQuality?numberMinimum SSIM (0..1) for perceptual modes. Defaults: visually-lossless 0.99, balanced 0.975. Ignored in lossless mode.OptiqOptions.minQuality
minSavingsRatio?numberReturn the original when the best candidate saves less than this fraction. Default 0.02.OptiqOptions.minSavingsRatio
mode?CompressionModeDefault balanced.OptiqOptions.mode
onProgress?(event) => void--
onUnmetConstraints?"best-effort" | "throw"What to do when no candidate meets all constraints. Default best-effort (result lists unmetConstraints).OptiqOptions.onUnmetConstraints
preserveAnimation?booleanDefault true. When false, animated inputs may be flattened to their first frame (with a warning).OptiqOptions.preserveAnimation
preserveMetadata?booleanKeep EXIF/XMP and non-sRGB/sRGB ICC profiles. Default true. Setting false strips them (privacy: removes GPS etc).OptiqOptions.preserveMetadata
reoptimize?booleanRe-encode inputs that carry the Optiq marker anyway. Default false: in perceptual modes a marked input is only optimised at container level (metadata), unless it is resized or converted to an explicitly requested format.OptiqOptions.reoptimize
searchStrategy?SearchStrategybinary (default) searches quality per codec; fixed encodes each codec once at a preset quality.OptiqOptions.searchStrategy
signal?AbortSignal--
targetFormat?TargetFormatDefault auto.OptiqOptions.targetFormat

CompressionResult ​

Properties ​

PropertyTypeDescription
blobBlob-
candidatesCandidateReport[]-
category?ImageCategory-
codec?string-
constraintsMetboolean-
durationMsnumber-
fallbacksstring[]Codec/runtime fallbacks used (e.g. canvas encoder instead of WASM). Empty when none.
fileNamestringSuggested file name with the extension matching outputFormat.
height?number-
metadataMetadataReport-
mimeTypestring-
modeCompressionMode-
originalBytesnumber-
originalFormatDetectedFormat-
originalHeight?number-
originalWidth?number-
outputBytesnumber-
outputFormat"jpeg" | "png" | "webp" | "avif" | "gif" | "heif" | "svg"-
qualityMetric?numberQuality of the chosen output vs. the reference (input, or resized input).
qualityMetricName?QualityMetricName-
settings?Record<string, string | number | boolean>-
sizeReductionRationumber1 - outputBytes/originalBytes (negative if larger).
unmetConstraintsUnmetConstraint[]-
usedOriginalbooleanTrue when blob is the unmodified input.
warningsstring[]-
width?numberDimensions of the output as displayed (after orientation).

Compressor ​

Methods ​

compress() ​
ts
compress(input, options?): Promise<CompressionResult>;
Parameters ​
ParameterType
inputBlob
options?CompressCallOptions
Returns ​

Promise<CompressionResult>

terminate() ​
ts
terminate(): void;

Terminate all workers and reject queued/running jobs.

Returns ​

void


CompressorConfig ​

Properties ​

PropertyTypeDescription
allowMainThread?booleanRun on the main thread when Workers are unavailable. Default false (throws UNSUPPORTED_ENVIRONMENT): this blocks the UI.
codecFallback?CodecFallbackPolicyCodec fallback when a WASM codec cannot load: canvas (default) uses the browser's own encoders via OffscreenCanvas and reports it in result.fallbacks; none fails with an error instead.
idleTimeoutMs?numberTerminate workers idle for this long. Default 30 s.
maxWorkers?numberConcurrent jobs (= worker count). Default: min(2, max(1, hardwareConcurrency - 1)). Each job holds a few copies of the decoded image.
recycleAfterPixels?numberTerminate the worker after a job whose image had more pixels than this. WebAssembly memory never shrinks, so this is how the codec heaps grown by a large image are returned to the system. Default 8 MP.
workerFactory?() => WorkerCustom worker construction (e.g. a bundler-specific ?worker import, or a CDN URL).

MetadataReport ​

Properties ​

PropertyTypeDescription
exif"kept" | "removed" | "none" | "unsupported-in-output"-
iccProfile"kept" | "none" | "dropped-srgb"-
orientation"kept" | "none" | "baked"baked: pixels were rotated/flipped and the orientation tag reset to 1.
xmp"kept" | "removed" | "none" | "unsupported-in-output"-

OptiqOptions ​

Extended by ​

Properties ​

PropertyTypeDescription
allowFormatConversion?booleanDefault true when targetFormat is auto. When false, the output keeps the input format.
allowLossyResize?booleanExplicitly permit resizing in lossless mode (the result is then no longer pixel-identical to the input).
autoFormats?OutputFormat[]Formats considered when targetFormat is auto. Default: jpeg, png, webp, avif. Remove avif if your audience includes browsers without AVIF decoding or encode time matters most.
markOutput?booleanMark lossy JPEG/WebP outputs with a small comment/chunk (~20 bytes) so a later run recognises them and does not re-encode them again (each lossy pass is checked against its own input, so repeated passes compound the loss). Default false in the library; the CLI enables it. AVIF and lossless outputs are not marked.
maxCandidates?numberMaximum number of encodes (candidates) per image. Defaults: visually-lossless 18, balanced 10, lossless 4.
maxInputBytes?numberReject inputs larger than this many bytes before reading them. Default 100 MiB.
maxInputPixels?numberReject inputs whose header declares more pixels than this (decompression-bomb guard). Default 50 MP.
maxOutputBytes?numberUpper bound for output size. Not a promise: reported in unmetConstraints if impossible.
maxWidthOrHeight?numberDownscale so that the longest side is at most this. Never applied in lossless mode unless allowLossyResize.
minQuality?numberMinimum SSIM (0..1) for perceptual modes. Defaults: visually-lossless 0.99, balanced 0.975. Ignored in lossless mode.
minSavingsRatio?numberReturn the original when the best candidate saves less than this fraction. Default 0.02.
mode?CompressionModeDefault balanced.
onUnmetConstraints?"best-effort" | "throw"What to do when no candidate meets all constraints. Default best-effort (result lists unmetConstraints).
preserveAnimation?booleanDefault true. When false, animated inputs may be flattened to their first frame (with a warning).
preserveMetadata?booleanKeep EXIF/XMP and non-sRGB/sRGB ICC profiles. Default true. Setting false strips them (privacy: removes GPS etc).
reoptimize?booleanRe-encode inputs that carry the Optiq marker anyway. Default false: in perceptual modes a marked input is only optimised at container level (metadata), unless it is resized or converted to an explicitly requested format.
searchStrategy?SearchStrategybinary (default) searches quality per codec; fixed encodes each codec once at a preset quality.
targetFormat?TargetFormatDefault auto.

ProgressEvent ​

Properties ​

PropertyTypeDescription
bestBytes?numberSmallest valid candidate so far, in bytes.
candidateBudgetnumber-
candidatesTriednumberEncodes done so far / allowed budget.
progressnumberRough overall progress 0..1.
stageProgressStage-

Type Aliases ​

CodecFallbackPolicy ​

ts
type CodecFallbackPolicy = "canvas" | "none";

CompressionMode ​

ts
type CompressionMode = "lossless" | "visually-lossless" | "balanced" | "fast";
  • lossless: decoded pixels (incl. alpha) of the output are verified to be identical to the input.
  • visually-lossless: decoded pixels may differ; the perceptual difference (SSIM) is kept above a strict threshold.
  • balanced: lower SSIM threshold and smaller search budget; trades some quality for size and speed.
  • fast: same threshold as balanced, but no AVIF, no oxipng and at most 5 encodes; for phones and batches.

DecodableFormat ​

ts
type DecodableFormat = "jpeg" | "png" | "webp" | "avif" | "gif";

Formats that can be decoded to pixels and re-encoded.


DetectedFormat ​

ts
type DetectedFormat = "jpeg" | "png" | "webp" | "avif" | "gif" | "heif" | "svg";

Formats Optiq can recognise from magic bytes. Recognition is not the same as support.


ImageCategory ​

ts
type ImageCategory = 
  | "photo"
  | "screenshot"
  | "text-graphic"
  | "illustration"
  | "transparent-illustration"
  | "gradient";

OptiqErrorCode ​

ts
type OptiqErrorCode = 
  | "INVALID_INPUT"
  | "UNSUPPORTED_FORMAT"
  | "MALFORMED_INPUT"
  | "INPUT_TOO_LARGE"
  | "INVALID_OPTIONS"
  | "INCOMPATIBLE_OPTIONS"
  | "CONSTRAINTS_UNSATISFIABLE"
  | "CODEC_UNAVAILABLE"
  | "UNSUPPORTED_ENVIRONMENT"
  | "WORKER_ERROR"
  | "ABORTED";

OutputFormat ​

ts
type OutputFormat = "jpeg" | "png" | "webp" | "avif";

Formats Optiq can encode.


ProgressStage ​

ts
type ProgressStage = 
  | "reading"
  | "probing"
  | "decoding"
  | "analyzing"
  | "resizing"
  | "encoding"
  | "finalizing"
  | "done";

QualityMetricName ​

ts
type QualityMetricName = "exact" | "ssim";

SearchStrategy ​

ts
type SearchStrategy = "binary" | "fixed";

TargetFormat ​

ts
type TargetFormat = "auto" | "original" | OutputFormat;

UnmetConstraint ​

ts
type UnmetConstraint = 
  | {
  actual: number;
  constraint: "maxOutputBytes";
  limit: number;
}
  | {
  actual: number;
  constraint: "minQuality";
  limit: number;
}
  | {
  constraint: "targetFormat";
  reason: string;
  requested: string;
};

Functions ​

compressImage() ​

ts
function compressImage(input, options?): Promise<CompressionResult>;

Compress an image in a background Web Worker using a shared compressor. Rejects with OptiqError (code), or an AbortError (code ABORTED) when signal aborts.

Parameters ​

ParameterType
inputBlob | File
options?CompressCallOptions

Returns ​

Promise<CompressionResult>


createCompressor() ​

ts
function createCompressor(config?): Compressor;

Parameters ​

ParameterType
config?CompressorConfig

Returns ​

Compressor


fileNameFor() ​

ts
function fileNameFor(name, format): string;

Replace the extension of name with the one matching format.

Parameters ​

ParameterType
namestring | undefined
format"jpeg" | "png" | "webp" | "avif" | "gif" | "heif" | "svg"

Returns ​

string


isOptiqError() ​

ts
function isOptiqError(e): e is OptiqError;

Parameters ​

ParameterType
eunknown

Returns ​

e is OptiqError


sniffFormat() ​

ts
function sniffFormat(b): DetectedFormat | undefined;

Identify the format from content only. Extensions and MIME types are never consulted.

Parameters ​

ParameterType
bUint8Array

Returns ​

DetectedFormat | undefined


toFile() ​

ts
function toFile(result, lastModified?): File;

Wrap a result as a File with a name, type and extension that match the encoded bytes.

Parameters ​

ParameterType
resultCompressionResult
lastModified?number

Returns ​

File