1import { Asset } from 'expo-asset'; 2import * as FileSystem from 'expo-file-system'; 3import * as ImageManipulator from 'expo-image-manipulator'; 4import { Platform } from 'react-native'; 5 6export const name = 'ImageManipulator'; 7 8export async function test(t) { 9 t.describe('ImageManipulator', async () => { 10 let image; 11 12 t.beforeAll(async () => { 13 image = Asset.fromModule(require('../assets/example_image_1.jpg')); 14 await image.downloadAsync(); 15 }); 16 17 t.describe('manipulateAsync()', async () => { 18 t.it('returns valid image', async () => { 19 const result = await ImageManipulator.manipulateAsync(image.localUri, [ 20 { resize: { width: 100, height: 100 } }, 21 ]); 22 t.expect(result).toBeDefined(); 23 t.expect(typeof result.uri).toBe('string'); 24 t.expect(typeof result.width).toBe('number'); 25 t.expect(typeof result.height).toBe('number'); 26 }); 27 28 t.it('returns valid image from base64 data URL', async () => { 29 // 1x1 red image 30 const result = await ImageManipulator.manipulateAsync( 31 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg==', 32 [{ resize: { width: 100, height: 100 } }] 33 ); 34 t.expect(result).toBeDefined(); 35 t.expect(typeof result.uri).toBe('string'); 36 t.expect(result.width).toBe(100); 37 t.expect(result.height).toBe(100); 38 }); 39 40 t.it('saves with default format', async () => { 41 const result = await ImageManipulator.manipulateAsync(image.localUri, [ 42 { resize: { width: 100, height: 100 } }, 43 ]); 44 45 if (Platform.OS === 'web') { 46 t.expect(result.uri.startsWith('data:image/jpeg;base64,')).toBe(true); 47 } else { 48 t.expect(result.uri.endsWith('.jpg')).toBe(true); 49 } 50 }); 51 52 t.it('saves as JPEG', async () => { 53 const result = await ImageManipulator.manipulateAsync( 54 image.localUri, 55 [{ resize: { width: 100, height: 100 } }], 56 { 57 format: ImageManipulator.SaveFormat.JPEG, 58 } 59 ); 60 61 if (Platform.OS === 'web') { 62 t.expect(result.uri.startsWith('data:image/jpeg;base64,')).toBe(true); 63 } else { 64 t.expect(result.uri.endsWith('.jpg')).toBe(true); 65 } 66 }); 67 68 t.it('saves as PNG', async () => { 69 const result = await ImageManipulator.manipulateAsync( 70 image.localUri, 71 [{ resize: { width: 100, height: 100 } }], 72 { 73 format: ImageManipulator.SaveFormat.PNG, 74 } 75 ); 76 77 if (Platform.OS === 'web') { 78 t.expect(result.uri.startsWith('data:image/png;base64,')).toBe(true); 79 } else { 80 t.expect(result.uri.endsWith('.png')).toBe(true); 81 } 82 }); 83 84 t.it('provides Base64 with no newline terminator', async () => { 85 const result = await ImageManipulator.manipulateAsync( 86 image.localUri, 87 [{ resize: { width: 100, height: 100 } }], 88 { 89 base64: true, 90 } 91 ); 92 93 t.expect(typeof result.base64).toBe('string'); 94 t.expect(result.base64).not.toContain('\n'); 95 t.expect(result.base64).not.toContain('\r'); 96 }); 97 98 t.it('performs compression', async () => { 99 const result = await ImageManipulator.manipulateAsync( 100 image.localUri, 101 [{ flip: ImageManipulator.FlipType.Vertical }], 102 { 103 compress: 0.0, 104 } 105 ); 106 107 if (Platform.OS === 'web') { 108 const imageInfo = await fetch(image.localUri).then(a => a.blob()); 109 const resultInfo = await fetch(result.uri).then(a => a.blob()); 110 111 t.expect(imageInfo.size).toBeGreaterThan(resultInfo.size); 112 } else { 113 const imageInfo = await FileSystem.getInfoAsync(image.localUri); 114 const resultInfo = await FileSystem.getInfoAsync(result.uri); 115 116 t.expect(imageInfo.size).toBeGreaterThan(resultInfo.size); 117 } 118 }); 119 120 t.it('rotates images', async () => { 121 const result = await ImageManipulator.manipulateAsync(image.localUri, [{ rotate: 45 }]); 122 t.expect(result.width).toBeGreaterThan(image.width); 123 }); 124 125 t.it('flips horizontally', async () => { 126 const result = await ImageManipulator.manipulateAsync(image.localUri, [ 127 { flip: ImageManipulator.FlipType.Horizontal }, 128 ]); 129 t.expect(result.width).toBe(image.width); 130 t.expect(result.height).toBe(image.height); 131 }); 132 133 t.it('flips vertically', async () => { 134 const result = await ImageManipulator.manipulateAsync(image.localUri, [ 135 { flip: ImageManipulator.FlipType.Vertical }, 136 ]); 137 t.expect(result.width).toBe(image.width); 138 t.expect(result.height).toBe(image.height); 139 }); 140 141 t.it('resizes image', async () => { 142 const result = await ImageManipulator.manipulateAsync(image.localUri, [ 143 { resize: { width: 100, height: 100 } }, 144 ]); 145 t.expect(result.height).toBe(100); 146 t.expect(result.width).toBe(100); 147 }); 148 149 t.it('crops image', async () => { 150 const result = await ImageManipulator.manipulateAsync(image.localUri, [ 151 { crop: { originX: 20, originY: 20, width: 100, height: 100 } }, 152 ]); 153 t.expect(result.height).toBe(100); 154 t.expect(result.width).toBe(100); 155 }); 156 157 t.it('performs multiple transformations', async () => { 158 const result = await ImageManipulator.manipulateAsync(image.localUri, [ 159 { resize: { width: 200, height: 200 } }, 160 { flip: ImageManipulator.FlipType.Vertical }, 161 { rotate: 45 }, 162 { crop: { originX: 20, originY: 20, width: 100, height: 100 } }, 163 ]); 164 t.expect(result.height).toBe(100); 165 t.expect(result.width).toBe(100); 166 }); 167 }); 168 }); 169} 170