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

# Image Manipulation API

> Learn how to manipulate images using Canvacord's image manipulation api.

<Note>This page is still a work in progress.</Note>

Canvacord's image manipulation API works by allowing you to define how image should be processed by using a schema object. The schema object is a JavaScript object that defines the image manipulation process. This schema can generate both static as well as animated images.

## Example

Check out [Stewie Griffin](/examples/image-manipulation/stewie-griffin) example to see how you can create your own image manipulation function.

### Usage

<CodeGroup>
  ```ts TypeScript theme={null}
  import {
    createTemplate,
    ImageFactory,
    TemplateImage,
    createImageGenerator,
    type ImageSource,
  } from "canvacord";

  const Manipulator = createTemplate((image: ImageSource) => {
    return {
      steps: [
        // base image
        {
          // one step can take multiple images
          image: [
            {
              source: new TemplateImage(ImageFactory.AFFECT), // source image
              x: 0, // x position
              y: 0, // y position
            },
          ],
        },
        // target image
        {
          image: [
            {
              source: new TemplateImage(image), // target image
              x: 180, // x position
              y: 383, // y position
              width: 200, // width
              height: 157, // height
            },
          ],
        },
      ],
    };
  });

  // get target photo to use on "affected" meme image
  const photo = await getPhotoForMemeSomehow();
  const generator = createImageGenerator(Manipulator(photo));

  // render out the image
  await generator.render();

  // get the resulting image in png format
  const affectedMeme = await generator.encode("png");
  ```

  ```js ES Modules theme={null}
  import {
    createTemplate,
    ImageFactory,
    TemplateImage,
    createImageGenerator,
  } from "canvacord";

  const Manipulator = createTemplate((image) => {
    return {
      steps: [
        // base image
        {
          // one step can take multiple images
          image: [
            {
              source: new TemplateImage(ImageFactory.AFFECT), // source image
              x: 0, // x position
              y: 0, // y position
            },
          ],
        },
        // target image
        {
          image: [
            {
              source: new TemplateImage(image), // target image
              x: 180, // x position
              y: 383, // y position
              width: 200, // width
              height: 157, // height
            },
          ],
        },
      ],
    };
  });

  // get target photo to use on "affected" meme image
  const photo = await getPhotoForMemeSomehow();
  const generator = createImageGenerator(Manipulator(photo));

  // render out the image
  await generator.render();

  // get the resulting image in png format
  const affectedMeme = await generator.encode("png");
  ```

  ```js CommonJS theme={null}
  const {
    createTemplate,
    ImageFactory,
    TemplateImage,
    createImageGenerator,
  } = require("canvacord");

  const Manipulator = createTemplate((image) => {
    return {
      steps: [
        // base image
        {
          // one step can take multiple images
          image: [
            {
              source: new TemplateImage(ImageFactory.AFFECT), // source image
              x: 0, // x position
              y: 0, // y position
            },
          ],
        },
        // target image
        {
          image: [
            {
              source: new TemplateImage(image), // target image
              x: 180, // x position
              y: 383, // y position
              width: 200, // width
              height: 157, // height
            },
          ],
        },
      ],
    };
  });

  // get target photo to use on "affected" meme image
  const photo = await getPhotoForMemeSomehow();
  const generator = createImageGenerator(Manipulator(photo));

  // render out the image
  await generator.render();

  // get the resulting image in png format
  const affectedMeme = await generator.encode("png");
  ```
</CodeGroup>

### Structure

```ts theme={null}
export interface ImageGenerationStep {
  /**
   * The image to render.
   */
  image?: ImgenStep[];
  /**
   * The text to render.
   */
  text?: TextGenerationStep[];
  /**
   * The custom steps to apply to the canvas.
   */
  custom?: CustomGenerationStep[];
  /**
   * The function to call before processing this step.
   */
  preprocess?: (
    canvas: Canvas,
    ctx: SKRSContext2D,
    step: ImageGenerationStep
  ) => Awaited<void>;
  /**
   * The function to call when processing this step.
   */
  process?: (
    canvas: Canvas,
    ctx: SKRSContext2D,
    step: ImageGenerationStep
  ) => Awaited<void>;
  /**
   * The function to call after processing has finished.
   */
  postprocess?: (
    canvas: Canvas,
    ctx: SKRSContext2D,
    step: ImageGenerationStep
  ) => Awaited<void>;
}

export interface CustomGenerationStep {
  /**
   * The function to call when processing this step.
   */
  process: (
    canvas: Canvas,
    ctx: SKRSContext2D,
    step: ImageGenerationStep
  ) => Awaited<void>;
}

export interface ImgenStep {
  /**
   * The image to render.
   */
  source: TemplateImage;
  /**
   * The x position of the image.
   */
  x: number;
  /**
   * The y position of the image.
   */
  y: number;
  /**
   * The width of the image.
   */
  width?: number;
  /**
   * The height of the image.
   */
  height?: number;
  /**
   * The function to call before processing this step.
   */
  preprocess?: (
    canvas: Canvas,
    ctx: SKRSContext2D,
    source: ImgenStep
  ) => Awaited<void>;
  /**
   * The function to call when processing this step.
   */
  process?: (
    canvas: Canvas,
    ctx: SKRSContext2D,
    source: ImgenStep
  ) => Awaited<void>;
  /**
   * The function to call after processing has finished.
   */
  postprocess?: (
    canvas: Canvas,
    ctx: SKRSContext2D,
    source: ImgenStep
  ) => Awaited<void>;
}

export interface TextGenerationStep {
  /**
   * The text to render.
   */
  value: string;
  /**
   * The font of the text.
   */
  font: string;
  /**
   * The color of the text.
   */
  color: string;
  /**
   * Whether to stroke the text.
   */
  stroke?: boolean;
  /**
   * The x position of the text.
   */
  x: number;
  /**
   * The y position of the text.
   */
  y: number;
  /**
   * The maximum width of the text.
   */
  maxWidth?: number;
  /**
   * The line height of the text.
   */
  lineHeight?: number;
  /**
   * The line width of the text.
   */
  lineWidth?: number;
  /**
   * The alignment of the text.
   */
  align?: "left" | "center" | "right";
  /**
   * The baseline of the text.
   */
  baseline?: "top" | "middle" | "bottom";
  /**
   * The directionality of the text.
   */
  direction?: "inherit" | "ltr" | "rtl";
  /**
   * The function to call before processing this step.
   */
  preprocess?: (
    canvas: Canvas,
    ctx: SKRSContext2D,
    text: TextGenerationStep
  ) => Awaited<void>;
  /**
   * The function to call when processing this step.
   */
  process?: (
    canvas: Canvas,
    ctx: SKRSContext2D,
    text: TextGenerationStep
  ) => Awaited<void>;
  /**
   * The function to call after processing has finished.
   */
  postprocess?: (
    canvas: Canvas,
    ctx: SKRSContext2D,
    text: TextGenerationStep
  ) => Awaited<void>;
}

/**
 * The template to use for image generation.
 */
export interface IImageGenerationTemplate {
  /**
   * The width of the template.
   */
  width?: number;
  /**
   * The height of the template.
   */
  height?: number;
  /**
   * The steps to apply to the canvas.
   */
  steps: ImageGenerationStep[];
  /**
   * The gif options.
   */
  gif?: EncoderOptions;
}
```
