composeImage method

  1. @override
Future<Uint8List> composeImage({
  1. required Uint8List inputImage,
  2. required Uint8List watermarkImage,
  3. String anchor = 'bottomRight',
  4. double margin = 16.0,
  5. double widthPercent = 0.18,
  6. double opacity = 0.6,
  7. String format = 'jpeg',
  8. double quality = 0.9,
  9. double offsetX = 0.0,
  10. double offsetY = 0.0,
  11. String marginUnit = 'px',
  12. String offsetUnit = 'px',
})
override

Composes inputImage with watermarkImage and returns encoded bytes.

Options (all optional with defaults):

  • anchor: one of 'topLeft','topRight','bottomLeft','bottomRight','center' (default: 'bottomRight')
  • margin: logical pixels in output space (default: 16.0)
  • widthPercent: 0..1 relative to base width (default: 0.18)
  • opacity: 0..1 applied to watermark (default: 0.6)
  • format: 'jpeg' | 'png' (default: 'jpeg')
  • quality: 0..1 for JPEG (default: 0.9)
  • offsetX/offsetY: offsets from the anchor (default: 0)
  • marginUnit: 'px' | 'percent' (default: 'px')
  • offsetUnit: 'px' | 'percent' (default: 'px')

Implementation

@override
Future<Uint8List> composeImage({
  required Uint8List inputImage,
  required Uint8List watermarkImage,
  String anchor = 'bottomRight',
  double margin = 16.0,
  double widthPercent = 0.18,
  double opacity = 0.6,
  String format = 'jpeg',
  double quality = 0.9,
  double offsetX = 0.0,
  double offsetY = 0.0,
  String marginUnit = 'px',
  String offsetUnit = 'px',
}) async {
  pigeon.Anchor _anchorFromString(String s) {
    switch (s) {
      case 'topLeft':
        return pigeon.Anchor.topLeft;
      case 'topRight':
        return pigeon.Anchor.topRight;
      case 'bottomLeft':
        return pigeon.Anchor.bottomLeft;
      case 'center':
        return pigeon.Anchor.center;
      case 'bottomRight':
      default:
        return pigeon.Anchor.bottomRight;
    }
  }

  pigeon.OutputFormat _formatFromString(String s) {
    switch (s) {
      case 'png':
        return pigeon.OutputFormat.png;
      case 'jpeg':
      default:
        return pigeon.OutputFormat.jpeg;
    }
  }

  pigeon.MeasureUnit _unitFromString(String s) {
    switch (s) {
      case 'percent':
        return pigeon.MeasureUnit.percent;
      case 'px':
      default:
        return pigeon.MeasureUnit.px;
    }
  }

  final api = pigeon.WatermarkApi();
  final req = pigeon.ComposeImageRequest(
    baseImage: inputImage,
    watermarkImage: watermarkImage,
    anchor: _anchorFromString(anchor),
    margin: margin,
    widthPercent: widthPercent,
    opacity: opacity,
    format: _formatFromString(format),
    quality: quality,
    offsetX: offsetX,
    offsetY: offsetY,
    marginUnit: _unitFromString(marginUnit),
    offsetUnit: _unitFromString(offsetUnit),
  );
  try {
    final res = await api.composeImage(req);
    return res.imageBytes;
  } on PlatformException catch (_) {
    // Fallback to legacy MethodChannel if Pigeon channel isn't set up.
    final args = <String, dynamic>{
      'inputImage': inputImage,
      'watermarkImage': watermarkImage,
      'anchor': anchor,
      'margin': margin,
      'widthPercent': widthPercent,
      'opacity': opacity,
      'format': format,
      'quality': quality,
      'offsetX': offsetX,
      'offsetY': offsetY,
      'marginUnit': marginUnit,
      'offsetUnit': offsetUnit,
    };
    final bytes = await methodChannel.invokeMethod<Uint8List>('composeImage', args);
    if (bytes == null) {
      throw PlatformException(code: 'compose_failed', message: 'No bytes returned');
    }
    return bytes;
  }
}