Save uint8list as 24 bit rgb png - flutter

I am creating custom images with flutters canvas and need them to be saved as 24 bit (rgb) pngs without the alpha channel.
I am using the flutter_file_dialog package for the image export.
But the final images are saved in the 32 bit format (rgba).
I have searched the flutter documentation but have not found an easy way to remove the alpha channel.
Would I have to do the removal myself by changing the uint8list?
import 'dart:ui' as ui;
Future<void> createImage() async {
final recorder = ui.PictureRecorder();
const Size size = Size(2000, 2000);
final Rect rect = Rect.fromLTRB(0, 0, size.width, size.height);
final canvas = Canvas(recorder, rect);
// canvas design ...
// capture canvas and save it as image
final picture = recorder.endRecording();
ui.Image newImage = await picture.toImage(size.width.toInt(), size.height.toInt());
ByteData pngBytes = await newImage.toByteData(format: ui.ImageByteFormat.png);
Uint8List uint8list = Uint8List.view(pngBytes.buffer);
// export the image
final params = SaveFileDialogParams(fileName: "image.png", data: uint8list);
final filePath = await FlutterFileDialog.saveFile(params: params);
}

Related

How to convert Image Data type from imageUrl

I need to convert this watermark(from assets) image and imageurl(getting from API) to Image data type, because ui.drawImage takes only Image data types
ui.Image? watermarkImage = ui.decodeImage('assets/images/watermark.png');// getting error
ui.Image? lookbookImage = ui.decodeImage(imageurl); // getting error
final originalImage = imgData;
ui.Image image = ui.Image(160, 50);
ui.drawImage(image, watermarkImage);
First you need to get the image bytes
// network
final response = await http.Client().get(Uri.parse(imageurl));
final bytes = response.bodyBytes;
//assets
final byteData = await rootBundle.load('assets/images/watermark.png');
final bytes = byteData.buffer.asUint8List();
Then you can decode ui.Image from the image bytes
final image = await decodeImageFromList(bytes);

Request for clarification using Canvas() and Paint() in flutter

I use this method for custom markers on a map. I added a custom round background on the marker by using Canvas and Paint and just put those 2 together before returning it back to BitmapDescriptor using code I found which I don't understand very much in depth. I believe that is the reason my background and marker is getting clipped into this square box no matter how I try to adjust it.
My goal is to slightly increase the round background behind the marker. But, it just takes the limits of the marker/icon. If I increase its size, it gets clipped. Also wondering how canvas operations still works even if this class does not have a CustomPainter mixin
class IconLoader {
var vd = VendorDatabase();
late var iconPath;
var convertedIcon;
int iconSize = 200;
Future <BitmapDescriptor?> getIconWithBackground(vendorId) async {
...fetch icon path....
return processIconWithBackground(iconPath, iconSize).then((onValue) async {
return convertedIcon = BitmapDescriptor.fromBytes(onValue!);
});
Future<Uint8List?> processIconWithBackground(String path, int width) async {
final imageData = await rootBundle.load(path); //original code: loads the image into ByteData
// Performs Witchcraft
ui.Codec codec = await ui.instantiateImageCodec(imageData.buffer.asUint8List(), targetWidth: width);
// Something about animation if image is gif? <-- I'm not dealing with animations, how can i get rid of this?
ui.FrameInfo fi = await codec.getNextFrame();
// Converts ByteData to Png format?
var process = (await fi.image.toByteData(format: ui.ImageByteFormat.png))?.buffer.asUint8List();
// finally makes an Image Type Object
final iconImage = await decodeImageFromList(process!);
final pictureRecorder = ui.PictureRecorder(); // starts to record
final canvas = ui.Canvas(pictureRecorder);
canvas.scale(1.5);
_paintCircleStroke(canvas);
final imagePaint = ui.Paint();
canvas.drawImage(iconImage, Offset.zero, Paint());
final drawing = pictureRecorder.endRecording();// ends recording the "drawing"
final image = await drawing.toImage(iconSize.round(), iconSize.round());//converts this drawing to an image
final bytes = await image.toByteData(format: ui.ImageByteFormat.png);
return bytes?.buffer.asUint8List();}
void _paintCircleStroke (ui.Canvas canvas) {
double _circleOffset = iconSize /2;
double _circleStrokeWidth = iconSize / 10;
double _outlineCircleWidth = iconSize /2 ;// (_circleStrokeWidth / 2) ;
// canvas.scale(1.0);
final paint = ui.Paint()
..style = ui.PaintingStyle.fill
..color = ui.Color .fromRGBO(132, 123, 123, 1);
// ..strokeWidth = _circleStrokeWidth;
canvas.drawCircle(ui.Offset(_circleOffset, _circleOffset), _outlineCircleWidth, paint);

Fitting Image inside a circle using canvas flutter

final ui.PictureRecorder pictureRecorder = ui.PictureRecorder();
final Canvas canvas = Canvas(pictureRecorder);
final Paint paint = Paint()..color;
final double radius = size / 2;
final Path clipPath = Path();
clipPath.addRRect(RRect.fromRectAndRadius(
Rect.fromLTWH(0, 0, size.toDouble(), size.toDouble()),
Radius.circular(100)));
canvas.clipPath(clipPath);
final Uint8List imageUint8List =
await (await NetworkAssetBundle(Uri.parse(src)).load(src))
.buffer
.asUint8List();
final ui.Codec codec = await ui.instantiateImageCodec(imageUint8List);
final ui.FrameInfo imageFI = await codec.getNextFrame();
paintImage(
canvas: canvas,
rect: Rect.fromLTWH(0, 0, size.toDouble(), size.toDouble()),
image: imageFI.image);
if (addBorder) {
//draw Border
paint..color = borderColor;
paint..style = PaintingStyle.stroke;
paint..strokeWidth = borderSize;
canvas.drawCircle(Offset(radius, radius), radius, paint);
}
final _image = await pictureRecorder
.endRecording()
.toImage(size, (size * 1.1).toInt());
final rdata = await _image.toByteData(format: ui.ImageByteFormat.png);
The code is as above. Granted I just learned about canvas today I have been trying to piece together code that will fit an image inside a circle to use as a marker for a map. The resultant image however looks like this:
I need it to fit entirely.
Adding
Fit:Boxfit.cover
to my paint image worked. Credits to #spazhead's comment.

how to save my QR generated image into gallery? using Flutter

I am trying to generate an image using RenderRepaintBoundary and want to save the image in my local directory.
I am able to save the image but I get a black image instead of a QR image.
Code block where I am writing the image to the directory:
try {
RenderRepaintBoundary boundary =
globalKey.currentContext.findRenderObject();
var image = await boundary.toImage();
ByteData byteData = await image.toByteData(format: ImageByteFormat.png);
Uint8List pngBytes = byteData.buffer.asUint8List();
final file =
await new File('/<localpath>/image.png').create();
await file.writeAsBytes(pngBytes);
} catch (e) {
print(e);
}
Code block where QR code is being generated:
RepaintBoundary( key: globalKey,child: QrImage(data: _dataString,size: 0.3 * bodyHeight,), );
This is caused by having transparent background;
Simple solution is to wrap your QrImage with Container that has white backround:
Container(
color: Colors.white,
child: QrImage(....
)

How to resize image using multi_image_picker in Flutter?

I'm using multi_image_picker package to pick images and upload to server, but before uploading I want to resize images. I'm trying to accomplish it using dart.ui but having a problem:
//assets is List<Asset> from MultiImagePicker.pickImages
assets.forEach((asset) {
Future<ByteData> byteData = asset.getByteData();
byteData.then((d) async {
List<int> imageData = d.buffer.asUint8List();
String b64 =base64Encode(imageData);
print(b64); // prints [/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE...
//if i send b64 to server then decode it and save as img it's working well
//Resize
ui.instantiateImageCodec(imageData,targetHeight: 800, targetWidth: 600)
.then((codec) {
codec.getNextFrame().then((frameInfo) async {
ui.Image i = frameInfo.image;
ByteData bytes = await i.toByteData();
List<int> resizedImageData = bytes.buffer.asUint8List();
String rb64 = base64Encode(resizedImageData);
print(rb64); // prints too many backslashes:[k5KO/5qWk/+ZlZL/mpaT/5uXlP+alpP/mJSR/5iUkf+YlJH/mZSR/5uWk/+blpP/n5qX/6GcmP+gm5f/oZyY/6GcmP+fmpb/nZi..
//If i send rb64 to server then server cannot decode and save it.
});
});
});
});
This is the function I normally use to resize:
import 'dart:ui' as skia;
Future<skia.Image> resizeImage(String path, {int width, int height}) async {
Uint8List data = await File(path).readAsBytes();
final codec = await skia.instantiateImageCodec(data, targetWidth: width, targetHeight: height);
final frame = await codec.getNextFrame();
return frame.image;
}
As I mentioned in the comment, this is currently not working in Flutter Web but it's due to a bug that will be fixed soon, hopefully.