Image optimization like whatsapp and instagram in ios and android

All we need is a simple explanation of the problem, which is provided below.

Task :-
optimize image like Facebook and WhatApp does?
Upload image to server with optimize size in android and ios without losing image quality and dimension.

I have seen many code like native image compression (UIImageJPEGRepresentation(viewImage, 0.8)) but I am not able to get proper result.

Can someone suggest me any algorithm or library in iOS and android through which we can optimise the image without losing quality.

Links I already visited:

iOS

  1. What's the easiest way to resize/optimize an image size with the iPhone SDK?

Android

  1. https://abdelhady.net/2015/03/28/android-loading-images-super-fast-like-whatsapp-part-2/
  2. https://gist.github.com/vipulasri/0cd97d012934531f1266
  3. http://voidcanvas.com/whatsapp-like-image-compression-in-android/

Let’s Solve it:

This is a common error many developers questioned us about it. So we write the explanation above. You just have to apply the suggested solution to your code and it will do for you. If you still getting this error after applying this code then comment below we will get back to you with the new method.

Solution 1

Try this code:

+(UIImage *)scaleAndRotateImage:(UIImage *)image {
int kMaxResolution = 640; // Or whatever

CGImageRef imgRef = image.CGImage;

CGFloat width = CGImageGetWidth(imgRef);
CGFloat height = CGImageGetHeight(imgRef);


CGAffineTransform transform = CGAffineTransformIdentity;
CGRect bounds = CGRectMake(0, 0, width, height);
if (width > kMaxResolution || height > kMaxResolution) {
    CGFloat ratio = width/height;
    if (ratio > 1) {
        bounds.size.width = kMaxResolution;
        bounds.size.height = roundf(bounds.size.width / ratio);
    }
    else {
        bounds.size.height = kMaxResolution;
        bounds.size.width = roundf(bounds.size.height * ratio);
    }
}

CGFloat scaleRatio = bounds.size.width / width;
CGSize imageSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef));
CGFloat boundHeight;
UIImageOrientation orient = image.imageOrientation;
switch(orient) {

    case UIImageOrientationUp: //EXIF = 1
        transform = CGAffineTransformIdentity;
        break;

    case UIImageOrientationUpMirrored: //EXIF = 2
        transform = CGAffineTransformMakeTranslation(imageSize.width, 0.0);
        transform = CGAffineTransformScale(transform, -1.0, 1.0);
        break;

    case UIImageOrientationDown: //EXIF = 3
        transform = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height);
        transform = CGAffineTransformRotate(transform, M_PI);
        break;

    case UIImageOrientationDownMirrored: //EXIF = 4
        transform = CGAffineTransformMakeTranslation(0.0, imageSize.height);
        transform = CGAffineTransformScale(transform, 1.0, -1.0);
        break;

    case UIImageOrientationLeftMirrored: //EXIF = 5
        boundHeight = bounds.size.height;
        bounds.size.height = bounds.size.width;
        bounds.size.width = boundHeight;
        transform = CGAffineTransformMakeTranslation(imageSize.height, imageSize.width);
        transform = CGAffineTransformScale(transform, -1.0, 1.0);
        transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
        break;

    case UIImageOrientationLeft: //EXIF = 6
        boundHeight = bounds.size.height;
        bounds.size.height = bounds.size.width;
        bounds.size.width = boundHeight;
        transform = CGAffineTransformMakeTranslation(0.0, imageSize.width);
        transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
        break;

    case UIImageOrientationRightMirrored: //EXIF = 7
        boundHeight = bounds.size.height;
        bounds.size.height = bounds.size.width;
        bounds.size.width = boundHeight;
        transform = CGAffineTransformMakeScale(-1.0, 1.0);
        transform = CGAffineTransformRotate(transform, M_PI / 2.0);
        break;

    case UIImageOrientationRight: //EXIF = 8
        boundHeight = bounds.size.height;
        bounds.size.height = bounds.size.width;
        bounds.size.width = boundHeight;
        transform = CGAffineTransformMakeTranslation(imageSize.height, 0.0);
        transform = CGAffineTransformRotate(transform, M_PI / 2.0);
        break;

    default:
        [NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"];

}

UIGraphicsBeginImageContext(bounds.size);
CGContextRef context = UIGraphicsGetCurrentContext();

if (orient == UIImageOrientationRight || orient == UIImageOrientationLeft) {
    CGContextScaleCTM(context, -scaleRatio, scaleRatio);
    CGContextTranslateCTM(context, -height, 0);
}
else {
    CGContextScaleCTM(context, scaleRatio, -scaleRatio);
    CGContextTranslateCTM(context, 0, -height);
}

CGContextConcatCTM(context, transform);

CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, width, height), imgRef);
UIImage *imageCopy = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

CGFloat scaleSize = 0.2f;
UIImage *smallImage = [UIImage imageWithCGImage:imageCopy.CGImage
                                          scale:scaleSize
                                    orientation:imageCopy.imageOrientation];

return smallImage;
}

Solution 2

This is what I am using in Android :

public class ImageCompresser {

    public static void compressImage(String inputFilePath, String outputFilePath) {
        try {

            final BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;

            BitmapFactory.decodeFile(inputFilePath, options);

            //options.inSampleSize = calculateInSampleSize(options,400,300);
            options.inSampleSize = calculateInSampleSize(options,800,1000);//Specify Minimum Height, Width of the resulting bitmap maintaining the aspect ratio

            options.inJustDecodeBounds = false;

            Bitmap bm = BitmapFactory.decodeFile(inputFilePath, options);

            FileOutputStream fileOutputStream;

            fileOutputStream = new FileOutputStream(outputFilePath);

            ExifInterface exif;
            try {
                exif = new ExifInterface(inputFilePath);

                Log.d("EXIF", "Make : " + exif.getAttribute(ExifInterface.TAG_MAKE));

                int orientation = exif.getAttributeInt(
                        ExifInterface.TAG_ORIENTATION, 0);
                Log.d("EXIF", "Exif Orientation : " + orientation);
                Matrix matrix = new Matrix();
                if (orientation == 6) {
                    matrix.postRotate(90);
                    Log.d("EXIF", "Exif: " + orientation);
                } else if (orientation == 3) {
                    matrix.postRotate(180);
                    Log.d("EXIF", "Exif: " + orientation);
                } else if (orientation == 8) {
                    matrix.postRotate(270);
                    Log.d("EXIF", "Exif: " + orientation);
                }
                Bitmap scaledBitmap = Bitmap.createBitmap(bm, 0, 0,
                        bm.getWidth(), bm.getHeight(), matrix,
                        true);

                scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream);//Instead of 100, you can provide any value. But it will reduce the image quality 
                scaledBitmap.recycle();
            } catch (IOException e) {
                e.printStackTrace();
            }

            fileOutputStream.flush();
            fileOutputStream.close();
            bm.recycle();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } 
    }

    private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        final int imageWidth = options.outWidth;
        final int imageHeight = options.outHeight;
        Log.d("Test", "imageWidth : " + imageWidth);
        Log.d("Test", "imageHeight : " + imageHeight);

        int inSampleSize = 1;

        if(imageWidth > reqWidth || imageHeight > reqHeight) {
            final int halfWidth = imageWidth / 2;
            final int halfHeight = imageHeight / 2;

            while((halfWidth / inSampleSize) > reqWidth
                    && (halfHeight / inSampleSize) > reqHeight) {
                inSampleSize *= 2;
            }
        }

        return inSampleSize;
    }
}

References :

  1. http://voidcanvas.com/whatsapp-like-image-compression-in-android/
  2. https://developer.android.com/training/displaying-bitmaps/load-bitmap.html

Note: You are free to use these solutions for your personal use. We recommend you apply the first solution to your code because it was tested in our system before posting it on this page.

We are always trying to help the developer community, So we made their work easy. Basically, we collected these data from stackoverflow.com, As it is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0.

Leave a Comment