I have an ImageView that is not wanting to display a JPEG, but will display all the other PNG's in the ListView. I have tried things such as adding a transparent background, and nothing works. To get the data, I downloaded all of the images, and stored them into a blob in a SQLite database. I retrieved them by fetching the info from the database, and according to the database, their is binary JPEG data available.
Here is the image I am trying to display (I have it already downloaded in binary data): http://image-store.slidesharecdn.com/1a4f1444-02e2-11e4-9166-22000a901256-large.jpeg
Here is the code I am using to try and convert the binary data back to a Bitmap:
try
{
String profilePictureBytes = submittedImageTemp; // this string holds the binary jpeg, png data, etc.
byte[] encoded;
try
{
encoded = profilePictureBytes.getBytes("ISO-8859-1");
ByteArrayInputStream imageStream = new ByteArrayInputStream(encoded);
Bitmap theBitmap = BitmapFactory.decodeStream(imageStream);
attachPreviewOne.setBackgroundColor(Color.TRANSPARENT);
attachPreviewOne.setImageBitmap(theBitmap);
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
}
A. Extract your jpeg from the blob to a temp file. You might want to use the getCacheDir() folder for that
B. Load it from temp file:
BitmapFactory.Options options = new BitmapFactory.Options();
Bitmap bm = BitmapFactory.decodeFile(jpegTemFile, options); //<------------
imageView.setImageBitmap(bm);
The above should work fine. Still - few things you might want to consider:
C. Depending on your jpeg, the loading operation - decodeFile - might be lengthy. You might want to do it in an
AsyncTask.
D. You might also want to consider setting a sampleSize so to reduce size of loaded image:
options.inSampleSize = 2; // setting to N will reduce in-memory size by factor of N*N
Or, you might use Picasso for the job. I used it in several projects and was happy with what I got:
Picasso.with(context)
.load(url)
.resize(50, 50)
.centerCrop()
.into(imageView)
Related
I am developing an application that chooses an image of a wound and displays it on the application screen. with this, the user marks the region of interest of the wound, so that later the algorithm can recognize and process the region of interest. I'm doing this using the lib implementation 'com.github.gcacace: signature-pad: 1.2.1' to demarcate the region and then I'm saving the screen's "printscreen" so I can save the markup along with the image of the wound.
How I wish the image will look
Exit:
However, I want to cut the printscreen according to the image of the wound to send to the server to process the image. Can someone help me cut out the wound image after marking.
private fun saveImage(myBitmap: Bitmap?): String? {
try {
// image naming and path to include sd card appending name you choose for file
val mPath = Environment.getExternalStorageDirectory().toString() + "/imagesignature.jpg"
// create bitmap screen capture
val v1 = window.decorView.rootView
v1.isDrawingCacheEnabled = true
val bitmap = Bitmap.createBitmap(v1.drawingCache)
v1.isDrawingCacheEnabled = false
val imageFile = File(mPath)
val outputStream = FileOutputStream(imageFile)
val quality = 100
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream)
outputStream.flush()
outputStream.close()
//setting screenshot in imageview
val filePath = imageFile.path
val ssbitmap = BitmapFactory.decodeFile(imageFile.absolutePath)
imagem.setImageBitmap(ssbitmap)
} catch (e: Throwable) {
// Several error may come out with file handling or DOM
e.printStackTrace()
}
return ""
}
I am still a learner so for an easy way to crop an image I would suggest using this library:
https://github.com/ArthurHub/Android-Image-Cropper
This is where you can crop the image as per your requirement and store the image on the server
If you have the coordinates of the rectangle you want to save:
Bitmap croppedBmp = Bitmap.createBitmap(originalBmp, rectanglePositionX, rectanglePositionY, rectangleWidth, rectangleHeight);
Or you can try:
BitmapFactory.decodeStream(InputStream is, Rect outPadding, Options opts)
or
BitmapFactory.decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts)
where in the Rect outPadding you will set the coordinates of the rectangle you want to save.
As far as I know, I don't think it's possible to crop and image. In order to crop, you need to find the dimensions for the part that you want. I don't think you can tell the program the dimensions of what you want and then crop everything else off, as far as my knowledge goes. It might be possible to print an image, but I don't think Java can crop. Other coding programs might work better for this.
Since android 10 there is some changes in accessing media files. After going through documentation https://developer.android.com/training/data-storage/shared/media i have been able to load the media content in to a bitmap, but i didn't get the orientation information. I know there is some restriction to the location information of the image, but does these exif restrictions also effect orientation information? If there is any other way to get an image's orientation information, please let me know. The code am using is given below (which is always returning 0 - Value for undefined). Thank you.
ContentResolver resolver = getApplicationContext().getContentResolver();
try (InputStream stream = resolver.openInputStream(selectedFileUri)) {
loadedBitmap = BitmapFactory.decodeStream(stream);
ExifInterface exif = new ExifInterface(stream);
orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
}
BitmapFactory.decodeStream consumed the whole stream and closed it.
You should open a new stream first before trying to read the exif.
Firstly, consider the API used in different SDK version, please use the AndroidX ExifInterface Library
Secondly, ExifInterface for reading and writing Exif tags in various image file formats. Supported for reading: JPEG, PNG, WebP, HEIF, DNG, CR2, NEF, NRW, ARW, RW2, ORF, PEF, SRW, RAF.
But you use it for bitmap, Bitmap does not have any EXIF headers. You already threw away any EXIF data when you loaded the Bitmap from wherever it came from. Use ExifInterface on the original source of the data, not the Bitmap
you can try to use the following code to get the info and remember to use the original stream.
public static int getExifRotation(Context context, Uri imageUri) throws IOException {
if (imageUri == null) return 0;
InputStream inputStream = null;
try {
inputStream = context.getContentResolver().openInputStream(imageUri);
ExifInterface exifInterface = new ExifInterface(inputStream);
int orienttation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED)
switch (orienttation) {
case ExifInterface.ORIENTATION_ROTATE_90:
return 90;
case ExifInterface.ORIENTATION_ROTATE_180:
return 180;
case ExifInterface.ORIENTATION_ROTATE_270:
return 270;
default:
return ExifInterface.ORIENTATION_UNDEFINED;
}
}finally {
//here to close the inputstream
}
}
I need to add an image to my docx file. The image is a png image of a signature that is to placed behind text in the signature line of a certificate to be downloaded by the user as a docx, a pdf or jpg. The first problem I encountered is that you can only add inline image using the latest version of docx4j (v6.1.2) and creating an image Anchor is currently disabled (see BinaryPartAbstractImage.java: line 1029). That's a problem since the signature image is not inline, it supposed to appear behind the name on the signature line. Instead of inserting one myself, my workaround is to place a placeholder image:
These images are mapped as image1.png and image2.png, respectively, on /word/media directory of the docx uncompressed version. The program then replaces these with the name, position, and actual png of the signature every time a certificate is generated.
The problem is that the images are scaled the same dimension as the placeholder image, where in fact it should look like this:
How can I get to keep the image dimension of the image after replacing, or at least the aspect ratio? Here is how I replace the placeholder image with the new image:
File approveBySignatureImage = new File(...);
final String approvedByImageNodeId = "rId5";
replaceImageById(approvedByImageNodeId,
"image1.png", approveBySignatureImage);
This is the actual method where the replacing happens:
public void replaceImageById(String id, String placeholderImageName, File newImage) throws Exception {
Relationship rel = document.getMainDocumentPart().getRelationshipsPart().getRelationshipByID(id);
BinaryPartAbstractImage imagePart;
if(FilenameUtils.getExtension(placeholderImageName).toLowerCase() == ContentTypes.EXTENSION_BMP) {
imagePart = new ImageBmpPart(new PartName("/word/media/" + placeholderImageName));
}
else if([ContentTypes.EXTENSION_JPG_1, ContentTypes.EXTENSION_JPG_2].contains(FilenameUtils.getExtension(placeholderImageName).toLowerCase())) {
imagePart = new ImageJpegPart(new PartName("/word/media/" + placeholderImageName));
}
else if(FilenameUtils.getExtension(placeholderImageName).toLowerCase() == ContentTypes.EXTENSION_PNG) {
imagePart = new ImagePngPart(new PartName("/word/media/" + placeholderImageName));
}
InputStream stream = new FileInputStream(newImage);
imagePart.setBinaryData(stream);
if(FilenameUtils.getExtension(newImage.getName()).toLowerCase() == ContentTypes.EXTENSION_BMP) {
imagePart.setContentType(new ContentType(ContentTypes.IMAGE_BMP));
}
else if([ContentTypes.EXTENSION_JPG_1, ContentTypes.EXTENSION_JPG_2].contains(FilenameUtils.getExtension(newImage.getName()).toLowerCase())) {
imagePart.setContentType(new ContentType(ContentTypes.IMAGE_JPEG));
}
else if(FilenameUtils.getExtension(newImage.getName()).toLowerCase() == ContentTypes.EXTENSION_PNG) {
imagePart.setContentType(new ContentType(ContentTypes.IMAGE_PNG));
}
imagePart.setRelationshipType(Namespaces.IMAGE);
final String embedId = rel.getId();
rel = document.getMainDocumentPart().addTargetPart(imagePart);
rel.setId(embedId);
}
You'll need to set the dimensions (or possibly just remove what you have?) on your placeholder image.
For help in doing that:-
docx4j inspects the image to work that out at https://github.com/plutext/docx4j/blob/master/src/main/java/org/docx4j/openpackaging/parts/WordprocessingML/BinaryPartAbstractImage.java#L512 using org.apache.xmlgraphics ImageInfo.
See also CxCy:https://github.com/plutext/docx4j/blob/master/src/main/java/org/docx4j/openpackaging/parts/WordprocessingML/BinaryPartAbstractImage.java#L1164
https://github.com/plutext/docx4j/blob/master/src/main/java/org/docx4j/openpackaging/parts/WordprocessingML/BinaryPartAbstractImage.java#L815 shows scaling to maintain aspect ratio.
I have images in my local database which I want to populate in a listview.
This is what I'm doing :
...
bitmap[i] = MySQLiteHelper.getImage(images[i]);
// This fetches the bitmap image from database
...
Here, I'm converting my Bitmap to a Drawable.
d[i] = new BitmapDrawable(getResources(),bitmap[i]);
Then I'm using this Drawable in HashMap's put method to set it as a listView item.
hm.put("img", String.valueOf(d[i]));
// put() accepts java.lang.String as input.
But the image is not displayed in the listview. I'm able to display all the text, but not the image.
I'm getting the following error in my LogCat :
BitmapFactory﹕ Unable to decode stream: java.io.FileNotFoundException: android.graphics.drawable.BitmapDrawable#3ab28e36: open failed: ENOENT (No such file or directory)
resolveUri failed on bad bitmap uri: android.graphics.drawable.BitmapDrawable#3ab28e36
What am I doing wrong here? I think that when converting that Bitmap to Drawable, the drawable is holding a temporary value and the put() cannot access that? What is wrong here folks, any help please?
EDIT :
My HashMap code :
List<HashMap<String,String>> aList = new ArrayList<HashMap<String,String>>();
for(int i=0;i<len;i++){
HashMap<String, String> hm = new HashMap<String,String>();
hm.put("img", String.valueOf(d[i]));
hm.put("tit", " Title : " + title[i]);
hm.put("init", " Initial Price : " + init_price[i]);
hm.put("cur"," Current Price : " + cur_price[i]);
aList.add(hm);
}
// Keys used in Hashmap
String[] from = { "img","tit","init","cur" };
// Ids of views in listview_layout
int[] to = { R.id.img,R.id.tit,R.id.init,R.id.cur};
getImage() method :
The image (Bitmap) is stored in the database as BLOB. I obtained it as a ByteArray.
Now, I'm converting it back to Bitmap using the below method.
// convert from byte array to bitmap
public static Bitmap getImage(byte[] image) {
return BitmapFactory.decodeByteArray(image, 0, image.length);
}
My Logcat : after using Base64 to convert Bitmap to String
(Note: consider using the new RecyclerView instead of a ListView for better performance)
What you are trying to do is either converting a String to a BitmapDrawable (in case MySQLiteHelper.getImage() returns a String as a path pointing to an image, since usually you won't store binary data in a database) OR converting a BitmapDrawable to a String. Both cases actually make no sense.
The way it is usually done: implementing a helper class and then parameterizing your ListView's Adapter with its instances. There are literally tons of examples around the web, look at this one, or that one which uses a database
From the error message it seems the problem is elsewhere in the code.
BitmapFactory﹕ Unable to decode stream: java.io.FileNotFoundException
This probably means you are decoding the file with a location and the location is invalid. Perhaps you are using BitmapFactory.decodeFile?
Check in your code if you are using BitmapFactory and make sure you are passing the correct location if available.
I am developing an application and testing it on my device running Android 2.2. In my code, I make use of a Bitmap that I retrieve using BitmapFactory.decodeResource, and I am able to make changes by calling bitmap.setPixels() on it. When I test this on a friend's device running Android 1.6, I get an IllegalStateException in the call to bitmap.setPixels. Documentation online says an IllegalStateException is thrown from this method when the bitmap is immutable. The documentation doesn't say anything about decodeResource returning an immutable bitmap, but clearly that must be the case.
Is there a different call I can make to get a mutable bitmap reliably from an application resource without needing a second Bitmap object (I could create a mutable one the same size and draw into a Canvas wrapping it, but that would require two bitmaps of equal size using up twice as much memory as I had intended)?
You can convert your immutable bitmap to a mutable bitmap.
I found an acceptable solution that uses only the memory of one bitmap.
A source bitmap is raw saved (RandomAccessFile) on disk (no ram memory), then source bitmap is released, (now, there's no bitmap at memory), and after that, the file info is loaded to another bitmap. This way is possible to make a bitmap copy having just one bitmap stored in ram memory per time.
See the full solution and implementation here: Android: convert Immutable Bitmap into Mutable
I add a improvement to this solution, that now works with any type of Bitmaps (ARGB_8888, RGB_565, etc), and deletes the temp file. See my method:
/**
* Converts a immutable bitmap to a mutable bitmap. This operation doesn't allocates
* more memory that there is already allocated.
*
* #param imgIn - Source image. It will be released, and should not be used more
* #return a copy of imgIn, but muttable.
*/
public static Bitmap convertToMutable(Bitmap imgIn) {
try {
//this is the file going to use temporally to save the bytes.
// This file will not be a image, it will store the raw image data.
File file = new File(Environment.getExternalStorageDirectory() + File.separator + "temp.tmp");
//Open an RandomAccessFile
//Make sure you have added uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
//into AndroidManifest.xml file
RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
// get the width and height of the source bitmap.
int width = imgIn.getWidth();
int height = imgIn.getHeight();
Config type = imgIn.getConfig();
//Copy the byte to the file
//Assume source bitmap loaded using options.inPreferredConfig = Config.ARGB_8888;
FileChannel channel = randomAccessFile.getChannel();
MappedByteBuffer map = channel.map(MapMode.READ_WRITE, 0, imgIn.getRowBytes()*height);
imgIn.copyPixelsToBuffer(map);
//recycle the source bitmap, this will be no longer used.
imgIn.recycle();
System.gc();// try to force the bytes from the imgIn to be released
//Create a new bitmap to load the bitmap again. Probably the memory will be available.
imgIn = Bitmap.createBitmap(width, height, type);
map.position(0);
//load it back from temporary
imgIn.copyPixelsFromBuffer(map);
//close the temporary file and channel , then delete that also
channel.close();
randomAccessFile.close();
// delete the temp file
file.delete();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return imgIn;
}
Copy the bitmap to itself with mutable option true. This way neither extra memory consumption nor long lines of code are needed.
Bitmap bitmap= BitmapFactory.decodeResource(....);
bitmap= bitmap.copy(Bitmap.Config.ARGB_8888, true);
We can first set options for BitmapFactory by instantiating an BitmapFactory.Options class and then set the options field named 'inMutable' as true and and then pass this options instance to decodeResource.
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inMutable = true;
Bitmap bp = BitmapFactory.decodeResource(getResources(), R.raw.white, opt);
Here's a solution i've created that uses the internal storage and doesn't require any new permission, based on "Derzu"'s idea, and the fact that starting with honeycomb, this is built in :
/**decodes a bitmap from a resource id. returns a mutable bitmap no matter what is the API level.<br/>
might use the internal storage in some cases, creating temporary file that will be deleted as soon as it isn't finished*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static Bitmap decodeMutableBitmapFromResourceId(final Context context, final int bitmapResId) {
final Options bitmapOptions = new Options();
if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB)
bitmapOptions.inMutable = true;
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), bitmapResId, bitmapOptions);
if (!bitmap.isMutable())
bitmap = convertToMutable(context, bitmap);
return bitmap;
}
#TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public static Bitmap convertToMutable(final Context context, final Bitmap imgIn) {
final int width = imgIn.getWidth(), height = imgIn.getHeight();
final Config type = imgIn.getConfig();
File outputFile = null;
final File outputDir = context.getCacheDir();
try {
outputFile = File.createTempFile(Long.toString(System.currentTimeMillis()), null, outputDir);
outputFile.deleteOnExit();
final RandomAccessFile randomAccessFile = new RandomAccessFile(outputFile, "rw");
final FileChannel channel = randomAccessFile.getChannel();
final MappedByteBuffer map = channel.map(MapMode.READ_WRITE, 0, imgIn.getRowBytes() * height);
imgIn.copyPixelsToBuffer(map);
imgIn.recycle();
final Bitmap result = Bitmap.createBitmap(width, height, type);
map.position(0);
result.copyPixelsFromBuffer(map);
channel.close();
randomAccessFile.close();
outputFile.delete();
return result;
} catch (final Exception e) {
} finally {
if (outputFile != null)
outputFile.delete();
}
return null;
}
another alternative is to use JNI in order to put the data into it, recycle the original bitmap, and use the JNI data to create a new bitmap, which will be (automatically) mutable, so together with my JNI solution for bitmaps, one can do the following:
Bitmap bitmap=BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher);
final JniBitmapHolder bitmapHolder=new JniBitmapHolder(bitmap);
bitmap.recycle();
bitmap=bitmapHolder.getBitmapAndFree();
Log.d("DEBUG",""+bitmap.isMutable()); //will return true
however, i'm not sure what is the minimal requirement of API level. it works very well on API 8 and above.
I know I'm late to the party, but this is how we avoided this painfully annoying Android problem, and cropped and modified an image with only one copy ever in memory.
Situation
we want to process the pixels of a cropped version of an image saved to file. With high memory demands, we never want to have more than one copy of this image in memory at any given time.
What should have worked but didn't
Opening the image subsection (the bit we wanted to crop to) with BitmapRegionDecoder, passing in a BitmapFactory.option with inMutable = true, processing the pixels then saving to file.
Though our app declared an API minimum of 14 and a target of 19, BitmapRegionDecoder was returning an immutable bitmap, effectively ignoring our BitMapFactory.options
What won't work
opening an mutable image with BitmapFactory (which respects our inMutable option) and croppping it: all cropping techniques are non-imperitive (require a copy of the entire image to exist in memory at a time, even if garbage collected immediately after with overwrites and recycling)
opening an immutable image with BitmapRegionDecoder (effectively cropped) and converting it to a mutable one; all available techniques again require a copy in memory.
The great work-around of 2014
open the full size image with BitmapFactory as a mutable bitmap, and perform our pixel operations
save the bitmap to file and recycle it from memory (it's still un-cropped)
open the saved bitmap with BitmapRegionDecoder, opening only the region to be cropped to (now we don't care if the bitmap is immutable or not)
save this bitmap (which has effectively been cropped) to file, overwriting the previously saved bitmap (which was un-cropped)
With this method, we can crop and perform pixel processing on a bitmap with only 1 copy ever in memory (so we can avoid those pesky OOM errors as much as possible), trading RAM for time as we have to perform extra (slow) file IOs.
It is happening because you want to resize the bitmap by calling setHeight() or setWidth()
To resize any bitmap or drawable (Png, Svg, vector, etc)
public Bitmap editMyBitmap(int drawableId, int newHeight, int newWidth) {
Bitmap myBitmap = BitmapFactory.decodeResource(getResources(), drawableId);
myBitmap = Bitmap.createScaledBitmap(myBitmap, newWidth, newHeight, false);
return myBitmap;
}
Usage Example:
Bitmap facebookIcon = editMyBitmap(R.drawable.facebookImage);
// now use it anywhere
imageView.setBitmapImage(facebookIcon);
canvas.drawBitmap(facebookIcon, 0, 0, null);
I know the question is solved but what about:
BitmapFactory.decodeStream(getResources().openRawResource(getResources().getIdentifier("bitmapname", "drawable", context.getPackageName())))