Skip to content

Instantly share code, notes, and snippets.

@karnadii
Last active February 24, 2024 03:24
Show Gist options
  • Save karnadii/53aae844b8fb110bf8651d261324e5e9 to your computer and use it in GitHub Desktop.
Save karnadii/53aae844b8fb110bf8651d261324e5e9 to your computer and use it in GitHub Desktop.
Crop a white border of an image
// ignore_for_file: avoid_print
// Import necessary libraries
import 'dart:io';
import 'package:image/image.dart' as img;
// Main function
void main(List<String> args) async {
// Check if the path to the image file and the color of the border to remove are provided
if (args.length < 2) {
print("Please provide the path to the image file and the color of the border to remove (white or black)");
return;
}
// Start the timer
final startTime = DateTime.now();
// Read the image file
final String filePath = args[0];
final String borderColor = args[1].toLowerCase();
// Decode the image
img.Image? image;
img.Image? unfilteredImage;
await img.decodeImageFile(filePath).then((value) {
image = value;
}).catchError((e) {
print("Failed to decode image: $e");
});
await img.decodeImageFile(filePath).then((value) {
unfilteredImage = value;
}).catchError((e) {
print("Failed to decode image: $e");
});
// Set contrast and threshold values
final int contrast = args.length > 2 ? int.tryParse(args[2]) ?? 200 : 200;
final int threshold = args.length > 3
? int.tryParse(args[3]) ?? (borderColor == 'white' ? 240 : 15)
: (borderColor == 'white' ? 240 : 15);
// Convert image to grayscale then increase contrast
final contrastedImage = img.contrast(img.grayscale(image!), contrast: contrast);
List<Future<int>> boundaryFutures = [
Future<int>(() => findBoundary(contrastedImage, 'top', borderColor, threshold)),
Future<int>(() => findBoundary(contrastedImage, 'bottom', borderColor, threshold)),
Future<int>(() => findBoundary(contrastedImage, 'left', borderColor, threshold)),
Future<int>(() => findBoundary(contrastedImage, 'right', borderColor, threshold)),
];
List<int> boundaries = await Future.wait(boundaryFutures);
final int top = boundaries[0];
final int bottom = boundaries[1];
final int left = boundaries[2];
final int right = boundaries[3];
// Crop the image
await cropAndSaveImage(unfilteredImage!, "./cropped_image.jpg", left, top, right - left, bottom - top);
// Print the time taken
final endTime = DateTime.now();
print("Time taken: ${endTime.difference(startTime).inMilliseconds}ms");
}
Future<img.Image> cropAndSaveImage(img.Image image, String path, int x, int y, int width, int height) async {
try {
// Check if the cropping parameters are within the image boundaries
if (x < 0 || y < 0 || x + width > image.width || y + height > image.height) {
throw ArgumentError('Cropping parameters are out of image boundaries.');
}
// Crop the image
final croppedImage = img.copyCrop(image, x: x, y: y, width: width, height: height);
// Write the cropped image to a file
await File(path).writeAsBytes(img.encodeJpg(croppedImage));
print('Image saved to $path');
return croppedImage;
} catch (e) {
if (e is FileSystemException) {
print('Failed to write file: $e');
} else {
print('An error occurred while cropping or saving the image: $e');
}
rethrow;
}
}
int findBoundary(img.Image image, String direction, String borderColor, [int threshold = 240]) {
bool Function(img.Pixel) isBorderPixel;
if (borderColor == 'white') {
isBorderPixel = (img.Pixel pixel) => isWhite(pixel, threshold);
} else if (borderColor == 'black') {
isBorderPixel = (img.Pixel pixel) => isBlack(pixel, threshold);
} else {
throw ArgumentError('Invalid border color: $borderColor. Expected "white" or "black".');
}
if (direction == 'top') {
for (int y = 0; y < image.height; y++) {
for (int x = 0; x < image.width; x++) {
if (!isBorderPixel(image.getPixel(x, y))) {
return y;
}
}
}
} else if (direction == 'bottom') {
for (int y = image.height - 1; y >= 0; y--) {
for (int x = 0; x < image.width; x++) {
if (!isBorderPixel(image.getPixel(x, y))) {
return y;
}
}
}
} else if (direction == 'left') {
for (int x = 0; x < image.width; x++) {
for (int y = 0; y < image.height; y++) {
if (!isBorderPixel(image.getPixel(x, y))) {
return x;
}
}
}
} else if (direction == 'right') {
for (int x = image.width - 1; x >= 0; x--) {
for (int y = 0; y < image.height; y++) {
if (!isBorderPixel(image.getPixel(x, y))) {
return x;
}
}
}
}
return 0;
}
// Function to check if a pixel is white
bool isWhite(img.Pixel pixel, [int threshold = 240]) {
final r = pixel.r;
final g = pixel.g;
final b = pixel.b;
// Check if the RGB values of the pixel are above the threshold
return r > threshold && g > threshold && b > threshold;
}
// Function to check if a pixel is black
bool isBlack(img.Pixel pixel, [int threshold = 15]) {
final r = pixel.r;
final g = pixel.g;
final b = pixel.b;
// Check if the RGB values of the pixel are below the threshold
return r < threshold && g < threshold && b < threshold;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment