Future<File> mergeImagesVertically(File front, File back) async {
final img.Image image1 = img.decodeImage(await front.readAsBytes())!;
final img.Image image2 = img.decodeImage(await back.readAsBytes())!;
// Determine max width and combined height
final int finalWidth = max(image1.width, image2.width);
final int finalHeight = image1.height + image2.height;
// Create a new canvas with final dimensions
final img.Image canvas = img.copyExpandCanvas(
image1,
newWidth: finalWidth,
newHeight: finalHeight,
position: img.ExpandCanvasPosition.topLeft,
);
// Place second image below the first one
final img.Image finalImage = img.compositeImage(
canvas,
image2,
dstX: 0,
dstY: image1.height,
);
// Save the final image to local storage
final dir = await getApplicationDocumentsDirectory();
final path = join(dir.path, 'merged_${DateTime.now().millisecondsSinceEpoch}.jpg');
final file = File(path);
await file.writeAsBytes(img.encodeJpg(finalImage));
return file;
}
Isolate
// A simple class to bundle parameters for the isolate function
class MergeImagesArgs {
final String frontPath;
final String backPath;
final String outputPath;
// Constructor
MergeImagesArgs(this.frontPath, this.backPath, this.outputPath);
}
// This function will run in a separate isolate using 'compute'
Future<String> _mergeImagesInIsolate(MergeImagesArgs args) async {
// Load images from file paths
final front = File(args.frontPath);
final back = File(args.backPath);
// Decode image bytes to image objects
final img.Image image1 = img.decodeImage(await front.readAsBytes())!;
final img.Image image2 = img.decodeImage(await back.readAsBytes())!;
// Determine final canvas size
final int finalWidth = max(image1.width, image2.width);
final int finalHeight = image1.height + image2.height;
// Create canvas with enough height to hold both images vertically
final img.Image canvas = img.copyExpandCanvas(
image1,
newWidth: finalWidth,
newHeight: finalHeight,
position: img.ExpandCanvasPosition.topLeft,
);
// Draw the second image below the first one on the canvas
final img.Image finalImage = img.compositeImage(
canvas,
image2,
dstX: 0,
dstY: image1.height,
);
// Save the result to the specified output path
final file = File(args.outputPath);
await file.writeAsBytes(img.encodeJpg(finalImage));
return file.path;
}
// This function is called from the main thread to perform image merge in the background
Future mergeImagesVerticallyInBackground(File frontImage, File backImage) async {
// Define the output path
final dir = await getApplicationDocumentsDirectory();
final outputPath = join(dir.path, 'merged_${DateTime.now().millisecondsSinceEpoch}.jpg');
// Run the merge function in a background isolate using 'compute'
final mergedPath = await compute(
_mergeImagesInIsolate,
MergeImagesArgs(frontImage.path, backImage.path, outputPath),
);
// Return the result as a File
return File(mergedPath);
}