Facsimile

Turns a photo of your stamp or signature into a transparent facsimile you can place on documents, print, or e-sign.

All famous image formats are supported as input (jpg, png, webp, tiff, ...). The output is always a PNG with a transparent background: the paper is removed, the ink is kept with its original color.

Features

  • removeBackground — cuts out a light (usually white) paper background using a soft luminance threshold. Great for stamps and signatures shot on paper.
  • removeColor — removes a specific background color (tinted or colored paper), with a soft transition to avoid jagged edges.
  • Pure Dart, no platform channels — works on mobile, desktop and web.

Getting started

Add the dependency to your pubspec.yaml:

dependencies:
  facsimile: ^1.0.0

Usage

import 'dart:typed_data';

import 'package:facsimile/facsimile.dart';

Future<Uint8List> makeFacsimile(Uint8List photoBytes) async {
  // Defaults work well for a signature/stamp on white paper.
  return Facsimile().removeBackground(photoBytes);
}

Then render the result over your document, e.g.:

Stack(
  children: [
    Image.memory(documentPng),
    Positioned(
      left: 120,
      top: 180,
      child: Image.memory(facsimilePng, width: 200),
    ),
  ],
)

Tuning

Photos taken in poor light (gray paper, shadows) may need adjustment:

// Raise the threshold to keep thin, light strokes; lower it if
// a gray/shadowed background is left behind.
final result = Facsimile().removeBackground(
  photoBytes,
  threshold: 190,
  softness: 60,
);

// Yellowish or tinted paper:
final result = Facsimile().removeColor(
  photoBytes,
  red: 255,
  green: 253,
  blue: 235,
);

Both methods are synchronous and throw ArgumentError if the input bytes are not a decodable image.

Large photos

The background is removed pixel by pixel, so processing modern big phone photos (12–48 MP) can take a noticeable amount of time — especially on the web. If you expect large inputs, downscale before processing:

import 'package:image/image.dart' as img;

final decoded = img.decodeImage(photoBytes)!;
final resized = img.copyResize(decoded, width: 1920, maintainAspect: true);
final out = Facsimile().removeBackground(img.encodeJpg(resized));

iPhone (HEIC) photos

Newer iPhone cameras save photos as HEIC, which the pure-Dart image decoder does not support. When picking a photo, ask the picker to re-encode to JPEG:

final picked = await picker.pickImage(source: ImageSource.camera, imageQuality: 90);

Native HEIC decoding is on the roadmap (see below).

Additional information

The original colors of the stamp or signature are preserved and the EXIF orientation of phone photos is baked in, so the result is always upright. The returned PNG has the same dimensions as the source image.

Roadmap

  • Native HEIC (Apple) decoding for iPhone photos, on all platforms.
  • Optional automatic downscaling (maxDimension) for a fast path on very large photos.

Facsimile (Русский)

Превращает фотографию вашей печати или подписи в прозрачный факсемиле, который можно накладывать на документы, печатать или использовать для электронной подписи.

Поддерживаются все популярные форматы изображений на входе (jpg, png, webp, tiff ...). На выходе всегда PNG с прозрачным фоном: бумага удаляется, а оттиск (чернила) сохраняется в его исходном цвете.

Возможности

  • removeBackground — убирает светлый (обычно белый) бумажный фон с помощью мягкого порога по яркости. Отлично подходит для печатей и подписей, сфотографированных на бумаге.
  • removeColor — убирает фон конкретного цвета (тонированная или цветная бумага) с плавным переходом, чтобы не было рваных краёв.
  • Чистый Dart, без платформенных каналов — работает на мобильных, десктопе и в вебе.

Установка

Добавьте зависимость в ваш pubspec.yaml:

dependencies:
  facsimile: ^1.0.0

Использование

import 'dart:typed_data';

import 'package:facsimile/facsimile.dart';

Future<Uint8List> makeFacsimile(Uint8List photoBytes) async {
  // Параметры по умолчанию хорошо работают для подписи/печати на белой бумаге.
  return Facsimile().removeBackground(photoBytes);
}

Затем наложите результат на ваш документ, например:

Stack(
  children: [
    Image.memory(documentPng),
    Positioned(
      left: 120,
      top: 180,
      child: Image.memory(facsimilePng, width: 200),
    ),
  ],
)

Настройка

Фотографии, снятые при плохом свете (серая бумага, тени), могут потребовать настройки:

// Поднимите порог, чтобы сохранить тонкие светлые штрихи; опустите его,
// если остаётся серый/теневой фон.
final result = Facsimile().removeBackground(
  photoBytes,
  threshold: 190,
  softness: 60,
);

// Желтоватая или тонированная бумага:
final result = Facsimile().removeColor(
  photoBytes,
  red: 255,
  green: 253,
  blue: 235,
);

Оба метода синхронные и бросают ArgumentError, если входные байты не являются распознаваемым изображением.

Большие файлы

Фон убирается попиксельно, поэтому обработка больших современных снимков с телефона (12–48 МП) может занять заметное время — особенно в вебе. Если на входе ожидаются крупные фото, уменьшите их перед обработкой:

import 'package:image/image.dart' as img;

final decoded = img.decodeImage(photoBytes)!;
final resized = img.copyResize(decoded, width: 1920, maintainAspect: true);
final out = Facsimile().removeBackground(img.encodeJpg(resized));

Фото с iPhone (HEIC)

Современные камеры iPhone сохраняют фото в HEIC, который чистый Dart-декодер image не поддерживает. При выборе фото попросите пикер перекодировать в JPEG:

final picked = await picker.pickImage(source: ImageSource.camera, imageQuality: 90);

Нативная поддержка HEIC — в планах (см. ниже).

Дополнительная информация

Исходные цвета печати или подписи сохраняются, а EXIF-ориентация телефонных фото учитывается, поэтому результат всегда стоит правильно. Возвращаемый PNG имеет те же размеры, что и исходное изображение.

Планы на будущие версии

  • Нативная поддержка HEIC (Apple) для фото с iPhone, на всех платформах.
  • Опциональное автоматическое уменьшение (maxDimension) для быстрой обработки очень больших фото.

Libraries

facsimile