Need help converting a process from Java(android) to IOS Swift - android

Background: I have a process in an android application that resizes an image, uses JPEG compression of 30% from a bitmap, and returns a byteArray in which I convert to base64Encoded String. I need this type of functionality ported to IOS Swift if possible. I am undergoing information overload from the amount of methods on the web for image manipulation and I need some more direction.
here is my android code:
Bitmap bmp = null;
Bitmap scaledBitmap = null;
ByteArrayOutputStream baos = null;
try
{
bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
//if the bitmap is smaller than 1600 wide, scale it up while preserving aspect ratio
if(bmp.getWidth() < 1600) {
int originalHeight = bmp.getHeight();
int originalWidth = bmp.getWidth();
scaledBitmap = Bitmap.createScaledBitmap(bmp, 1600,
originalHeight*1600/originalWidth, true);
bmp = scaledBitmap;
scaledBitmap = null;
}
baos = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.JPEG, 30, baos); // 30% compression
image = baos.toByteArray();
}
//catch stuff after this
And here is my IOS Swift code so far:
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
picker.dismissViewControllerAnimated(true, completion: nil)
let image = info[UIImagePickerControllerOriginalImage] as? UIImage
self.imgCheckFront.image = info[UIImagePickerControllerOriginalImage] as? UIImage
let imageData = UIImageJPEGRepresentation(info[UIImagePickerControllerOriginalImage] as? UIImage, 30.0)
let base64String = imageData.base64EncodedStringWithOptions(.allZeros)
}
}
I think this is quite different than my Android process. The size of the resulting base64String I create in my IOS Code is way too big.

Sorry guys, it was a silly mistake.
this:
let imageData = UIImageJPEGRepresentation(info[UIImagePickerControllerOriginalImage] as? UIImage, 30.0)
Needs to be this:
let imageData = UIImageJPEGRepresentation(info[UIImagePickerControllerOriginalImage] as? UIImage, 0.3)

Related

OutOfMemory when Bitmap.createBitmap & converting to Base64

Sometimes on some mobile devices, image converting to Base64 String get OutOfMemoryError because of enormous size if base64 string (when the original image & it's resize - not weight too much). Is there any way to get more modest size of string without Outofmemory exception? In my code I resize image & compress... but anyway the size of final Base64 String is large.
public String getBase64Image() {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(getFileInst().getAbsolutePath(), options);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int currentWidth = options.outWidth;
int currentHeight = options.outHeight;
int maxSize = Math.max(currentHeight, currentWidth);
double diff = 1;
if (maxSize > maxAcceptableImageSize) {
diff = (double)maxAcceptableImageSize / maxSize;
}
Matrix matrix = new Matrix();
int rotate = getCameraPhotoOrientation(getImage().getContext(), getFileInst().getAbsolutePath());
matrix.preRotate(rotate);
Bitmap image;
Bitmap src = Bitmap.createBitmap(BitmapFactory.decodeFile(getFileInst().getAbsolutePath()), 0, 0,
currentWidth, currentHeight, matrix, false);
if (diff <= 1) {
image = Bitmap.createScaledBitmap(src, (int)(src.getWidth() * diff), (int)(src.getHeight() * diff), false);
} else {
image = src;
}
image.compress(Bitmap.CompressFormat.PNG, 75, baos);
byte[] byteArrayImage = baos.toByteArray();
String base64Str = "data:image/png;base64," + Base64.encodeToString(byteArrayImage, Base64.DEFAULT);
src.recycle();
image.recycle();
return base64Str;
}
You should scale the image before rotating it.
If you scale it down first, there are less pixels that need to be rotated, saving memory.
You should also place .recycle() calls directly after you're done using them, not all at the end of the function.
As a very very VERY last resort, you could add android:largeHeap="true" to your application in the manifest, which will most likely give you more available memory.
For specific details on largeHeap, read the documentation here:
https://developer.android.com/guide/topics/manifest/application-element.html

byte[] to image using Xamarin.Android

I know, this is an old question, but I've got problems with encoding a byte[] into a bitmap...
Background: I'm writing an Andoid-App which receives picturebytes via UDP, encodes them into a bitmap and displays the picture in an image view.
Since my functions didn't work, I cancelled the UDP-Connection for testing and wrote all the image-bytes in a huge variable. So they're all correct...
The function returns "null".
The function I'm using:
public Bitmap ByteArrayToImage(byte[] imageData)
{
var bmpOutput = BitmapFactory.DecodeByteArray(imageData, 0, imageData.Length);
return bmpOutput;
}
another function I tried out:
public Bitmap ByteArrayToImage2(byte[] imageData)
{
Bitmap bmpReturn;
bmpReturn = (Android.Graphics.Bitmap) Android.Graphics.Bitmap.FromArray<byte>(imageData);
return bmpReturn;
}
A function I found in the internet:
public static Bitmap bytesToUIImage (byte[] bytes)
{
if (bytes == null)
return null;
Bitmap bitmap;
var documentsFolder = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
//Create a folder for the images if not exists
System.IO.Directory.CreateDirectory(System.IO.Path.Combine (documentsFolder, "images"));
string imatge = System.IO.Path.Combine (documents, "images", "image.jpg");
System.IO.File.WriteAllBytes(imatge, bytes.Concat(new Byte[]{(byte)0xD9}).ToArray());
bitmap = BitmapFactory.DecodeFile(imatge);
return bitmap;
}
Most unfortunately, the last function didn't work as well, but here I have do admit, that I was a bit confused about the 'documents' in
string imatge = System.IO.Path.Combine (documents, "images", "image.jpg");
I got an error and changed it into documentsFolder since i guess, that should (or could) be right....
Thank you in advance for your help
it seems, I found the error...
I stored the public Bitmap ByteArrayToImage(byte[] imageData) in another class. I don't know why, but when I decode the Bytearray in the class that also receives the array, all works fine...
If someone knows the reason, feel welcome to let me know, but for now I'm happy ;-)
I did something similar
On sender side:
Camera.Parameters parameters = camera.getParameters();
if (parameters.getPreviewFormat() == ImageFormat.NV21) {
Rect rect = new Rect(0, 0, parameters.getPreviewSize().width, parameters.getPreviewSize().height);
YuvImage yuvimage = new YuvImage(data, ImageFormat.NV21, parameters.getPreviewSize().width, parameters.getPreviewSize().height, null);
ByteArrayOutputStream os = new ByteArrayOutputStream();
yuvimage.compressToJpeg(rect, 75, os);
byte[] videoFrame = os.toByteArray();
//send the video frame to reciever
}
On receiving side:
DataInputStream dIn = new DataInputStream(socket.getInputStream());
int length = 0;
length = dIn.readInt();
if (length > 0) {
byte[] message = new byte[length];
dIn.readFully(message, 0, message.length);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4;
final Bitmap bitmap = BitmapFactory.decodeByteArray(message, 0, message.length, options);
ReceiverActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
imgPreview.setImageBitmap(bitmap);
}
});
There is a built in method to decode a byte array into a bitmap. The problem comes when we are talking of big images. With small ones you can use:
Bitmap bmp = BitmapFactory.DecodeByteArray (data, 0, data.length);
Be aware. Those bitmaps are not mutable, so you will not be able to use canvases on those. To make them mutable go to: BitmapFactory.decodeResource returns a mutable Bitmap in Android 2.2 and an immutable Bitmap in Android 1.6

Dynamically creating a compressed Bitmap

I'm writing a custom printing app in Android and I'm looking for ways to save on memory. I have three basic rectangles I need to print on a full page. Currently I'm creating a base Bitmap the size of the page:
_baseBitmap = Bitmap.createBitmap(width/_scale, height/_scale, Bitmap.Config.ARGB_8888);
The print process requests a Rect portion of that page. I cannot predetermine the dimensions of this Rect.
newBitmap = Bitmap.createBitmap(fullPageBitmap, rect.left/_scale, rect.top/_scale, rect.width()/_scale, rect.height()/_scale);
return Bitmap.createScaledBitmap(newBitmap, rect.width(), rect.height(), true);
Using bitmap config ARGB_8888 _baseBitmap is about 28MB (8.5"x11" # 300dpi = 2250*3300*4bytes). Even at 50% scaling (used above), my image is over 7MB. Scaling any smaller than this and image quality is too poor.
I've attempted to create _baseBitmap using Bitmap.Config.RGB_565, which does greatly reduce the full image size, but then when I overlay an image (jpegs) I get funny results. The image is compressed in width, duplicated next to itself, and all the color is green.
BitmapFactory.Options options = new BitmapFactory.Options();
options.inDither = true;
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap myBitmap = BitmapFactory.decodeStream(input, null, options);
input.close();
return myBitmap;
....
private static Bitmap overlay(Bitmap bmp1, Bitmap bmp2, float left, float top) {
Canvas canvas = new Canvas(bmp1);
canvas.drawBitmap(bmp2, left, top, null);
return bmp1;
}
I know I can compress an image of these dimensions down to a reasonable size. I've looked into Bitmap.compress, but for some reason beyond my understanding I'm getting the same size image back:
ByteArrayOutputStream os = new ByteArrayOutputStream();
_baseBitmap.compress(Bitmap.CompressFormat.JPEG, 3, os);
byte[] array = os.toByteArray();
Bitmap newBitmap = BitmapFactory.decodeByteArray(array, 0, array.length);
_baseBitmap.getAllocationByteCount() == newBitmap.getAllocationByteCount()
It would be better to create it compressed than to create a large one and then compress it. Is there any way to create a compressed Bitmap? Any advice is greatly appreciated.
note: Not an Android expert. I'm not necessarily familiar with the platform specific terms you may use to respond. Please be gentle.
Try something like this, if you have a target size in mind.
private static final int MAX_BYTES_IMAGE = 4194304; // 4MB
//...
ByteArrayOutputStream out;
int quality = 90;
do
{
out = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, out);
quality -= 10;
} while (out.size() > MAX_BYTES_IMAGE_FILESIZE);
out.close();

getting Image ThumbNail in Android

I need Thumbnail of an image . I only know about the name of image which is stored in SD card . Can anyone help me.
Try this.
final int THUMBSIZE = 64;
Bitmap ThumbImage = ThumbnailUtils.extractThumbnail(BitmapFactory.decodeFile(imagePath),
THUMBSIZE, THUMBSIZE);
Refer this for more details.
Using MediaStore.Images.Thumbnails you can query and get two kinds of thumbnails: MINI_KIND: 512 x 384 thumbnail MICRO_KIND: 96 x 96 thumbnail.
The advantage of using this call is that the thumbnails are cached by the MediaStore. So retrieval would be faster if the thumbnail was previously created.
byte[] imageData = null;
try
{
final int THUMBNAIL_SIZE = 64;
FileInputStream fis = new FileInputStream(fileName);
Bitmap imageBitmap = BitmapFactory.decodeStream(fis);
Float width = new Float(imageBitmap.getWidth());
Float height = new Float(imageBitmap.getHeight());
Float ratio = width/height;
imageBitmap = Bitmap.createScaledBitmap(imageBitmap, (int)(THUMBNAIL_SIZE * ratio), THUMBNAIL_SIZE, false);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
imageBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
imageData = baos.toByteArray();
}
catch(Exception ex) {
}
If you like HQ thumbnails, so use [RapidDecoder][1] library. It is simple as follow:
import rapid.decoder.BitmapDecoder;
...
Bitmap bitmap = BitmapDecoder.from(getResources(), R.drawable.image)
.scale(width, height)
.useBuiltInDecoder(true)
.decode();
Don't forget to use builtin decoder if you want to scale down less than 50% and a HQ result.

How to handle large amount of pictures. which thumbnails sould be shown in android app?

I have a problem in my android application.
I use an application which make pictures with the build in camera of a phone/tablet.These pictures are sometimes quite large in size because of the high resolution of the camera.
Now i load the application and create a listView, where a small thumbnail of the picture is on the left side and on the right is some text.
I create the pictures in this way:
Bitmap a = BitmapFactory.decodeFile(url);
int width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
(float) 66.0, context.getResources().getDisplayMetrics());
int height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
(float) 48.0, context.getResources().getDisplayMetrics());
Bitmap b = Bitmap.createScaledBitmap(a, width, height, false);
The problem is that this step take quite a long time.
Is there any way to make this faster?
There is no way to make it faster, but you should not block the UI thread. See
AsyncTask (and many related questions like Using AsyncTask to load Images in ListView)
LruCache
This is the solution I used taken from here: https://stackoverflow.com/a/5934983/1369222
It works great!
byte[] imageData = null;
try
{
final int THUMBNAIL_SIZE = 64;
FileInputStream fis = new FileInputStream(fileName);
Bitmap imageBitmap = BitmapFactory.decodeStream(fis);
imageBitmap = Bitmap.createScaledBitmap(imageBitmap, THUMBNAIL_SIZE, THUMBNAIL_SIZE, false);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
imageBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
imageData = baos.toByteArray();
}
catch(Exception ex) {
}
Make sure you do this in an Async or a separate thread task so you don't block up the UI thread!

Categories

Resources