compress method

  1. @override
Future<Uint8List> compress(
  1. Uint8List data,
  2. CompressOptions options
)
override

Compresses image data in memory.

Takes raw image data as Uint8List and applies compression according to options.

Returns compressed image data as Uint8List.

Throws ImageCompressException if compression fails.

Implementation

@override
Future<Uint8List> compress(Uint8List data, CompressOptions options) async {
  try {
    // Detect image format by magic bytes
    final format = _detectFormat(data);
    final mimeType = format == 'jpeg' ? 'image/jpeg' : 'image/png';

    // Create blob from Uint8List
    final blob = web.Blob(
      [data.buffer.toJS].toJS,
      web.BlobPropertyBag(type: mimeType),
    );
    final url = web.URL.createObjectURL(blob);

    try {
      // Load image
      final img = web.HTMLImageElement();
      final completer = Completer<void>();

      img.addEventListener(
        'load',
        (web.Event event) {
          completer.complete();
        }.toJS,
      );

      img.addEventListener(
        'error',
        (web.Event event) {
          completer.completeError(
            ImageCompressException('Failed to load image', 'INVALID_IMAGE'),
          );
        }.toJS,
      );

      img.src = url;
      await completer.future;

      // Calculate target dimensions
      final dimensions = _calculateDimensions(
        img.width,
        img.height,
        options.maxWidth,
        options.maxHeight,
      );

      // Create canvas and draw resized image
      final canvas = web.HTMLCanvasElement();
      canvas.width = dimensions.width;
      canvas.height = dimensions.height;

      final ctx = canvas.getContext('2d') as web.CanvasRenderingContext2D;
      ctx.drawImage(
        img,
        0,
        0,
        dimensions.width.toDouble(),
        dimensions.height.toDouble(),
      );

      // Convert to blob
      final resultCompleter = Completer<Uint8List>();

      canvas.toBlob(
        ((web.Blob? blob) {
          if (blob == null) {
            resultCompleter.completeError(
              ImageCompressException(
                'Failed to create blob',
                'COMPRESSION_FAILED',
              ),
            );
            return;
          }

          final reader = web.FileReader();
          reader.addEventListener(
            'loadend',
            (web.Event event) {
              final result = reader.result;
              if (result != null) {
                final jsArrayBuffer = result as JSArrayBuffer;
                final uint8List = jsArrayBuffer.toDart.asUint8List();
                resultCompleter.complete(uint8List);
              } else {
                resultCompleter.completeError(
                  ImageCompressException(
                    'Failed to read blob',
                    'COMPRESSION_FAILED',
                  ),
                );
              }
            }.toJS,
          );

          reader.addEventListener(
            'error',
            (web.Event event) {
              resultCompleter.completeError(
                ImageCompressException(
                  'Failed to read blob',
                  'COMPRESSION_FAILED',
                ),
              );
            }.toJS,
          );

          reader.readAsArrayBuffer(blob);
        }).toJS,
        mimeType,
        format == 'jpeg' ? (options.quality / 100.0).toJS : null,
      );

      return await resultCompleter.future;
    } finally {
      web.URL.revokeObjectURL(url);
    }
  } catch (e) {
    if (e is ImageCompressException) {
      rethrow;
    }
    throw ImageCompressException(
      'Unexpected error during compression: $e',
      'COMPRESSION_FAILED',
    );
  }
}