I want to set an image into an imageView. On portrait orientation it works properly. But when the device has landscape orientation it does not load the image.
The strange thing is, once I rotate it to portrait and back to landscape it shows the image properly.
private void setPhoto(File photoFile) {
readyToDelete=false;
try {
Transformation transformation = new RoundedTransformationBuilder()
.borderColor(Color.parseColor("#757575"))
.borderWidthDp(3)
.cornerRadiusDp(15)
.oval(false)
.build();
Picasso.with(this)
.load(photoFile)
.fit()
.centerInside()
.transform(transformation)
.into(imageView);
imageView.setVisibility(View.VISIBLE);
deleteImageTextView.setVisibility(View.VISIBLE);
addImageTextView.setVisibility(View.GONE);
editScrollView.invalidate();
}
Seems you are running out of memory while loading the image, when in landscape the image is bigger to fit the view.
Try this:
Picasso picasso = new Picasso.Builder(image.getContext())
.listener(new Picasso.Listener() {
#Override
public void onImageLoadFailed(Picasso picasso, Uri uri, Exception exception)
{
Log.e(TAG, "Picasso error:"+exception.getCause().getMessage()+"\n"+uri);
}
})
.build();
then use the picasso instance:
picasso.load(photoFile)....
I recommend you to use a listener when loading, if you have an error, just load the image resizing it to lower resolution, half the screen size for example, let screenSize be the size in pixels of the device screen largest axis:
picasso.load(photoFile).....into(_imageView, new Callback.EmptyCallback(){
#Override
public void onError()
{
picasso.load(photoFile).resize(screenSize/2, screenSize/2).centerInside().transform(transformation).into(imageView);
}
});
anyway the log you get on your listener will give you the clue of what's happening
Related
How can I get my VNCoreMLRequest to detect objects appearing anywhere within the fullscreen view?
I am currently using the Apple sample project for object recognition in breakfast foods:BreakfastFinder. The model and recognition works well, and generally gives the correct bounding box (visual) of the objects it is detecting / finding.
The issue arises here with changing the orientation of this detection.
In portrait mode, the default orientation for this project, the model identifies objects well in the full bounds of the view. Naturally, given the properties of the SDK objects, rotating the camera causes poor performance and visual identification.
In landscape mode, the model behaves strangely. The window / area of which the model is detecting objects is not the full view. Instead, it is (what seems like) the same aspect ratio of the phone itself, but centered and in portrait mode. I have a screenshot below showing approximately where the model stops detecting objects when in landscape:
The blue box with red outline is approximately where the detection stops. It behaves strangely, but consistently does not find any objects outside this approbate view / near the left or right edge. However, the top and bottom edges near the center detect without any issue.
regionOfInterest
I have adjusted this to be the maximum: x: 0, y: 0, width: 1, height: 1. This made no difference
imageCropAndScaleOption
This is the only setting that allows detection in the full screen, however, the performance became noticeably worse, and that's not really an allowable con.
Is there a scale / size setting somewhere in this process that I have not set properly? Or perhaps a mode I am not using. Any help would be most appreciated. Below is my detection controller:
ViewController.swift
// All unchanged from the download in Apples folder
" "
session.sessionPreset = .hd1920x1080 // Model image size is smaller.
...
previewLayer.connection?.videoOrientation = .landscapeRight
" "
VisionObjectRecognitionViewController
#discardableResult
func setupVision() -> NSError? {
// Setup Vision parts
let error: NSError! = nil
guard let modelURL = Bundle.main.url(forResource: "ObjectDetector", withExtension: "mlmodelc") else {
return NSError(domain: "VisionObjectRecognitionViewController", code: -1, userInfo: [NSLocalizedDescriptionKey: "Model file is missing"])
}
do {
let visionModel = try VNCoreMLModel(for: MLModel(contentsOf: modelURL))
let objectRecognition = VNCoreMLRequest(model: visionModel, completionHandler: { (request, error) in
DispatchQueue.main.async(execute: {
// perform all the UI updates on the main queue
if let results = request.results {
self.drawVisionRequestResults(results)
}
})
})
// These are the only properties that impact the detection area
objectRecognition.regionOfInterest = CGRect(x: 0, y: 0, width: 1, height: 1)
objectRecognition.imageCropAndScaleOption = VNImageCropAndScaleOption.scaleFit
self.requests = [objectRecognition]
} catch let error as NSError {
print("Model loading went wrong: \(error)")
}
return error
}
EDIT:
When running the project in portrait mode only (locked by selecting only Portrait in Targets -> General), then rotating the device to landscape, the detection occurs perfectly across the entire screen.
The issue seemed to reside in the rotation of the physical device.
When telling Vision that the device is “not rotated”, but passing all other elements the current orientation, this allowed for the detection bounds to remain the full screen (as if portrait), but allowing the controller to in fact be landscape.
The bounding Boxes are normalised rect which we get from CoreML bounding box observation which we have convert with due ratio of screen to generate boxes in the image for Words
I'm using the Xam.Plugin.Media in my Forms app to take pictures.
I take the Image stream (GetStream) and convert to a byte[] and store in my DB.
I then use that as the image source.
On Android and UWP, its working fine.
On iOS, if the picture is taken in portrait mode, the image once, selected is always rotated 90 deg.
I will later, upload this to a server and that image could be used on a different device.
For this, I also tried the GetStreamWithImageRotatedForExternalStorage but in this case, I cant see the image at all.
There are bytes in the stream (I DisplayAlert the length) but the image does not display.
Any idea what I might be doing wrong?
My code:-
private async Task TakePicture(WineDetails details)
{
await CrossMedia.Current.Initialize();
if (CrossMedia.Current.IsCameraAvailable && CrossMedia.Current.IsTakePhotoSupported)
{
var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
{
AllowCropping = true,
PhotoSize = Plugin.Media.Abstractions.PhotoSize.Medium,
SaveToAlbum = false,
RotateImage = true
});
if (file == null)
return;
using (var ms = new MemoryStream())
{
var stream = file.GetStreamWithImageRotatedForExternalStorage();
stream.CopyTo(ms);
details.LabelImage = ms.ToArray();
details.NotifyChange("ImageSource");
}
}
}
The image is updated in the page via the NotifyChange and looks like this:-
ImageSource.FromStream(() => new MemoryStream(this.LabelImage))
This works fine in all cases on Android and UWP, works on iOS using GetStream (except the image is incorrectly rotated) but does not work using GetStreamWithImageRotatedForExternalStorage on iOS.
Anyone else using this plugin?
Any idea why GetStream returns a rotated image?
Any idea why GetStreamWithImageRotatedForExternalStorage is not working?
Thanks
Update:-
Changed SaveToAlbum = true and when I open the gallery, the image is rotated 90 deg.
Have RotateImage = true which could cause the issue? I'll try setting it to false.
I still can't set the image source to the byte array of the image using GetStreamWithImageRotatedForExternalStorage.
using (var ms = new MemoryStream())
{
file.GetStreamWithImageRotatedForExternalStorage().CopyTo(ms);
details.LabelImage = ms.ToArray();
}
using the byte array for an image
return ImageSource.FromStream(() => new MemoryStream(this.LabelImage));
This does not work for me, GetStream works ok.
Update:-
Ok so, RotateImage = false + GetStreamWithImageRotatedForExternalStorage allows me to display the image but its still incorrectly rotated in my app and the gallery.
I'm using this plugin, which is similar (if not the same thing - I know James Montemagno has recently packaged/bundled his work with Xamarin).
If you check the issues board there, you'll see there are quite a few people that have similar troubles (image rotation on iOS). Almost every 'solution' mentions using GetStreamWithImageRotatedForExternalStorage.
My issue was similar - I was unable to take a photo on iOS in portrait mode, without other (non-ios Devices) rotating the image. I have tried for weeks to solve this issue, but support on the plugin seems to be quite limited.
Ultimately I had to solve this with a huge workaround - using a custom renderer extending from FFImageLoading to display our images and MetadataExtractor. We were then able to extract the EXIF data from the stream and apply a rotation transformation to the FFImageLoding image control.
The rotation information was stored in a sort of weird way, as a string. This is the method I'm using to extract the rotation information, and return the amount it needs to be rotated as an int. Note that for me, iOS was able to display the image correctly still, so it's only returned a rotation change for Android devices.
public static int GetImageRotationCorrection(byte[] image)
{
try
{
var directories = ImageMetadataReader.ReadMetadata(new MemoryStream(image));
if (Device.Android == "Android")
{
foreach (var directory in directories)
{
foreach (var tag in directory.Tags)
{
if (tag.Name == "Orientation")
{
if (tag.Description == "Top, left side(Horizontal / normal)")
return 0;
else if (tag.Description == "Left side, bottom (Rotate 270 CW)")
return 270;
else if (tag.Description == "Right side, top (Rotate 90 CW")
return 90;
}
}
}
}
return 0;
}
catch (Exception ex)
{
return 0;
}
}
Note that there is also a custom renderer for the image for FFImage Loading.
public class RotatedImage : CachedImage
{
public static BindableProperty MyRotationProperty = BindableProperty.Create(nameof(MyRotation), typeof(int), typeof(RotatedImage), 0, propertyChanged: UpdateRotation);
public int MyRotation
{
get { return (int)GetValue(MyRotationProperty); }
set { SetValue(MyRotationProperty, value); }
}
private static void UpdateRotation(BindableObject bindable, object oldRotation, object newRotation)
{
var _oldRotation = (int)oldRotation;
var _newRotation = (int)newRotation;
if (!_oldRotation.Equals(_newRotation))
{
var view = (RotatedImage)bindable;
var transformations = new System.Collections.Generic.List<ITransformation>() {
new RotateTransformation(_newRotation)
};
view.Transformations = transformations;
}
}
}
So, in my XAML - I had declared a RotatedImage instead of the standard Image. With the custom renderer, I'm able to do this and have the image display rotated the correct amount.
image.MyRotation = GetImageRotationCorrection(imageAsBytes)
It's a totally unnecessary workaround - but these are the lengths that I had to go to to get around this issue.
I'll definitely be following along with this question, there might be someone in the community who could help us both!
The SaveMetaData flag is causing the rotation issue.
Setting it to false (default is true) now displays the photo correctly.
One side effect of that, the image no longer appears in the gallery if SaveToAlbum=true.
Still can't use an image take when using GetStreamWithImageRotatedForExternalStorage, even using FFImageLoading.
I found that while using Xam.Plugin.Media v5.0.1 (https://github.com/jamesmontemagno/MediaPlugin), the combination of three different inputs produced different results on Android vs. iOS:
StoreCameraMediaOptions.SaveMetaData
StoreCameraMediaOptions.RotateImage
Using MediaFile.GetStream() vs. MediaFile.GetStreamWithImageRotatedForExternalStorage()
On Android, SaveMetaData = false, RotateImage = true, and using MediaFile.GetStreamWithImageRotatedForExternalStorage() worked for me whether I was saving the result stream externally or processing the result stream locally for display.
On iOS, the combination of RotateImage = true and StreamRotated = true would result in a NullReferenceException coming out of the plugin library. Using MediaFile.GetStreamWithImageRotatedForExternalStorage() appeared to have no impact on behaivor.
--
Before going further, it's important to understand that image orientation in the JPEG format (which Xam.Plugin.Media seems to use) isn't as straightforward as you might think. Rather than rotating the raw image bytes 90 or 180 or 270 degrees, JPEG orientation can be set through embedded EXIF metadata. Orientation issues will happen with JPEGs either if EXIF data is stripped or if downstream consumers don't handle the EXIF data properly.
The approach I landed on was to normalize JPEG image orientation at the point the image is captured without relying on EXIF metadata. This way, downstream consumers shouldn't need to be relied on to properly inspect and handle EXIF orientation metadata.
The basic solution is:
Scan a JPEG for EXIF orientation metadata
Transform the JPEG to rotate/flip as needed
Set the result JPEG's orientation metadata to default
--
Code example compatible with Xamarin, using ExifLib.Standard (1.7.0) and SixLabors.ImageSharp (1.0.4) NuGet packages. Based on (Problem reading JPEG Metadata (Orientation))
using System;
using System.IO;
using ExifLib;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.Processing;
namespace Your.Namespace
{
public static class ImageOrientationUtility
{
public static Stream NormalizeOrientation(Func<Stream> inputStreamFunc)
{
using Stream exifStream = inputStreamFunc();
using var exifReader = new ExifReader(exifStream);
bool orientationTagExists = exifReader.GetTagValue(ExifTags.Orientation, out ushort orientationTagValue);
if (!orientationTagExists)
// You may wish to do something less aggressive than throw an exception in this case.
throw new InvalidOperationException("Input stream does not contain an orientation EXIF tag.");
using Stream processStream = inputStreamFunc();
using Image image = Image.Load(processStream);
switch (orientationTagValue)
{
case 1:
// No rotation required.
break;
case 2:
image.Mutate(x => x.RotateFlip(RotateMode.None, FlipMode.Horizontal));
break;
case 3:
image.Mutate(x => x.RotateFlip(RotateMode.Rotate180, FlipMode.None));
break;
case 4:
image.Mutate(x => x.RotateFlip(RotateMode.Rotate180, FlipMode.Horizontal));
break;
case 5:
image.Mutate(x => x.RotateFlip(RotateMode.Rotate90, FlipMode.Horizontal));
break;
case 6:
image.Mutate(x => x.RotateFlip(RotateMode.Rotate90, FlipMode.None));
break;
case 7:
image.Mutate(x => x.RotateFlip(RotateMode.Rotate270, FlipMode.Horizontal));
break;
case 8:
image.Mutate(x => x.RotateFlip(RotateMode.Rotate270, FlipMode.None));
break;
}
image.Metadata.ExifProfile.SetValue(ExifTag.Orientation, (ushort)1);
var outStream = new MemoryStream();
image.Save(outStream, new JpegEncoder{Quality = 100});
outStream.Position = 0;
return outStream;
}
}
}
And to use in conjunction with Xam.Plugin.Media:
MediaFile photo = await CrossMedia.Current.TakePhotoAsync(options);
await using Stream stream = ImageOrientationUtility.NormalizeOrientation(photo.GetStream);
I have tried creating a game in unity and build it on ios on any apple devices there were no problem except on iphone x. Screenshot is below.enter image description here. It was covered by the iphone x notch and then when when the character is on the left or the right side it was cut it half.Is there any other solution or a plugin we can use to solve the issue ?. Is there a unity settins or xcode settings to that ? .Thank You
About the iPhone X notch, you can use this:
Screen.safeArea
It is a convenient way to determine the screen actual "Safe Area". Read more about it in this thread.
About the character cutting in half, this is probably something you need to take care of manually based on your game logic. By getting the Screen.width - you should be able to either adjust the Camera (zoom out) or limit the character movement in a way that it will not get past the screen edge.
For the iPhone X and other notched phones you can use the generic Screen.safeArea provided by Unity 2017.2.1+. Attach the script below to a full screen UI panel (Anchor 0,0 to 1,1; Pivot 0.5,0.5) and it will shape itself to the screen safe.
Also recommended to have your Canvas set to "Scale With Screen Size" and "Match (Width-Height)" = 0.5.
public class SafeArea : MonoBehaviour
{
RectTransform Panel;
Rect LastSafeArea = new Rect (0, 0, 0, 0);
void Awake ()
{
Panel = GetComponent<RectTransform> ();
Refresh ();
}
void Update ()
{
Refresh ();
}
void Refresh ()
{
Rect safeArea = GetSafeArea ();
if (safeArea != LastSafeArea)
ApplySafeArea (safeArea);
}
Rect GetSafeArea ()
{
return Screen.safeArea;
}
void ApplySafeArea (Rect r)
{
LastSafeArea = r;
Vector2 anchorMin = r.position;
Vector2 anchorMax = r.position + r.size;
anchorMin.x /= Screen.width;
anchorMin.y /= Screen.height;
anchorMax.x /= Screen.width;
anchorMax.y /= Screen.height;
Panel.anchorMin = anchorMin;
Panel.anchorMax = anchorMax;
}
}
For a more in depth breakdown, I've written a detailed article with screenshots here: https://connect.unity.com/p/updating-your-gui-for-the-iphone-x-and-other-notched-devices. Hope it helps!
Sorry for the late answer but I have adjusted the camera's viewport rectangle for iOS devices and it works correctly. Check if it works for your camera as well.
I have tried safeArea and other script based solutions which do not seem to work.
#if UNITY_IPHONE
mainCamera.rect = new Rect(0.06f, 0.06f, 0.88f, 1);
#endif
Could someone tell me how to catch this event?
Because when I rotated the phone to landscape mode, the app could not display correctly.
Thanks,
Duy
When this happens then BB UI framework definitelly calls layout(int width, int height) for your screen. This is because MainScreen is also a Manager, so it should layout all its child fields before BB UI framework starts painting.
So in layout() you could track current orientation state (with net.rim.device.api.system.Display.getOrientation()) and compare with the previous one. If it is changed, then the device has just been rotated.
I've come up with a method different to the suggested by Arhimed and it seems to work well (I use it to draw a custom Field differently - when the device is tilted). I have a method
protected void myOrientation() {
// portrait is true when dh > dw
boolean portrait = (Display.getOrientation() == Display.ORIENTATION_PORTRAIT);
// dw and dh = real horizontal and vertical dimensions of display - regardless of device orientation
int dw = portrait ? Math.min(Display.getWidth(), Display.getHeight()) : Math.max(Display.getWidth(), Display.getHeight());
int dh = portrait ? Math.max(Display.getWidth(), Display.getHeight()) : Math.min(Display.getWidth(), Display.getHeight());
// here I draw my custom Field
invalidate();
}
and call it once in the constructor and after that it is called on every Accelerometer event:
public class MyScreen extends MainScreen implements AccelerometerListener {
private MyScreen() {
if (AccelerometerSensor.isSupported()) {
orientationChannel = AccelerometerSensor.openOrientationDataChannel( Application.getApplication() );
orientationChannel.addAccelerometerListener(this);
}
....
}
public void onData(AccelerometerData accData) {
if (old != accData.getOrientation()) {
myField.myOrientation();
}
}
Maybe this helps you and yes - you have to check, if the keyboard is slided out on Torch
Regards
Alex
I am working on an eBook app where I need to transition the screens from left to right and right to left. I tried many samples that I've found, but I am not successful. How do I change the screen frequently when user clicks on the screen from left to right and right to left. What is the basic idea for transition of pages. I went through the Developer Support Forum thread "page-flip effect" looking for a solution, but I can't see it.
The following code is not logical. In which position do I have to implement flip effect for flipping pages in the screen and how to implement it?
public class TransitionScreen extends FullScreen implements Runnable{
private int angle = 0;
Bitmap fromBmp,toBmp;
public TransitionScreen(){
}
public TransitionScreen(AnimatableScreen from,AnimatableScreen to) {
fromBmp = new Bitmap(Display.getWidth(), Display.getHeight());
toBmp = new Bitmap(Display.getWidth(), Display.getHeight());
Graphics fromGraphics = Graphics.create(fromBmp);
Graphics toGraphics = Graphics.create(toBmp);
Object eventLock = getApplication().getEventLock();
synchronized(eventLock) {
from.drawAnimationBitmap(fromGraphics);
to.drawAnimationBitmap(toGraphics);
// Interpolate myOffset to target
// Set animating = false if myOffset = target
invalidate();
}
try {
synchronized (Application.getEventLock()) {
Ui.getUiEngine().suspendPainting(true);
}
} catch (final Exception ex) {
}
}
protected void paint(Graphics g){
//control x,y positions of the bitmaps in the timer task and the paint will just paint where they go
g.drawBitmap(0,0, 360,
480, toBmp, 0, 0);
g.drawBitmap(0, 0, 360,
480, fromBmp, 0, 0);
// invalidate();
}
protected boolean touchEvent(TouchEvent event) {
if (!this.isFocus())
return true;
if (event.getEvent() == TouchEvent.CLICK) {
// invalidate();
}
return super.touchEvent(event);
}
}
Assuming you're working with version 5.0 or later of the OS, this page has a simple example:
http://docs.blackberry.com/en/developers/deliverables/11958/Screen_transitions_detailed_overview_806391_11.jsp
From where did you get the code sample posted in your question? That code does not appear to be close to working.
Update: you can actually animate transitions like this yourself fairly simply. Assuming you know how to use the Timer class, you basically have a class-level variable that stores the current x-position of your first Bitmap (the variable would have a value of 0 initially). In each timer tick, you subtract some amount from the x-position (however many pixels you want it to move each tick) and then call invalidate();.
In each call to the paint method, then, you just draw the first bitmap using the x-position variable for the call's x parameter, and draw the second bitmap using the x-position variable plus the width of the first bitmap. The resulting effect is to see the first bitmap slide off to the left while the second slides in from the right.
A caveat : Because this is java (which means the timer events are not real-time - they're not guaranteed to occur when you want them to), this animation will be kind of erratic and unsmooth. The best way to get smooth animation like this is to pre-render your animation cells (where each is a progressive combination of the two bitmaps you're transitioning between), so that in the paint method you're just drawing a single pre-rendered bitmap.