Given a the uri of a photo on the users device (both file:// and content://), how could i resize the photo? I'm running a managed expo app, so ideally we would be able to do this without detaching
This can be done with expo's ImageManipulator util:
const resizedPhoto = await ImageManipulator.manipulateAsync(
photo.uri,
[{ resize: { width: 300 } }], // resize to width of 300 and preserve aspect ratio
{ compress: 0.7, format: 'jpeg' },
);
note: i'm using expo@v31, the latest version @v33 has a different syntax - please reference the link above
bonus: here is a way to ensure that neither the width or the height exceeds a maximum value
import { ImageManipulator } from 'expo';
enum PhotoDimensions {
WIDTH = 'width',
HEIGHT = 'height',
}
const maximalValuesPerDimension = { width: 1000, height: 1000 };
export const resizePhotoToMaxDimensionsAndCompressAsJPEG = async ({ photo }: { photo: { width: number, height: number, uri: string } }) => {
// 1. define the maximal dimension and the allowed value for it
const largestDimension = (photo.width > photo.height) ? PhotoDimensions.WIDTH : PhotoDimensions.HEIGHT;
const initialValueOfLargestDimension = photo[largestDimension];
const maximalAllowedValueOfLargestDimension = maximalValuesPerDimension[largestDimension];
const targetValueOfLargestDimension = (initialValueOfLargestDimension > maximalAllowedValueOfLargestDimension) ? maximalAllowedValueOfLargestDimension : initialValueOfLargestDimension;
// 2. resize the photo w/ that target value for that dimension (keeping the aspect ratio)
const resizedPhoto = await ImageManipulator.manipulateAsync(
photo.uri,
[{ resize: { [largestDimension]: targetValueOfLargestDimension } }],
{ compress: 0.7, format: 'jpeg' },
);
// 3. return the resized photo
return resizedPhoto;
};
and some test coverage for it:
import { ImageManipulator } from 'expo';
import { resizePhotoToMaxDimensionsAndCompressAsJPEG } from './resizePhotoToMaxDimensionsAndCompressAsJPEG';
jest.mock('expo', () => ({
ImageManipulator: {
manipulateAsync: jest.fn(),
},
}));
const manipulateAsyncMock = ImageManipulator.manipulateAsync as jest.Mock;
describe('resizePhotoToMaxDimensionsAndCompressAsJPEG', () => {
beforeEach(() => jest.clearAllMocks());
it('should not change the dimensions of a photo if neither of its dimensions exceed the largest allowed value', async () => {
const inputPhoto = { uri: '__TEST_URI__', width: 821, height: 128 };
await resizePhotoToMaxDimensionsAndCompressAsJPEG({ photo: inputPhoto });
expect(manipulateAsyncMock).toHaveBeenCalledTimes(1);
expect(manipulateAsyncMock.mock.calls[0][1][0].resize).toEqual({
width: 821,
});
});
it('should resize the photo accurately if the width exceeds the largest allowed value', async () => {
const inputPhoto = { uri: '__TEST_URI__', width: 12000, height: 128 };
await resizePhotoToMaxDimensionsAndCompressAsJPEG({ photo: inputPhoto });
expect(manipulateAsyncMock).toHaveBeenCalledTimes(1);
expect(manipulateAsyncMock.mock.calls[0][1][0].resize).toEqual({
width: 1000,
});
});
it('should resize the photo accurately if the height exceeds the largest allowed value', async () => {
const inputPhoto = { uri: '__TEST_URI__', width: 821, height: 12000 };
await resizePhotoToMaxDimensionsAndCompressAsJPEG({ photo: inputPhoto });
expect(manipulateAsyncMock).toHaveBeenCalledTimes(1);
expect(manipulateAsyncMock.mock.calls[0][1][0].resize).toEqual({
height: 1000,
});
});
it('should compress the photo and convert it into a jpeg', async () => {
const inputPhoto = { uri: '__TEST_URI__', width: 821, height: 12000 };
await resizePhotoToMaxDimensionsAndCompressAsJPEG({ photo: inputPhoto });
expect(manipulateAsyncMock).toHaveBeenCalledTimes(1);
expect(manipulateAsyncMock.mock.calls[0][2]).toEqual({
compress: expect.any(Number),
format: 'jpeg',
});
});
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With