I am developing an app to do a lot of tasks related to images and PDF files. In one of the features I am converting images to PDF. I have encountered a few problems while handling images with bitmap.
1) When I am creating PDF file with images that I clicked using my phone's camera, for some reason they get rotated 90 degrees anti-clockwise automatically. When I am clicking the image, I used portrait mode, the image gets saved in my phone's gallery in portrait mode. When I view it in my phone's gallery it gets displayed correctly but when I load it in ImageView in Android Studio, it shows me a 90 degree anti-clockwise rotated image.
I am using the code below to load images in ImageView:
File file = new File(imagez.get(position));
Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
imageView.setImageBitmap(bitmap);
Here, "imagez" is an array that contains path to all images that are selected by the user in String format. e.g., "/storage/emualted/0/pics/...." like that.
This problem is only with images that I clicked using my phone's camera, other images that I downloaded from internet or from WhatsApp or Facebook all works fine.
2) My second problem is that when I scroll the PDF that I created, the images there loads slowly. The PDF creation is completed, the images should be there all time instead they load every time as I scroll up and down as if I am using an Adapter View to inflate a List View where non-visible items gets destroyed as they move out of the view and gets loaded again when I scroll back up.
I am using itextpdf class for converting images to PDF.
EDIT :
My question is that I want the image to be displayed in the orientation it was clicked, and when I am creating the PDF, the image should be saved as original (it should not get rotated automatically).
And I also a solution to make my created PDF load the pages quickly, if it can be done.
Thank you.
The problem that you are having is a common issue. I would suggest you to try the following method:
int orientation = 0;
ExifInterface exif = new ExifInterface(path_to_your_image);
orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0);
if(orientation != 0)
{
Matrix rotateMatrix = new Matrix();
if (orientation == 6)
rotateMatrix.postRotate(90);
else if (orientation == 3)
rotateMatrix.postRotate(180);
else if (orientation == 8)
rotateMatrix.postRotate(270);
else
rotateMatrix.postRotate(0);
Bitmap newBitmap = Bitmap.createBitmap(previous_bitmap, 0, 0, previous_bitmap.getWidth(), previous_bitmap.getHeight(), rotateMatrix, false);
}
else
{
Bitmap newBitmap = Bitmap.createBitmap(previous_bitmap, 0, 0, previous_bitmap.getWidth(), previous_bitmap.getHeight);
}
//After this you can save your bitmap wherever you want
As far as your second problem is concerned I guess your images are too big. Try decreasing their size or dimensions to say 1200x1200 or whatever you feel right.
Hope it helps!
Related
I have this code to preview an image loaded from the phone, the problem is when I use camera to take image and load it to my app it gets rotated 90 degrees. What could be causing this behavior? This is my code:
private void addImageToGrid(String selectedImageUri) {
Bitmap bitmap = getBitmapFromPath(selectedImageUri);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
int bitmapWidth = 90;//bitmap.getScaledWidth(density);
int bitmapHeight = 80;// bitmap.getScaledWidth(density);
ImageItem imageItem = new ImageItem();
imageItem.setImage(Bitmap.createScaledBitmap(bitmap, bitmapWidth, bitmapHeight, false));
imageItem.setUri(selectedImageUri);
gridViewAdapter.add(imageItem);
}
While some android devices (or camera apps) really produce a bitmap corresponding to the device orientation (i.e. landscape vs portrait) others always use a landscape bitmap and only put the orientation information into the EXIF data packed into the JPEG file. It depends then on the viewer if the image is displayed correctly or not.
Because some devices will auto rotate the camera, some devices will use only portrait other only landscape you have to check the image what you select is it portrait or it is landscape by verify width and height.
So first check the Bitmap bitmap orientation and apply a rotation like this:
enter link description here
Okay,
I have what I think is an odd problem.
I load photos into a list view as the user scroll (meaning if picked up from disk or online, it takes a little time and they "pop in")
1)
I ensure that I only fetch one image online + resize to 1/3 width at a time (a lock) -- this is to ensure not e.g. 5 threads each are converting a .jpg to bitmap at the same time. (Imagine a user scrolling very fast, it would then be conceivable this could happen.)
2)
All images on disk are only 1/3 width
3)
While the bitmaps are scaled up to fit device width, I call recycle and set bitmaps to null when used in the getView. (I am converting bitmaps to a BitmapDrawable object which the listitem imageview uses in a setImageDrawable call)
4)
I reuse view in getView if not null
5)
I load bitmaps like this:
BitmapFactory.Options o = new BitmapFactory.Options();
o.inPurgeable = false; // I do not use this since I resize/scale down images myself later
o.inInputShareable = false;
o.inPreferredConfig = Config.RGB_565;
res.bitmap = BitmapFactory.decodeStream(is, null, o);
6)
I also clean scrap items
public void onMovedToScrapHeap(View view) {
final TextView description = (TextView)view.findViewById(R.id.listitem_news_content);
description.setText("");
final ImageView image = (ImageView)view.findViewById(R.id.listitem_news_image);
image.setImageBitmap(null);
}
I am testing on a Samsung Galaxy II. Do you guys have any ideas on what more I could try? Since I only max need to show 10 items, I would think it should be possible...
Try using widely used library Universal Image Loader https://github.com/nostra13/Android-Universal-Image-Loader
It is simple and straight forward and you will never have to care about decoding images yourself.
Option two: There's a powerful new API for loading image is available from the team of Square http://square.github.io/picasso/
Try this, it worked for me in case of OutOfMemory...using System.gc()
bitmap = null;
imageView.setImageBitmap(null);
System.gc();
I am using html, tag:
<input type = "file" />
On android and on many cellulars I have the ability to get the file directly by taking a picture and save it.
How can I know (by javascript code) how did I get the picture (direcly by the camera, or by some files that on my cellular)?
I did some workarround, and found exif (http://www.nihilogic.dk/labs/exif/exif.js), but I didn't succeed using it for images loading dynamically, as the site : http://exif-viewer.com/
Need some source code examples, to understand how exif works on dynamically loaded images.
Thanks :)
I have found the solution by myself, so I want to participate it:
What I needed is translate the binary data to exif data,
so on exif.js, I added the following.
jQuery.fn.getExif = function() {
var exif;
var bin;
var bf;
bin = atob(this.attr("src").split(',')[1]);
if (bin) {
bf = new BinaryFile(bin);
}
if (bf) {
exif = EXIF.readFromBinaryFile(bf);
}
if (exif) {
this.attr("exifdata", exif);
}
return exif;
}
and use the above on code - just get any exif value I want.
The main issue is that the image should be rotated according to exif
(if, i.e. the orientation is 90 degrees clockwise, so I should rotate 90 counterclockwise, in order to fix the orientation) - No problem on most devices,
but there is a problem that persists on several devices, such as IPAD.
IPAD (or Safari - I don't know exactly where might be the problem) do me a favour, and auto rotate the image, when I am loading it from file, so it is displayed always correctly.
Now how can I know when to rotate the image and when not rotating it.
Thanks :)
Currently im making an app to show images from SD card. Basicly you make an album and add pictures to it, be it from camera of the MediaStore picker.
I tried implementing 2 methods:
The standard gallery app with a custom BaseAdapter to return a view
A viewpager with custom PagerAdapter
I dont want to display a grid view, so it should go fullscreen right away. After that i want to disable swipe left and right and only listen for clicks.
Atm both methods work in portrait mode. When i switch over to landscape some images just drop
03-20 12:20:56.515: W/OpenGLRenderer(17398): Bitmap too large to be uploaded into a texture
followed by Out of memory errors. Stack overflow if full with problems about the OOM and the gallery, you should recycle the views to make them work because convertView is always null in the getView from BaseAdapter.
So i used a recycler for the views, i limit it to 2 views and portrait mode worked for method 1 (using the gallery). Landscape still gives me the same problem.
For method 2 (viewflipper) it handles the views by
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
Wich is never called btw... However portrait mode works here. Landscape still crashes.
My method for getting the bitmap:
public static Bitmap getBitmap(Context ctx, int imageId, ImageView target) {
String file = getPath(ctx, imageId);
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(file, bmOptions);
WindowManager mgr = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE);
int scaleFactor = 1;
if (mgr != null) {
// Get the dimensions of the View
int targetW = mgr.getDefaultDisplay().getWidth();
int targetH = mgr.getDefaultDisplay().getHeight();
Log.d(TAG, "Image width + height=" + targetW + "," + targetH);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
// Determine how much to scale down the image
scaleFactor = Math.min(photoW / targetW, photoH / targetH);
} else {
Log.d(TAG, "Target is null");
}
// Get the dimensions of the bitmap
// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
logHeap(ImageHelper.class);
Bitmap bm = BitmapFactory.decodeFile(file, bmOptions);
if (target != null) {
target.setImageBitmap(bm);
}
return bm;
}
Works fine, i know i use the window manager to get a screensize but that is because my ImageView is still size(0,0) when i inflate it. Afterwards i call
imgView.setLayoutParams(new Gallery.LayoutParams(
Gallery.LayoutParams.FILL_PARENT,
Gallery.LayoutParams.FILL_PARENT));
imgView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
Nothing seems to work...
Please note that i dont use drawables or any other resources included in the APK.
This gallery should be able to load pictures from SD card or from camera in whatever quality they were taken. Obvously the gallery should be able to handle as much images as there are in the directory.
Could someone please help me out with the following questions?
Is there any way to make the default Gallery go fullscreen right away and block out the grid view? This way i only need an adapter to provide images instead of making my own views. (maybe this solves the OOM crashes)
Is my Bitmap decoding function ok? Do i need to built in some hacks to catch the landscape changes?
Whats the best way to make the kind of gallery i need, using a viewpager or the gallery?
Does anyone have some sample code of a fullscreen gallery that doesnt crash?
This is an issue i faced a few times in the past. Google actually posted an article about this.
The problem is in the inSampleSize that u use to decode the image. Since different devices have different screens and memory sizes (VM Heap Sizes that may go from 12 to 64 or more Mb) you cant decode the images the same way in all of them. For example, an image in a 320x240 device with a 12Mb Heap Memory should u a given inSampleSize while a 1280x720 64Mb Heap Memory device should user another inSampleSize (a bigger one).
The article i attack shows an efficient way to render the images for a given height and width. Take a special attention to the last code segment, they "pre-open" the file and calculate the inSampleSize for a "full-decode" later on.
I would also like to add this recommendations.
Use the "getBitmap" function in an async way, call a new thread or an asyncTask (this is done because using the SD takes time and this will cause your application to hang, to be slow and give a bad impression on low-mid end devices.
Try to always use the same Bitmap object. Avoid creating multiple "Bitmap bitmap = new Bitmap()". You have to realize that loaded bitmaps are stored in ram and once assigned to a view its "harder" for the garbage collector to get them.
When you have finished using a Bitmap over make it null. This of this, imagine your have 12Mb max heap RAM. your app is using 8Mb now. Garbage collector starts and cant get any more unused RAM. you 10 Bitmaps fast never make them null after assigning the data to the ImageView and somehow you retain their reference. Taken that each bitmap take 500Kb of Ram your app will crash. Always make Bitmaps null after using.
Finally use the DDMS provided in the google platform-tools (you can access it with the eclipse to debug and see your memory usage, you can also force Garbage Collection to see how your app behaves).
I'm intending to display very large Images in Android. My first solution - to supply them as pdf - fails because not every handheld got a pdf-viewer preinstalled, and I don't want to require the users to install one.
So I have a png now (width = 3998px height=2827px) that I want to display. I downloaded this image to test how it would be displayed the gallery. It was quite painful. It seems that the galery renders this picture only once, and if I Zoom in, I cannot read the text at all.
So I wrote a testActivity which simply has an ImageView nested in a LinearLayout. I put the image into the drawable and set it as ImageView's image-source.
Unforunately the app crashes immediatly, due to an "
ERROR/AndroidRuntime(8906): Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget"
I didn't expect that ONE single Image can be too large forVM's memory. I played a little bit around, set ImageViews size to 3998 & 2827px , put the Image to sdCard and read it manually with a fileInputStream.
To my big surprise it now shows my image, but if I turn my Nexus S horizontal I get the same OutOfMemoryError as before.
Can somewone point me the main difference between recieving a Bitmap through a FileInputStream or to set it as ImageView's source.
Also I'm not able to scroll comfortable with two parent scrollViews
I searching for a simple solution to display ONE large image at a time with the ability to scroll horizontal and vertical while able to zoom in and out.
here is a sample of the image I want to display
I know it's an old post but I spent a lot of time on this problem, so here's my solution.
I wanted to display a 2000×3000 picture but I got out of memory or the image was too large to be displayed.
To begin, I get the dimensions of the picture:
o = new BitmapFactory.Options();
o.inJustDecodeBounds=true;
pictures = BitmapFactory.decodeStream(new FileInputStream(f), null, o);
Then I cut it up into four parts and displayed them with four ImageViews.
I tried to load the full picture and cut it into four (using BitmapFactory.create(bitmap,int,int,int,int)) but got out of memory again.
So I decided to use some BitMapRegionDecoder:
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
ImageView iv = new ImageView(this);
InputStream istream = null;
try {
istream = this.getContentResolver().openInputStream(Uri.fromFile(f));
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
BitmapRegionDecoder decoder = null;
try {
decoder = BitmapRegionDecoder.newInstance(istream, false);
} catch (IOException e) {
e.printStackTrace();
}
int nw = (j*width/k);
int nh = (i*height/k);
Bitmap bMap = decoder.decodeRegion(new Rect(nw,nh, (nw+width/k),(nh+height/k)), null);
iv.setImageBitmap(bMap);
}
}
This worked.
I know its an old question but I used TileView to do exactly this:
https://github.com/moagrius/TileView
Try to use this one:
https://github.com/davemorrissey/subsampling-scale-image-view
A custom image view for Android, designed for photo galleries and
displaying huge images (e.g. maps and building plans) without
OutOfMemoryErrors. Includes pinch to zoom, panning, rotation and
animation support, and allows easy extension so you can add your own
overlays and touch event detection.
You can use this "easy to integerate" source of WorldMap application:
https://github.com/johnnylambada/WorldMap
This uses a huge image of a world map, and uses cache to display a map.
To integerate, I just copied all the java files (5 i guess) and used the surfaceView in my layout file. Then I went through the small OnCreate() method of ImageViewerActivity.java and used the code in my activity (with sligh alteration, depending on my personal use).
This post is a good demo for zooming a picture using multi touch gestures. It uses Matrix to zoom as well as pan a picture.
To handle scaling etc and using full resolution, You can use MapView of OSM (open street map) and provide it with your tiles (instead of the map). Check this: http://www.haakseth.com/?p=30
We have to follow following steps to remove out of memory exception while loading huge images:
1. Read Bitmap Dimensions and Type
2. Load a Scaled down version into memory
Android Developer's Guide defines how we achieve these.
here is the link
http://developer.android.com/training/displaying-bitmaps/load-bitmap.html#load-bitmap