# How Convert Enables Cross-Medium File Conversion: Image to PDF and Beyond

> Discover how Convert handles cross-medium file conversions like image to PDF using its plugin architecture and format handlers for seamless transformations.

- Repository: [p2r3/convert](https://github.com/p2r3/convert)
- Tags: how-to-guide
- Published: 2026-02-19

---

**Convert supports cross-medium file conversions through a plugin-style architecture where format handlers expose supported formats and a global traversal graph discovers conversion routes, enabling direct image-to-PDF transformation via the ImageMagick handler.**

The `p2r3/convert` repository solves the challenge of transforming files across different media types—such as converting raster images to PDF documents—without requiring users to install multiple standalone tools. By abstracting format capabilities behind a unified handler interface and routing conversions through a directed graph, the system can chain operations or execute direct transformations when supported.

## The Handler Architecture: FormatHandler Interface and Supported Formats

At the core of cross-medium conversion lies the `FormatHandler` interface. Each handler implements this contract to advertise which formats it can read and write through a `supportedFormats` array of `FileFormat` objects.

### How ImageMagick Exposes PDF Writing Capabilities

The `ImageMagickHandler` in [`src/handlers/ImageMagick.ts`](https://github.com/p2r3/convert/blob/main/src/handlers/ImageMagick.ts) dynamically builds its format list by querying the ImageMagick-WASM library. It iterates over `Magick.supportedFormats` to create entries for every image type the library can process.

Crucially, the handler sets the `to` property to `true` for PDFs, indicating it can write PDF files, while setting `from` to `false` to indicate it does not read PDFs:

```typescript
// src/handlers/ImageMagick.ts – building the format list
Magick.supportedFormats.forEach(format => {
  const mimeType = format.mimeType || mime.getType(formatName);
  this.supportedFormats.push({
    name: format.description,
    format: formatName === "jpg" ? "jpeg" : formatName,
    extension: formatName,
    mime: normalizeMimeType(mimeType),
    from: mimeType === "application/pdf" ? false : format.supportsReading,
    to: format.supportsWriting,               // ← true for PDF
    internal: format.format,
    category: mimeType.split("/")[0],
    lossless: ["png","bmp","tiff"].includes(formatName)
  });
});

```

This configuration allows any image format that ImageMagick supports—such as PNG, JPEG, or WebP—to be converted directly into a PDF document.

## Building the Conversion Graph with TraversionGraph

Cross-medium conversion routing is handled by the `TraversionGraph` class in [`src/TraversionGraph.ts`](https://github.com/p2r3/convert/blob/main/src/TraversionGraph.ts). During initialization in [`src/main.ts`](https://github.com/p2r3/convert/blob/main/src/main.ts), the system loads each handler, executes `handler.init()`, caches the supported formats, and registers them in the graph.

The graph treats each `FileFormat` as a node and creates directed edges for every format where the `to` property is enabled. When a user selects an input format (e.g., PNG) and an output format (e.g., PDF), the `tryConvertByTraversing` function queries the graph for the shortest path. Because ImageMagick advertises a direct edge from PNG to PDF, the path consists of a single step:

```typescript
// src/main.ts – building the option list & initializing the graph
window.traversionGraph.init(window.supportedFormatCache, handlers);

```

## Executing Cross-Medium Conversions

Once the graph identifies a valid conversion route, the `attemptConvertPath` function traverses the path step-by-step. For each segment, it invokes the handler's `doConvert` method with the current file bytes and the target `FileFormat`.

### Image to PDF Conversion Flow

The `ImageMagickHandler.doConvert` method in [`src/handlers/ImageMagick.ts`](https://github.com/p2r3/convert/blob/main/src/handlers/ImageMagick.ts) executes the actual transformation. It reads the input image using Magick's read settings, then writes the output collection to the requested format (PDF):

```typescript
// src/handlers/ImageMagick.ts – conversion core
const inputSettings = new MagickReadSettings();
inputSettings.format = inputMagickFormat;
// …read input, push to collection…
outputCollection.write(outputMagickFormat, bytes => resolve(new Uint8Array(bytes)));

```

### Reverse Direction: PDF to Image

While ImageMagick handles image-to-PDF conversion, the reverse operation—extracting images from PDF files—is handled by a dedicated `pdftoimg` handler in [`src/handlers/pdftoimg.ts`](https://github.com/p2r3/convert/blob/main/src/handlers/pdftoimg.ts). This separation of concerns allows each handler to specialize in specific media transformations while the graph coordinates complex multi-step conversions when necessary.

## Programmatic Usage Example

You can trigger cross-medium conversions programmatically using the exported `tryConvertByTraversing` function:

```typescript
import { tryConvertByTraversing } from "./main.ts";
import CommonFormats from "./CommonFormats.ts";

/* Prepare a single PNG file */
const pngBytes = await fetch("example.png").then(r => r.arrayBuffer());
const inputFile = { name: "example.png", bytes: new Uint8Array(pngBytes) };

/* Define the source and target formats */
const from = {
  handler: null!,                                 // will be filled by graph
  format: CommonFormats.PNG.builder("png")        // PNG source
};
const to = {
  handler: null!,
  format: CommonFormats.PDF.builder("pdf")        // PDF target
};

/* Perform the conversion */
const result = await tryConvertByTraversing([inputFile], from, to);

if (result) {
  const pdf = result.files[0];
  // e.g., create a blob URL to download
  const url = URL.createObjectURL(new Blob([pdf.bytes], { type: pdf.mime }));
  console.log("PDF generated:", url);
}

```

Behind the scenes, the graph resolves `from.handler` and `to.handler` (ImageMagick for both), then runs `ImageMagickHandler.doConvert` to produce the PDF.

## Summary

- **Convert** uses a modular handler architecture where each handler implements the `FormatHandler` interface and advertises capabilities via `supportedFormats`.
- **ImageMagickHandler** in [`src/handlers/ImageMagick.ts`](https://github.com/p2r3/convert/blob/main/src/handlers/ImageMagick.ts) enables image-to-PDF conversion by setting `to: true` for PDF formats while leveraging the ImageMagick-WASM library for actual byte transformation.
- **TraversionGraph** in [`src/TraversionGraph.ts`](https://github.com/p2r3/convert/blob/main/src/TraversionGraph.ts) constructs a directed graph of format nodes and edges, enabling automatic route discovery for cross-medium conversions.
- The system supports reverse conversions (PDF to image) through specialized handlers like `pdftoimg`, allowing bidirectional cross-medium transformations.

## Frequently Asked Questions

### How does Convert handle formats that require intermediate conversion steps?

When no direct edge exists between the input and output formats, the `TraversionGraph` searches for the shortest path through intermediate nodes. For example, if converting from an obscure image format to a document format required an intermediate step, the graph would route through the necessary handlers automatically, chaining multiple `doConvert` calls in [`src/main.ts`](https://github.com/p2r3/convert/blob/main/src/main.ts) until the final format is reached.

### Can Convert preserve image quality when converting to PDF?

Yes, the `ImageMagickHandler` preserves the original image data during conversion. In [`src/handlers/ImageMagick.ts`](https://github.com/p2r3/convert/blob/main/src/handlers/ImageMagick.ts), the handler reads the source image using `MagickReadSettings` and writes it directly to PDF format without re-encoding or compression unless specified. The `lossless` property in the `FileFormat` object also indicates which formats (like PNG, BMP, and TIFF) maintain lossless quality throughout the conversion chain.

### What is the difference between the ImageMagick and pdftoimg handlers?

The **ImageMagick** handler in [`src/handlers/ImageMagick.ts`](https://github.com/p2r3/convert/blob/main/src/handlers/ImageMagick.ts) specializes in raster image processing and can write PDF files, making it responsible for **image-to-PDF** conversions. Conversely, the **pdftoimg** handler in [`src/handlers/pdftoimg.ts`](https://github.com/p2r3/convert/blob/main/src/handlers/pdftoimg.ts) specifically extracts raster images from PDF documents, handling the **PDF-to-image** direction. This separation allows each handler to optimize for its specific media transformation while the `TraversionGraph` coordinates complex workflows that might require both.

### Is it possible to convert multiple images into a single PDF document?

According to the source code in [`src/handlers/ImageMagick.ts`](https://github.com/p2r3/convert/blob/main/src/handlers/ImageMagick.ts), the `doConvert` method processes collections of images using ImageMagick's `MagickImageCollection`. When multiple input files are provided, the handler can write them as a multi-page PDF document, with each image becoming a separate page in the output file.