30

Photos captured via camera are too large for efficient upload and download in React native.

Is there an api or library to compress a PNG image file in React Native?

Learner
  • 2,459
  • 4
  • 23
  • 39
  • 1
    i'm using this plugin: https://github.com/marcshilling/react-native-image-picker , it allows to set maximum desired quality, width , height etc. – Ivan Chernykh Jun 05 '16 at 07:30
  • Thanks @Cherniv. That plug-in is userful, but I wanted to embed the camera into my RN UI which is why I went for https://github.com/lwansbrough/react-native-camera. – Learner Jun 06 '16 at 00:41

4 Answers4

21

If you are using react-native-image-picker for uploading images, you can set maxWidth, maxHeight or quality of image for reducing the size.

const options = {
    title: 'Select Picture',
    storageOptions: {
        skipBackup: true,
        path: 'images',
    },
    maxWidth: 500,
    maxHeight: 500,
    quality: 0.5,
};

ImagePicker.showImagePicker(options, resolve, reject);
Estevan Maito
  • 1,482
  • 1
  • 19
  • 23
Shehzad Osama
  • 1,222
  • 12
  • 13
12

https://github.com/bamlab/react-native-image-resizer provides an API to resize local images.

It allows you to specify:

  • Max dimensions (whilst preserving aspect ratio) and;
  • Output quality (for JPEG only)

API

import ImageResizer from 'react-native-image-resizer';

ImageResizer.createResizedImage(
  imageUri,
  newWidth,
  newHeight,
  compressFormat,
  quality,
)
  .then(resizedImageUri => {
    // resizeImageUri is the URI of the new image that can now be displayed, uploaded...
  })
  .catch(err => {
    // Oops, something went wrong. Check that the filename is correct and
    // inspect err to get more details.
  });
Estevan Maito
  • 1,482
  • 1
  • 19
  • 23
Learner
  • 2,459
  • 4
  • 23
  • 39
7

You could use expo-image-manipulator:

import { manipulateAsync, SaveFormat } from 'expo-image-manipulator';    

const compressImage = async (uri, format = SaveFormat.JPEG) => { // SaveFormat.PNG
    const result = await manipulateAsync(
        uri,
        [{ resize: { width: 1200 } }],
        { compress: 0.7, format }
    );

    return  { name: `${Date.now()}.${format}`, type: `image/${format}`, ...result };
    // return: { name, type, width, height, uri }
};
Mihail
  • 1,246
  • 1
  • 9
  • 8
5

My custom solution for image compression in react-native based on image size.

import * as ImageManipulator from 'expo-image-manipulator';

export default async function ImageCompress(image, { width, height }) {
  const compressSizer = size => {
    const MB = size / Math.pow(1024, 2);
    if (Math.round(MB) === 0) return 1;
    if (Math.round(MB) === 1) return 0.9;
    if (Math.round(MB) === 2) return 0.8;
    if (Math.round(MB) === 3) return 0.7;
    if (Math.round(MB) === 4) return 0.6;
    if (Math.round(MB) >= 5) return 0.5;
    if (Math.round(MB) >= 10) return 0.4;
    if (Math.round(MB) >= 15) return 0.3;
    if (Math.round(MB) >= 20) return 0.2;
    if (Math.round(MB) >= 25) return 0.1;
  };

  const imageManipulator = async (image, { width, height }) => {
    const response = await fetch(image);
    const blob = await response.blob();

    const compress = compressSizer(blob.size);

    let resize;
    if (height === width) resize = { height: 480, width: 480 };
    else if (height > width) resize = { height: 480 };
    else resize = { width: 720 };

    const compressedPhoto = await ImageManipulator.manipulateAsync(
      image,
      [{ resize }],
      {
        compress,
        format: ImageManipulator.SaveFormat.JPEG,
      },
    );

    return compressedPhoto.uri;
  };

  try {
    return await imageManipulator(image, { width, height });
  } catch (error) {
    console.log(error);
  }
}

U.A
  • 2,991
  • 3
  • 24
  • 36