Skip to content

Instantly share code, notes, and snippets.

@LokieVikky
Created March 7, 2023 11:57
Show Gist options
  • Save LokieVikky/6d271de9fd7375eda5282a468f57cbf9 to your computer and use it in GitHub Desktop.
Save LokieVikky/6d271de9fd7375eda5282a468f57cbf9 to your computer and use it in GitHub Desktop.
import 'dart:io';
import 'dart:math';
import 'package:flutter/material.dart';
import 'dart:ui' as ui;
enum Sequence { rotate, crop, delete, straighten,drawImage,drawFrame }
enum Units { cm, inch }
enum ImageRotation {
rotate90,
rotate180,
rotate270,
}
class DeleteArea {
Rect rect;
Paint paint;
DeleteArea(this.rect, this.paint);
}
class FrameInsets {
double left = 0.0;
double top = 0.0;
double right = 0.0;
double bottom = 0.0;
FrameInsets.all(double value)
: left = value,
top = value,
right = value,
bottom = value;
FrameInsets.only({
this.left = 0.0,
this.top = 0.0,
this.right = 0.0,
this.bottom = 0.0,
});
}
class ImageFrame {
Paint paint;
FrameInsets frame;
Units unit;
ImageFrame(this.paint, this.frame, this.unit);
}
class ImageEditor {
double imageHeight = 0.0;
double imageWidth = 0.0;
Future<ui.Image> edit({
required String srcPath,
List<DeleteArea> areasToDelete = const [],
ImageFrame? imageFrame,
Rect? areaToCrop,
ColorFilter? colorFilter,
ImageRotation? imageRotation,
double? straightenAngle,
List<Sequence> sequence = const [Sequence.rotate, Sequence.crop, Sequence.delete],
}) async {
try {
ui.Image image;
File file = File(srcPath);
ui.Codec codec = await ui.instantiateImageCodec(await file.readAsBytes());
ui.FrameInfo frame = await codec.getNextFrame();
image = frame.image;
imageHeight = image.height.toDouble();
imageWidth = image.width.toDouble();
// Start Recording
ui.PictureRecorder pr = ui.PictureRecorder();
Canvas c = Canvas(pr);
for (Sequence s in sequence) {
switch (s) {
case Sequence.rotate:
rotate(c, imageRotation);
break;
case Sequence.crop:
crop(c, image, colorFilter, areaToCrop);
break;
case Sequence.delete:
deleteSelection(c, areasToDelete);
break;
case Sequence.straighten:
straighten(c, straightenAngle);
break;
case Sequence.drawImage:
c.drawImage(image, Offset.zero, Paint()..colorFilter = colorFilter);
break;
case Sequence.drawFrame:
drawFrame(c, imageFrame);
break;
}
}
if (imageRotation != null) {
if (imageRotation == ImageRotation.rotate90 || imageRotation == ImageRotation.rotate270) {
return pr.endRecording().toImage(imageHeight.toInt(), imageWidth.toInt());
}
return pr.endRecording().toImage(imageWidth.toInt(), imageHeight.toInt());
}
return pr.endRecording().toImage(imageWidth.toInt(), imageHeight.toInt());
} catch (e) {
rethrow;
}
}
void straighten(Canvas c, double? angle) {
if (angle == null) {
return;
}
if (angle < -45 || angle > 45) {
throw Exception("Straighten angle can only range from -45 to +45");
}
var radians = angle * pi / 180;
final double r = sqrt(imageWidth * imageWidth + imageHeight * imageHeight) / 2;
double alpha;
double beta;
double shiftY;
double shiftX;
double translateX;
double translateY;
alpha = atan(imageHeight / imageWidth);
beta = alpha + radians;
shiftY = r * sin(beta);
shiftX = r * cos(beta);
translateX = imageWidth / 2 - shiftX;
translateY = imageHeight / 2 - shiftY;
// if (angle == 90 || angle == 270) {
// translateX = imageHeight / 2 - shiftX;
// translateY = imageWidth / 2 - shiftY;
// } else {
// translateX = imageWidth / 2 - shiftX;
// translateY = imageHeight / 2 - shiftY;
// }
c.translate(translateX, translateY);
c.rotate(radians);
}
void deleteSelection(Canvas c, List<DeleteArea> areasToDelete) {
for (DeleteArea element in areasToDelete) {
c.drawRect(
element.rect,
element.paint,
);
}
}
void drawFrame(Canvas c, ImageFrame? imageFrame) {
if (imageFrame != null) {
double leftPixels = _unitToPixel(imageFrame.unit, imageFrame.frame.left);
double topPixels = _unitToPixel(imageFrame.unit, imageFrame.frame.top);
double rightPixels = _unitToPixel(imageFrame.unit, imageFrame.frame.right);
double bottomPixels = _unitToPixel(imageFrame.unit, imageFrame.frame.bottom);
Rect leftRect = Rect.fromLTWH(0.0, 0.0, leftPixels, imageHeight);
Rect topRect = Rect.fromLTWH(0.0, 0.0, imageWidth, topPixels);
Rect rightRect = Rect.fromLTWH(imageWidth - rightPixels, 0.0, rightPixels, imageHeight);
Rect bottomRect = Rect.fromLTWH(0.0, imageHeight - bottomPixels, imageWidth, bottomPixels);
c.drawRect(leftRect, imageFrame.paint);
c.drawRect(topRect, imageFrame.paint);
c.drawRect(rightRect, imageFrame.paint);
c.drawRect(bottomRect, imageFrame.paint);
}
}
void crop(Canvas c, ui.Image image, ColorFilter? colorFilter, Rect? areaToCrop) {
if (areaToCrop != null) {
imageHeight = areaToCrop.height;
imageWidth = areaToCrop.width;
c.drawImageRect(
image,
areaToCrop,
Rect.fromPoints(Offset.zero, Offset(areaToCrop.width, areaToCrop.height)),
Paint()..colorFilter = colorFilter);
}
}
void rotate(Canvas c, ImageRotation? imageRotation) {
// Rotate
if (imageRotation != null) {
int angle;
switch (imageRotation) {
case ImageRotation.rotate90:
angle = 90;
break;
case ImageRotation.rotate180:
angle = 180;
break;
case ImageRotation.rotate270:
angle = 270;
break;
}
var radians = angle * pi / 180;
final double r = sqrt(imageWidth * imageWidth + imageHeight * imageHeight) / 2;
double alpha;
double beta;
double shiftY;
double shiftX;
double translateX;
double translateY;
alpha = atan(imageHeight / imageWidth);
beta = alpha + radians;
shiftY = r * sin(beta);
shiftX = r * cos(beta);
if (angle == 90 || angle == 270) {
translateX = imageHeight / 2 - shiftX;
translateY = imageWidth / 2 - shiftY;
} else {
translateX = imageWidth / 2 - shiftX;
translateY = imageHeight / 2 - shiftY;
}
c.translate(translateX, translateY);
c.rotate(radians);
}
}
double _unitToPixel(Units unit, double value) {
switch (unit) {
case Units.cm:
return cmToPixel(cm: value);
case Units.inch:
return inchToPixel(inch: value);
}
}
double cmToPixel({required double cm, int dpi = 96}) => (dpi / 2.54) * cm;
double inchToPixel({required double inch, int dpi = 96}) => inch * dpi;
Offset findActualOffset(Offset offset, Size widgetSize, Size imageSize) {
return Offset(((offset.dx / widgetSize.width) * 100) * imageSize.width,
((offset.dy / widgetSize.height) * 100) * imageSize.height);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment