compress method
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 = _getMimeType(format);
// 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>();
// Determine quality parameter based on format
final qualityParam = _shouldApplyQuality(format)
? (options.quality / 100.0).toJS
: null;
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,
qualityParam,
);
return await resultCompleter.future;
} finally {
web.URL.revokeObjectURL(url);
}
} catch (e) {
// Graceful error handling: log error and return original data
if (e is ImageCompressException) {
debugPrint('Web compression failed: ${e.message} (${e.code})');
} else {
debugPrint('Web compression failed with unexpected error: $e');
}
return data;
}
}