ArtistAPhoto Documentation

Complete documentation for the ArtistAPhoto image editing SDK.

Getting Started

ArtistAPhoto is a powerful browser-based image editing SDK that provides a complete toolkit for image manipulation. With support for filters, adjustments, transformations, text overlays, shapes, and full undo/redo functionality, it's designed to integrate seamlessly into any web application.

Key Features

  • 10 Professional Filters - Grayscale, sepia, blur, sharpen, vintage, invert, vignette, posterize, pixelate, edge detection
  • 5 Image Adjustments - Brightness, contrast, saturation, exposure, temperature
  • Transformations - Crop, resize with quality control
  • Overlays - Text with full styling, shapes (rectangles, ellipses)
  • Non-destructive Editing - Original image preserved, full undo/redo
  • High Performance - Web Workers for heavy operations
  • TypeScript Ready - Full type definitions included
  • Multiple Export Formats - JPEG, PNG, WebP

Quick Example

import { ArtistAPhoto } from 'artistaphoto';

// Load an image
const editor = await ArtistAPhoto.fromFile(file);

// Apply edits
editor
  .crop({ x: 50, y: 50, width: 400, height: 400 })
  .filter('vintage', 0.8)
  .brightness(10)
  .resize(800, 600);

// Download result
await editor.download('edited-photo.jpg', 'image/jpeg', 0.9);

Installation

npm

npm install artistaphoto

yarn

yarn add artistaphoto

pnpm

pnpm add artistaphoto

CDN (Browser)

<script src="https://unpkg.com/artistaphoto/dist/index.global.js"></script>
<script>
  const { ArtistAPhoto } = window.artistaphoto;
</script>

ES Module Import

import { ArtistAPhoto } from 'artistaphoto';

CommonJS

const { ArtistAPhoto } = require('artistaphoto');

Licensing

ArtistAPhoto is a commercial SDK with a free trial mode.

Trial Mode (No License)

Without a license key, the SDK operates in trial mode:

FeatureTrial Mode
All editing featuresAvailable
Preview (toCanvas)No watermark
Export (toBlob, toDataURL, download)With watermark

Activating Your License

import { ArtistAPhoto, LicenseError } from 'artistaphoto';

async function activateLicense() {
  try {
    const licenseInfo = await ArtistAPhoto.setLicenseKey('YOUR-LICENSE-KEY');
    console.log('License activated!', licenseInfo);
  } catch (error) {
    if (error instanceof LicenseError) {
      console.error('License error:', error.code, error.message);
    }
  }
}

License Methods

MethodDescription
setLicenseKey(key)Activate a license key
isLicenseValid()Check if license is valid
getLicenseInfo()Get license details
clearLicense()Deactivate license (returns to trial)
refreshLicense()Force re-validation

Core Concepts

Fluent API

ArtistAPhoto uses a fluent (chainable) API pattern. Most methods return this, allowing you to chain operations:

editor
  .crop({ x: 0, y: 0, width: 500, height: 500 })
  .filter('grayscale')
  .brightness(20)
  .resize(400, 400);

Non-Destructive Editing

All edits are stored as operations in a queue. The original image is never modified, allowing you to:

  • Undo/redo any operation
  • Reset to the original image at any time
  • Preview changes before exporting

Operation Queue

Operations are applied in order when you call preview(), toCanvas(), toBlob(), toDataURL(), or download().

// Operations are queued, not immediately applied
editor.brightness(20);  // Queued
editor.contrast(10);    // Queued

// Operations applied when rendering
const canvas = await editor.preview();

Loading Images

ArtistAPhoto provides multiple ways to load images.

From URL

const editor = await ArtistAPhoto.fromUrl('https://example.com/image.jpg');

Note: The image URL must be CORS-enabled or same-origin.

From File Input

const fileInput = document.getElementById('fileInput');
fileInput.addEventListener('change', async (e) => {
  const file = e.target.files[0];
  const editor = await ArtistAPhoto.fromFile(file);
});

From Canvas Element

const canvas = document.getElementById('myCanvas');
const editor = await ArtistAPhoto.fromCanvas(canvas);

From Image Element

const img = document.getElementById('myImage');
const editor = await ArtistAPhoto.fromImageElement(img);

Transformations

Crop

Extract a rectangular region from the image.

editor.crop({
  x: number,      // Left position (required)
  y: number,      // Top position (required)
  width: number,  // Crop width (required)
  height: number  // Crop height (required)
});

// Example: Crop a 300x300 region starting at position (50, 50)
editor.crop({ x: 50, y: 50, width: 300, height: 300 });

Resize

Scale the image to new dimensions.

editor.resize(
  width: number,   // Target width (required)
  height: number,  // Target height (required)
  options?: {
    quality?: 'low' | 'medium' | 'high',  // Default: 'medium'
    maintainAspectRatio?: boolean          // Default: false
  }
);

// Examples
editor.resize(800, 600);

// High-quality resize maintaining aspect ratio
editor.resize(800, 600, {
  quality: 'high',
  maintainAspectRatio: true
});

Quality Levels

QualityDescription
lowFastest, suitable for thumbnails
mediumBalanced quality and speed
highBest quality, uses multi-step algorithm

Filters

Apply visual filters to the image. All filters accept an intensity parameter (0 to 1).

editor.filter(type: FilterType, intensity?: number);

Available Filters

FilterDescriptionDefault Intensity
grayscaleConvert to black and white1.0
sepiaWarm, vintage brown tones1.0
blurGaussian blur effect1.0
sharpenEnhance edges and details1.0
vintageRetro look with vignette1.0
invertNegative/inverted colors1.0
vignetteDarkened edges1.0
posterizeReduce color levels1.0
pixelatePixelated/mosaic effect1.0
edgeDetectionSobel edge detection1.0

Examples

// Full intensity grayscale
editor.filter('grayscale');

// 50% sepia effect
editor.filter('sepia', 0.5);

// Light blur
editor.filter('blur', 0.3);

// Combine multiple filters
editor
  .filter('vintage', 0.7)
  .filter('vignette', 0.5);

Adjustments

Fine-tune image properties. All adjustments accept values from -100 to 100.

Brightness

editor.brightness(value: number); // -100 to 100
ValueEffect
-100Completely dark
0No change
100Completely bright

Contrast

editor.contrast(value: number); // -100 to 100

Saturation

editor.saturation(value: number); // -100 to 100

Exposure

editor.exposure(value: number); // -100 to 100

Temperature

editor.temperature(value: number); // -100 to 100

Combined Example

// Portrait enhancement
editor
  .brightness(5)
  .contrast(10)
  .saturation(-5)
  .temperature(10);

Text & Shapes

Adding Text

Add text overlays with full styling options.

editor.addText({
  // Required
  text: string,
  x: number,
  y: number,

  // Optional styling
  fontSize?: number,        // Default: 24
  fontFamily?: string,      // Default: 'Arial'
  color?: string,           // Default: '#000000'
  bold?: boolean,           // Default: false
  italic?: boolean,         // Default: false
  align?: 'left' | 'center' | 'right',
  rotation?: number,        // Rotation in degrees

  // Optional stroke (outline)
  stroke?: { color: string, width: number },

  // Optional shadow
  shadow?: { color: string, blur: number, offsetX: number, offsetY: number }
});

Text Examples

// Simple text
editor.addText({ text: 'Hello World', x: 100, y: 100 });

// Styled text
editor.addText({
  text: 'ArtistAPhoto',
  x: 200,
  y: 150,
  fontSize: 48,
  fontFamily: 'Georgia',
  color: '#FF0000',
  bold: true,
  italic: true
});

// Text with stroke and shadow
editor.addText({
  text: 'WATERMARK',
  x: 300,
  y: 200,
  fontSize: 36,
  color: '#FFFFFF',
  stroke: { color: '#000000', width: 2 },
  shadow: { color: 'rgba(0, 0, 0, 0.5)', blur: 4, offsetX: 2, offsetY: 2 }
});

Adding Shapes

editor.addShape({
  type: 'rectangle' | 'ellipse',
  x: number,
  y: number,
  width: number,
  height: number,
  fill?: string,            // Fill color
  rotation?: number,        // Rotation in degrees
  stroke?: { color: string, width: number }
});

Shape Examples

// Filled rectangle
editor.addShape({
  type: 'rectangle',
  x: 50, y: 50,
  width: 200, height: 100,
  fill: '#FF0000'
});

// Circle (ellipse with equal width/height)
editor.addShape({
  type: 'ellipse',
  x: 150, y: 150,
  width: 100, height: 100,
  fill: '#00FF00'
});

// Rectangle with stroke only
editor.addShape({
  type: 'rectangle',
  x: 100, y: 100,
  width: 150, height: 80,
  stroke: { color: '#0000FF', width: 3 }
});

Undo/Redo

ArtistAPhoto maintains a complete history of operations, allowing full undo/redo support.

// Undo last operation
editor.undo();

// Redo previously undone operation
editor.redo();

// Check availability
if (editor.canUndo()) {
  editor.undo();
}

if (editor.canRedo()) {
  editor.redo();
}

// Reset to original image
editor.reset();

// Get operation history
const history = editor.getHistory();

Exporting

Export the edited image in various formats.

Preview (Canvas)

const canvas = await editor.preview();
document.body.appendChild(canvas);

Note: Preview never includes watermark, even in trial mode.

To Blob

const blob = await editor.toBlob(
  format?: 'image/jpeg' | 'image/png' | 'image/webp',
  quality?: number  // 0-1 for JPEG/WebP
);

// Upload example
const formData = new FormData();
formData.append('image', blob, 'edited.jpg');
await fetch('/upload', { method: 'POST', body: formData });

To Data URL

const dataURL = await editor.toDataURL('image/jpeg', 0.9);
document.getElementById('result').src = dataURL;

Download

// Download as JPEG with 90% quality
await editor.download('my-photo.jpg', 'image/jpeg', 0.9);

// Download as PNG (lossless)
await editor.download('my-photo.png', 'image/png');

// Download as WebP with 85% quality
await editor.download('my-photo.webp', 'image/webp', 0.85);

Format Comparison

FormatCompressionTransparencyBest For
JPEGLossyNoPhotos
PNGLosslessYesGraphics, screenshots
WebPBothYesWeb (smaller files)

Error Handling

ArtistAPhoto provides specific error types for different failure scenarios.

import {
  ArtistAPhoto,
  LicenseError,
  ImageLoadError,
  InvalidCropError,
  InvalidDimensionsError
} from 'artistaphoto';

async function editImage(file) {
  try {
    await ArtistAPhoto.setLicenseKey(process.env.LICENSE_KEY);
    const editor = await ArtistAPhoto.fromFile(file);
    editor.filter('vintage').brightness(10);
    return await editor.toBlob('image/jpeg', 0.9);

  } catch (error) {
    if (error instanceof LicenseError) {
      console.error('License problem:', error.code);
    } else if (error instanceof ImageLoadError) {
      console.error('Could not load image');
    } else {
      console.error('Unexpected error:', error);
    }
  }
}

License Error Codes

CodeDescription
INVALID_KEYLicense key not found or invalid format
LICENSE_EXPIREDLicense has expired
LICENSE_REVOKEDLicense was revoked
LICENSE_DISABLEDLicense was disabled
NO_LICENSENo license key set (when calling refresh)

TypeScript

ArtistAPhoto is written in TypeScript and includes full type definitions.

Importing Types

import {
  ArtistAPhoto,
  LicenseError,
  ImageLoadError,
  InvalidCropError,
  InvalidDimensionsError,
  FilterType,
  ExportFormat,
  CropOptions,
  ResizeOptions,
  TextOptions,
  ShapeOptions,
  LicenseInfo,
  LicenseConfig
} from 'artistaphoto';

Type Definitions

type FilterType =
  | 'grayscale' | 'sepia' | 'blur' | 'sharpen' | 'vintage'
  | 'invert' | 'vignette' | 'posterize' | 'pixelate' | 'edgeDetection';

type ExportFormat = 'image/jpeg' | 'image/png' | 'image/webp';

interface CropOptions {
  x: number;
  y: number;
  width: number;
  height: number;
}

interface ResizeOptions {
  quality?: 'low' | 'medium' | 'high';
  maintainAspectRatio?: boolean;
}

Performance

ArtistAPhoto is optimized for performance in browser environments.

Web Workers

Heavy operations automatically use Web Workers to avoid blocking the main thread:

  • Blur filter
  • Sharpen filter
  • Edge detection filter
  • Pixelate filter

Best Practices

// 1. Process at display size, not original size
editor
  .resize(1200, 900)
  .filter('blur', 0.5);  // Much faster on smaller image

// 2. Chain operations before rendering
editor
  .brightness(10)
  .contrast(5)
  .filter('vintage');
const result = await editor.toBlob();

// 3. Use appropriate quality settings
// Thumbnails: low quality resize, high compression
editor.resize(200, 200, { quality: 'low' });
await editor.toBlob('image/jpeg', 0.6);

Browser Support

Supported Browsers

BrowserVersion
ChromeLast 2 versions
EdgeLast 2 versions
FirefoxLast 2 versions
SafariLast 2 versions

Required APIs

  • Canvas API
  • ES2020
  • Fetch API (for URL loading)
  • Blob API (for export)

FAQ

Can I use ArtistAPhoto without a license?

Yes! The SDK works fully without a license. The only limitation is that exported images will have a watermark. This is perfect for evaluation, testing, and development.

How does the watermark look?

The watermark displays "ArtistAPhoto - UNLICENSED" in a diagonal pattern across the entire image. It's semi-transparent (30% opacity) gray text.

Does ArtistAPhoto modify the original image?

No. ArtistAPhoto uses non-destructive editing. The original image is preserved, and all edits are stored as operations. You can always call reset() to return to the original.

How large images can ArtistAPhoto handle?

This depends on the browser and device memory. Generally up to 4000x4000 pixels works well on desktop, and up to 2000x2000 pixels on mobile devices.

Troubleshooting

Image won't load from URL

Problem: ImageLoadError when loading from URL.

Solutions:

  • Check if the URL is accessible
  • Verify CORS headers on the server
  • Try loading from same origin
  • Use fromFile() instead with a file input

Export quality is poor

Solutions:

  • Use higher quality setting: toBlob('image/jpeg', 0.95)
  • Use PNG for lossless: toBlob('image/png')
  • Avoid multiple resize operations
  • Use quality: 'high' for resize

Watermark appears even with license

Solutions:

  • Verify isLicenseValid() returns true
  • Ensure setLicenseKey() completed successfully before export
  • Check getLicenseInfo() for expiration
  • Try refreshLicense() to update cached license

Support

Last updated: January 2025