refactor: Resizing
This commit is contained in:
parent
43d2003e6c
commit
570ca352cf
|
|
@ -57,63 +57,20 @@ final class ImageConverterAndroid implements ImageConverterPlatform {
|
|||
throw Exception('Failed to decode image. Invalid image data.');
|
||||
}
|
||||
|
||||
switch (resizeMode) {
|
||||
case OriginalResizeMode():
|
||||
bitmapToCompress = originalBitmap;
|
||||
case ExactResizeMode(width: final w, height: final h):
|
||||
scaledBitmap = Bitmap.createScaledBitmap(
|
||||
originalBitmap,
|
||||
w,
|
||||
h,
|
||||
true, // filter
|
||||
);
|
||||
bitmapToCompress = scaledBitmap;
|
||||
case FitResizeMode(:final width, :final height):
|
||||
final originalWidth = originalBitmap.getWidth();
|
||||
final originalHeight = originalBitmap.getHeight();
|
||||
final (newWidth, newHeight) = resizeMode.calculateSize(
|
||||
originalWidth,
|
||||
originalHeight,
|
||||
);
|
||||
|
||||
double newWidth;
|
||||
double newHeight;
|
||||
|
||||
if (width != null && height != null) {
|
||||
if (originalWidth <= width && originalHeight <= height) {
|
||||
if (newWidth == originalWidth && newHeight == originalHeight) {
|
||||
bitmapToCompress = originalBitmap;
|
||||
break;
|
||||
}
|
||||
final aspectRatio = originalWidth / originalHeight;
|
||||
newWidth = width.toDouble();
|
||||
newHeight = newWidth / aspectRatio;
|
||||
if (newHeight > height) {
|
||||
newHeight = height.toDouble();
|
||||
newWidth = newHeight * aspectRatio;
|
||||
}
|
||||
} else if (width != null) {
|
||||
if (originalWidth <= width) {
|
||||
bitmapToCompress = originalBitmap;
|
||||
break;
|
||||
}
|
||||
newWidth = width.toDouble();
|
||||
final aspectRatio = originalWidth / originalHeight;
|
||||
newHeight = newWidth / aspectRatio;
|
||||
} else if (height != null) {
|
||||
if (originalHeight <= height) {
|
||||
bitmapToCompress = originalBitmap;
|
||||
break;
|
||||
}
|
||||
newHeight = height.toDouble();
|
||||
final aspectRatio = originalWidth / originalHeight;
|
||||
newWidth = newHeight * aspectRatio;
|
||||
} else {
|
||||
// This case should not be reachable due to the assertion
|
||||
// in the FitResizeMode constructor.
|
||||
bitmapToCompress = originalBitmap;
|
||||
break;
|
||||
}
|
||||
|
||||
scaledBitmap = Bitmap.createScaledBitmap(
|
||||
originalBitmap,
|
||||
newWidth.round(),
|
||||
newHeight.round(),
|
||||
newWidth,
|
||||
newHeight,
|
||||
true, // filter
|
||||
);
|
||||
bitmapToCompress = scaledBitmap;
|
||||
|
|
|
|||
|
|
@ -73,58 +73,19 @@ final class ImageConverterDarwin implements ImageConverterPlatform {
|
|||
throw Exception('Failed to decode image.');
|
||||
}
|
||||
|
||||
switch (resizeMode) {
|
||||
case OriginalResizeMode():
|
||||
imageToEncode = originalImage;
|
||||
case ExactResizeMode(width: final w, height: final h):
|
||||
imageToEncode = _resizeImage(originalImage, w, h);
|
||||
case FitResizeMode(:final width, :final height):
|
||||
final originalWidth = CGImageGetWidth(originalImage);
|
||||
final originalHeight = CGImageGetHeight(originalImage);
|
||||
|
||||
double newWidth;
|
||||
double newHeight;
|
||||
|
||||
if (width != null && height != null) {
|
||||
if (originalWidth <= width && originalHeight <= height) {
|
||||
imageToEncode = originalImage;
|
||||
break;
|
||||
}
|
||||
final aspectRatio = originalWidth / originalHeight;
|
||||
newWidth = width.toDouble();
|
||||
newHeight = newWidth / aspectRatio;
|
||||
if (newHeight > height) {
|
||||
newHeight = height.toDouble();
|
||||
newWidth = newHeight * aspectRatio;
|
||||
}
|
||||
} else if (width != null) {
|
||||
if (originalWidth <= width) {
|
||||
imageToEncode = originalImage;
|
||||
break;
|
||||
}
|
||||
newWidth = width.toDouble();
|
||||
final aspectRatio = originalWidth / originalHeight;
|
||||
newHeight = newWidth / aspectRatio;
|
||||
} else if (height != null) {
|
||||
if (originalHeight <= height) {
|
||||
imageToEncode = originalImage;
|
||||
break;
|
||||
}
|
||||
newHeight = height.toDouble();
|
||||
final aspectRatio = originalWidth / originalHeight;
|
||||
newWidth = newHeight * aspectRatio;
|
||||
} else {
|
||||
// This case should not be reachable due to the assertion
|
||||
// in the FitResizeMode constructor.
|
||||
imageToEncode = originalImage;
|
||||
break;
|
||||
}
|
||||
imageToEncode = _resizeImage(
|
||||
originalImage,
|
||||
newWidth.round(),
|
||||
newHeight.round(),
|
||||
final (newWidth, newHeight) = resizeMode.calculateSize(
|
||||
originalWidth,
|
||||
originalHeight,
|
||||
);
|
||||
|
||||
if (newWidth == originalWidth && newHeight == originalHeight) {
|
||||
imageToEncode = originalImage;
|
||||
} else {
|
||||
imageToEncode = _resizeImage(originalImage, newWidth, newHeight);
|
||||
}
|
||||
|
||||
if (imageToEncode == nullptr) {
|
||||
throw Exception('Failed to prepare image for encoding.');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,21 @@
|
|||
import 'dart:math';
|
||||
|
||||
/// A sealed class representing different ways to resize an image.
|
||||
sealed class ResizeMode {
|
||||
const ResizeMode();
|
||||
|
||||
/// Calculates the target size for the image based on the original dimensions.
|
||||
(int, int) calculateSize(int originalWidth, int originalHeight);
|
||||
}
|
||||
|
||||
/// A resize mode that keeps the original dimensions of the image.
|
||||
class OriginalResizeMode extends ResizeMode {
|
||||
const OriginalResizeMode();
|
||||
|
||||
@override
|
||||
(int, int) calculateSize(int originalWidth, int originalHeight) {
|
||||
return (originalWidth, originalHeight);
|
||||
}
|
||||
}
|
||||
|
||||
/// A resize mode that resizes the image to exact dimensions,
|
||||
|
|
@ -18,6 +28,11 @@ class ExactResizeMode extends ResizeMode {
|
|||
|
||||
/// The target height for the resized image.
|
||||
final int height;
|
||||
|
||||
@override
|
||||
(int, int) calculateSize(int originalWidth, int originalHeight) {
|
||||
return (width, height);
|
||||
}
|
||||
}
|
||||
|
||||
/// A resize mode that fits the image within the specified dimensions while
|
||||
|
|
@ -34,4 +49,24 @@ class FitResizeMode extends ResizeMode {
|
|||
|
||||
/// The maximum height for the resized image.
|
||||
final int? height;
|
||||
|
||||
@override
|
||||
(int, int) calculateSize(int originalWidth, int originalHeight) {
|
||||
double scale = 1.0;
|
||||
if (width != null && height != null) {
|
||||
final widthScale = width! / originalWidth;
|
||||
final heightScale = height! / originalHeight;
|
||||
scale = min(widthScale, heightScale);
|
||||
} else if (width != null) {
|
||||
scale = width! / originalWidth;
|
||||
} else if (height != null) {
|
||||
scale = height! / originalHeight;
|
||||
}
|
||||
|
||||
if (scale >= 1.0) {
|
||||
return (originalWidth, originalHeight);
|
||||
}
|
||||
|
||||
return ((originalWidth * scale).round(), (originalHeight * scale).round());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,65 +59,10 @@ final class ImageConverterWeb implements ImageConverterPlatform {
|
|||
|
||||
final canvas = HTMLCanvasElement();
|
||||
|
||||
final int destWidth;
|
||||
final int destHeight;
|
||||
|
||||
switch (resizeMode) {
|
||||
case OriginalResizeMode():
|
||||
destWidth = img.width;
|
||||
destHeight = img.height;
|
||||
case ExactResizeMode(width: final w, height: final h):
|
||||
destWidth = w;
|
||||
destHeight = h;
|
||||
case FitResizeMode(:final width, :final height):
|
||||
final originalWidth = img.width;
|
||||
final originalHeight = img.height;
|
||||
|
||||
double newWidth;
|
||||
double newHeight;
|
||||
|
||||
if (width != null && height != null) {
|
||||
if (originalWidth <= width && originalHeight <= height) {
|
||||
destWidth = originalWidth;
|
||||
destHeight = originalHeight;
|
||||
break;
|
||||
}
|
||||
final aspectRatio = originalWidth / originalHeight;
|
||||
newWidth = width.toDouble();
|
||||
newHeight = newWidth / aspectRatio;
|
||||
if (newHeight > height) {
|
||||
newHeight = height.toDouble();
|
||||
newWidth = newHeight * aspectRatio;
|
||||
}
|
||||
} else if (width != null) {
|
||||
if (originalWidth <= width) {
|
||||
destWidth = originalWidth;
|
||||
destHeight = originalHeight;
|
||||
break;
|
||||
}
|
||||
newWidth = width.toDouble();
|
||||
final aspectRatio = originalWidth / originalHeight;
|
||||
newHeight = newWidth / aspectRatio;
|
||||
} else if (height != null) {
|
||||
if (originalHeight <= height) {
|
||||
destWidth = originalWidth;
|
||||
destHeight = originalHeight;
|
||||
break;
|
||||
}
|
||||
newHeight = height.toDouble();
|
||||
final aspectRatio = originalWidth / originalHeight;
|
||||
newWidth = newHeight * aspectRatio;
|
||||
} else {
|
||||
// This case should not be reachable due to the assertion
|
||||
// in the FitResizeMode constructor.
|
||||
destWidth = originalWidth;
|
||||
destHeight = originalHeight;
|
||||
break;
|
||||
}
|
||||
|
||||
destWidth = newWidth.round();
|
||||
destHeight = newHeight.round();
|
||||
}
|
||||
final (destWidth, destHeight) = resizeMode.calculateSize(
|
||||
img.width,
|
||||
img.height,
|
||||
);
|
||||
|
||||
canvas.width = destWidth;
|
||||
canvas.height = destHeight;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,97 @@
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:platform_image_converter/src/output_resize.dart';
|
||||
|
||||
void main() {
|
||||
group('ResizeMode', () {
|
||||
const originalWidth = 1000;
|
||||
const originalHeight = 500;
|
||||
|
||||
group('OriginalResizeMode', () {
|
||||
test('should return original dimensions', () {
|
||||
const resizeMode = OriginalResizeMode();
|
||||
final (width, height) = resizeMode.calculateSize(
|
||||
originalWidth,
|
||||
originalHeight,
|
||||
);
|
||||
expect(width, originalWidth);
|
||||
expect(height, originalHeight);
|
||||
});
|
||||
});
|
||||
|
||||
group('ExactResizeMode', () {
|
||||
test('should return exact dimensions', () {
|
||||
const resizeMode = ExactResizeMode(width: 300, height: 200);
|
||||
final (width, height) = resizeMode.calculateSize(
|
||||
originalWidth,
|
||||
originalHeight,
|
||||
);
|
||||
expect(width, 300);
|
||||
expect(height, 200);
|
||||
});
|
||||
});
|
||||
|
||||
group('FitResizeMode', () {
|
||||
test('downscales with both width and height, respecting aspect ratio', () {
|
||||
// Aspect ratio is 2:1 (1000x500)
|
||||
// Target is 500x500, so scale should be based on width (min(500/1000, 500/500) = 0.5)
|
||||
const resizeMode = FitResizeMode(width: 500, height: 500);
|
||||
final (width, height) = resizeMode.calculateSize(
|
||||
originalWidth,
|
||||
originalHeight,
|
||||
);
|
||||
expect(width, 500); // 1000 * 0.5
|
||||
expect(height, 250); // 500 * 0.5
|
||||
});
|
||||
|
||||
test('does not upscale if image is smaller than target dimensions', () {
|
||||
const resizeMode = FitResizeMode(width: 2000, height: 1000);
|
||||
final (width, height) = resizeMode.calculateSize(
|
||||
originalWidth,
|
||||
originalHeight,
|
||||
);
|
||||
expect(width, originalWidth);
|
||||
expect(height, originalHeight);
|
||||
});
|
||||
|
||||
test('downscales with only width, respecting aspect ratio', () {
|
||||
const resizeMode = FitResizeMode(width: 500);
|
||||
final (width, height) = resizeMode.calculateSize(
|
||||
originalWidth,
|
||||
originalHeight,
|
||||
);
|
||||
expect(width, 500); // 1000 * 0.5
|
||||
expect(height, 250); // 500 * 0.5
|
||||
});
|
||||
|
||||
test('does not upscale with only width', () {
|
||||
const resizeMode = FitResizeMode(width: 2000);
|
||||
final (width, height) = resizeMode.calculateSize(
|
||||
originalWidth,
|
||||
originalHeight,
|
||||
);
|
||||
expect(width, originalWidth);
|
||||
expect(height, originalHeight);
|
||||
});
|
||||
|
||||
test('downscales with only height, respecting aspect ratio', () {
|
||||
const resizeMode = FitResizeMode(height: 250);
|
||||
final (width, height) = resizeMode.calculateSize(
|
||||
originalWidth,
|
||||
originalHeight,
|
||||
);
|
||||
expect(width, 500); // 1000 * 0.5
|
||||
expect(height, 250); // 500 * 0.5
|
||||
});
|
||||
|
||||
test('does not upscale with only height', () {
|
||||
const resizeMode = FitResizeMode(height: 1000);
|
||||
final (width, height) = resizeMode.calculateSize(
|
||||
originalWidth,
|
||||
originalHeight,
|
||||
);
|
||||
expect(width, originalWidth);
|
||||
expect(height, originalHeight);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
Loading…
Reference in New Issue