I am trying to create custom dynamic markers (changes on tap) for my google maps project. Each marker shows a shop with some promotion going on. A single shop can have 3 promotions displayed at the same time and it is supposed to be highlighted if tapped on
I have tried to convert the SVGs for the markers in Canvas code using online tools, but it's bulky and I don't understand it well.
Here's the screenshot for an example screen
Here's the code written for converting theses SVGs to image byte data for use as marker icons
static Future<ByteData?> marker({double? width}) async {
width ??= 88;
double height = width * 1.2247191011235956;
final recorder = ui.PictureRecorder();
final canvas = Canvas(recorder,
Rect.fromPoints(const Offset(0.0, 0.0), const Offset(200.0, 200.0)));
Size size = Size(width, (width * 1.2247191011235956).toDouble());
_paintMarker(size: size, canvas: canvas);
final picture = recorder.endRecording();
final img = await picture.toImage((width).toInt(), height.toInt());
return await img.toByteData(format: ui.ImageByteFormat.png);
}
So I've been trying really hard to crop an image according to my needs in flutter.
Problem statement:
I have a screen and in that screen I show a frame while the device camera is run on the background. Now, what I want is that whenever the user clicks a photo, only the area of that image inside the frame should be kept and rest should be cropped.
What I have done so far?
Added a package image 3.1.3
Wrote code to fetch x,y coordinates of my frame.
Using the calculated x,y coordinates and copyCrop method from the Image package to crop the clicked image.
Now the problem is that I do not know how copyCrop works and the code right now does not give me the expected results.
final GlobalKey _key = GlobalKey();
void _getOffset(GlobalKey key) {
RenderBox? box = key.currentContext?.findRenderObject() as RenderBox?;
Offset? position = box?.localToGlobal(Offset.zero);
if (position != null) {
setState(() {
_x = position.dx;
_y = position.dy;
});
}
}
I assign this _key to my Image.file(srcToFrameImage) and the function above yields 10, 289.125
Here 10 is the offset from x and 289.125 is the offset from y. I used this tutorial for the same.
Code to crop my image using the Image package:
var bytes = await File(pictureFile!.path).readAsBytes();
img.Image src = img.decodeImage(bytes)!;
img.Image destImage = img.copyCrop(
src, _x!.toInt(), _y!.toInt(), src.width, src.height);
var jpg = img.encodeJpg(destImage);
await File(pictureFile!.path).writeAsBytes(jpg);
bloc.addFrontImage(File(pictureFile!.path));
Now, can anyone tell me how i can do this effectively? Right now, it does crop my image but not as I want it to be. It would be really great if someone could tell me how does copyCrop work and what is the meaning of all these different parameters that we pass into it.
Any help would be appreciated.
Edit:
Now, as you can see, i only want the image between this frame to be kept after being captured and rest to be cropped off.
How can I find out the screen size and place my game item according to screen resolution? I want to run my game on the web client.
I want to resize my red game component so fit in the screen and position in center.
LibGdx has some good java class for this concept: Link
You can use the FixedResolutionViewport and set it to the smallest edge if you always want it as a square:
class MyGame extends FlameGame {
Future<void> onLoad() async {
double maxSide = min(size.x, size.y);
camera.viewport = FixedResolutionViewport(Vector2.all(maxSide));
}
}
If you want the game's (viewport) size inside of another component you can add the HasGameRef mixin and use the game's size variable in the same way:
class MyComponent extends Component with HasGameRef {
MyComponent() : super(anchor: Anchor.center);
Future<void> onLoad() async {
final gameSize = gameRef.size;
// To add a position component in the center of the screen for example:
// (when the camera isn't moved)
position = gameSize/2;
}
}
If you want other sizes I recommend to look at game.camera and game.camera.viewport which offers a few other options too.
Thanks in Advance
Currently my app uses camera to take video input and process each frames . The app also works in background for hours. So to avoid heating issues I need to turn the camera off and on it later.
The camera is turned off when I use
_camera.dispose()
but its not turned on after disposing when I use
_camera.initialize()
CameraDescription description = await getCamera(_direction);
ImageRotation rotation = rotationIntToImageRotation(
description.sensorOrientation,
);
_camera =CameraController(description, ResolutionPreset.low, enableAudio: false);
await _camera.initialize();
_camera.startImageStream((CameraImage image) {
_baseStopwatch.start();
if (_baseStopwatch.elapsed.inSeconds > 5) {
_camera.stopImageStream(); }
if (_baseStopwatch.elapsed.inSeconds > 10){
// need to restart the camera streaming!!
}}
I'm taking a photo with the newest camera plugin version and I'm using code from flutter example. This is how I pick a camera:
final cameras = await availableCameras();
final firstCamera = cameras.first;
This is inside init:
_cameraController = CameraController(
widget.camera,
ResolutionPreset.medium,
enableAudio: false,
);
This is the rest of the relevant code:
Future _takePhoto(BuildContext context) async {
try {
await _initializeControllerFuture;
final path = join(
(await getTemporaryDirectory()).path,
'${DateTime.now()}.png',
);
await _cameraController.takePicture(path);
setState(() {
_imagePath = path;
});
} catch (e) {
print(e);
}
}
Afterwards, I show the photo to the user with Image.file(File(_imagePath)) and later I send the photo to API.
The problem is that the photo is sometimes captured with a wrong orientation. (I'm sure about this because the photo is also rotated in the database.) For example, on 3 years old Xiaomi phone, it works flawlessly, but on a certain new Samsung phone, the photo is always rotated.
How to make sure that the rotation is always correct? (Even on ios devices)
This worked for me:
import 'package:image/image.dart' as img;
...
final img.Image capturedImage = img.decodeImage(await File(path).readAsBytes());
final img.Image orientedImage = img.bakeOrientation(capturedImage);
await File(path).writeAsBytes(img.encodeJpg(orientedImage));
This is my solution that works cross-platform and doesn't use plugins.
import 'dart:io';
import 'package:exif/exif.dart';
import 'package:image/image.dart' as img;
Future<File> fixExifRotation(String imagePath) async {
final originalFile = File(imagePath);
List<int> imageBytes = await originalFile.readAsBytes();
final originalImage = img.decodeImage(imageBytes);
final height = originalImage.height;
final width = originalImage.width;
// Let's check for the image size
// This will be true also for upside-down photos but it's ok for me
if (height >= width) {
// I'm interested in portrait photos so
// I'll just return here
return originalFile;
}
// We'll use the exif package to read exif data
// This is map of several exif properties
// Let's check 'Image Orientation'
final exifData = await readExifFromBytes(imageBytes);
img.Image fixedImage;
if (height < width) {
logger.logInfo('Rotating image necessary');
// rotate
if (exifData['Image Orientation'].printable.contains('Horizontal')) {
fixedImage = img.copyRotate(originalImage, 90);
} else if (exifData['Image Orientation'].printable.contains('180')) {
fixedImage = img.copyRotate(originalImage, -90);
} else if (exifData['Image Orientation'].printable.contains('CCW')) {
fixedImage = img.copyRotate(originalImage, 180);
} else {
fixedImage = img.copyRotate(originalImage, 0);
}
}
// Here you can select whether you'd like to save it as png
// or jpg with some compression
// I choose jpg with 100% quality
final fixedFile =
await originalFile.writeAsBytes(img.encodeJpg(fixedImage));
return fixedFile;
}
Source
You can use package https://pub.dev/packages/flutter_exif_rotation
Support iOS and Android
In some devices the exif data shows picture in landscape mode when they're actually in portrait.
This plugin fixes the orientation for pictures taken with those devices.
For Android
Add this in your AndroidManifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
code snippet
image = await FlutterExifRotation.rotateImage(path: image.path);
//Note : iOS not implemented
image = await FlutterExifRotation.rotateAndSaveImage(path: image.path);
if you want to rotate image, you can use https://pub.dev/packages/image to manipulate images:
import 'package:image/image.dart';
If you use package "camera", you can't rotate image (remove mirror effect) using bakeOrientation because don't have exif data.
this works for me using "image_picker" or "camera".
File originalFile = File.fromUri(Uri(path: file.path));
List<int> imageBytes = await originalFile.readAsBytes();
final Image originalImage = decodeImage(imageBytes)!;
final Image orientedImage = flipHorizontal(originalImage);
List<int> imageBytesOrientated = encodeJpg(orientedImage);
For Write in same path:
await File(path).writeAsBytes(imageBytesOrientated);
You can use this package flutter_image_compress to resolve the camera image orientation problem. Note that this approach is faster than using the image package approach.
Use it this way:
import 'package:flutter_image_compress/flutter_image_compress.dart';
........
final fixedImageBytes = await FlutterImageCompress.compressWithFile(
image.path,
rotate: 0,
quality: 100,
keepExif: false,
autoCorrectionAngle: true,
format: CompressFormat.jpeg,
);
Note:
Make sure to set autoCorrectionAngle to true, keepExif to false and rotate to 0
I know this is late, but I just wanna to share how I fix my issue, you can call this function after it's initialized or every time before you take a photo, and here is the code:
await _camCtrl.lockCaptureOrientation(DeviceOrientation.portraitUp);
This fix my issue, somebody says it won't work on iOS, but I haven't test that it, so you can test it out and see if it is compatible with iOS or not.
A bit late to the party. It is really bad idea to ask Flutter to rotate images or similar operations because mobile apps are not designed for these purposes. The only reasonable use case is to ask Flutter to resize the image because you don't want to send a high resolution image to your server over the mobile connection. My solution is send your full size (if you prefer and resize in the back end) or resized images from Flutter to the back end where you can do auto orientation. I use MagickNET lib which is cross platform to do the job and it works perfectly. By doing this, your Flutter code is much cleaner and tidier.
--- VERY SIMPLE SOLUTION ---
import 'package:image/image.dart' as img;
XFile xfile = await _cameraController.takePicture();
List<int> imageBytes = await xfile.readAsBytes();
img.Image? originalImage = img.decodeImage(imageBytes);
img.Image fixedImage = img.flipVertical(originalImage!);
File file = File(xfile.path);
File fixedFile = await file.writeAsBytes(
img.encodeJpg(fixedImage),
flush: true,
);