Merge branch 'hailey/swap-out-cropper' into hailey/79fab
This commit is contained in:
+16
-7
@@ -1,5 +1,4 @@
|
||||
import {Image as RNImage} from 'react-native'
|
||||
import {type Image} from 'react-native-image-crop-picker'
|
||||
import uuid from 'react-native-uuid'
|
||||
import {
|
||||
cacheDirectory,
|
||||
@@ -20,17 +19,17 @@ import {Buffer} from 'buffer'
|
||||
import {POST_IMG_MAX} from '#/lib/constants'
|
||||
import {logger} from '#/logger'
|
||||
import {isAndroid, isIOS} from '#/platform/detection'
|
||||
import {type PickerImage} from './picker.shared'
|
||||
import {type Dimensions} from './types'
|
||||
|
||||
export async function compressIfNeeded(
|
||||
img: Image,
|
||||
img: PickerImage,
|
||||
maxSize: number = 1000000,
|
||||
): Promise<Image> {
|
||||
const origUri = `file://${img.path}`
|
||||
): Promise<PickerImage> {
|
||||
if (img.size < maxSize) {
|
||||
return img
|
||||
}
|
||||
const resizedImage = await doResize(origUri, {
|
||||
const resizedImage = await doResize(normalizePath(img.path), {
|
||||
width: img.width,
|
||||
height: img.height,
|
||||
mode: 'stretch',
|
||||
@@ -130,7 +129,10 @@ interface DoResizeOpts {
|
||||
maxSize: number
|
||||
}
|
||||
|
||||
async function doResize(localUri: string, opts: DoResizeOpts): Promise<Image> {
|
||||
async function doResize(
|
||||
localUri: string,
|
||||
opts: DoResizeOpts,
|
||||
): Promise<PickerImage> {
|
||||
// We need to get the dimensions of the image before we resize it. Previously, the library we used allowed us to enter
|
||||
// a "max size", and it would do the "best possible size" calculation for us.
|
||||
// Now instead, we have to supply the final dimensions to the manipulation function instead.
|
||||
@@ -145,6 +147,7 @@ async function doResize(localUri: string, opts: DoResizeOpts): Promise<Image> {
|
||||
let minQualityPercentage = 0
|
||||
let maxQualityPercentage = 101 // exclusive
|
||||
let newDataUri
|
||||
const intermediateUris = []
|
||||
|
||||
while (maxQualityPercentage - minQualityPercentage > 1) {
|
||||
const qualityPercentage = Math.round(
|
||||
@@ -159,6 +162,8 @@ async function doResize(localUri: string, opts: DoResizeOpts): Promise<Image> {
|
||||
},
|
||||
)
|
||||
|
||||
intermediateUris.push(resizeRes.uri)
|
||||
|
||||
const fileInfo = await getInfoAsync(resizeRes.uri)
|
||||
if (!fileInfo.exists) {
|
||||
throw new Error(
|
||||
@@ -178,8 +183,12 @@ async function doResize(localUri: string, opts: DoResizeOpts): Promise<Image> {
|
||||
} else {
|
||||
maxQualityPercentage = qualityPercentage
|
||||
}
|
||||
}
|
||||
|
||||
safeDeleteAsync(resizeRes.uri)
|
||||
for (const intermediateUri of intermediateUris) {
|
||||
if (newDataUri?.path !== normalizePath(intermediateUri)) {
|
||||
safeDeleteAsync(intermediateUri)
|
||||
}
|
||||
}
|
||||
|
||||
if (newDataUri) {
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import {Image as RNImage} from 'react-native-image-crop-picker'
|
||||
|
||||
import {Dimensions} from './types'
|
||||
import {type PickerImage} from './picker.shared'
|
||||
import {type Dimensions} from './types'
|
||||
import {blobToDataUri, getDataUriSize} from './util'
|
||||
|
||||
export async function compressIfNeeded(
|
||||
img: RNImage,
|
||||
img: PickerImage,
|
||||
maxSize: number,
|
||||
): Promise<RNImage> {
|
||||
): Promise<PickerImage> {
|
||||
if (img.size < maxSize) {
|
||||
return img
|
||||
}
|
||||
@@ -69,7 +68,10 @@ interface DoResizeOpts {
|
||||
maxSize: number
|
||||
}
|
||||
|
||||
async function doResize(dataUri: string, opts: DoResizeOpts): Promise<RNImage> {
|
||||
async function doResize(
|
||||
dataUri: string,
|
||||
opts: DoResizeOpts,
|
||||
): Promise<PickerImage> {
|
||||
let newDataUri
|
||||
|
||||
let minQualityPercentage = 0
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
import {
|
||||
Image as RNImage,
|
||||
openCropper as openCropperFn,
|
||||
} from 'react-native-image-crop-picker'
|
||||
import {
|
||||
documentDirectory,
|
||||
getInfoAsync,
|
||||
readDirectoryAsync,
|
||||
} from 'expo-file-system'
|
||||
import ExpoImageCropTool, {type OpenCropperOptions} from 'expo-image-crop-tool'
|
||||
|
||||
import {compressIfNeeded} from './manip'
|
||||
import {CropperOptions} from './types'
|
||||
import {type PickerImage} from './picker.shared'
|
||||
|
||||
async function getFile() {
|
||||
const imagesDir = documentDirectory!
|
||||
@@ -37,18 +34,18 @@ async function getFile() {
|
||||
})
|
||||
}
|
||||
|
||||
export async function openPicker(): Promise<RNImage[]> {
|
||||
export async function openPicker(): Promise<PickerImage[]> {
|
||||
return [await getFile()]
|
||||
}
|
||||
|
||||
export async function openCamera(): Promise<RNImage> {
|
||||
export async function openCamera(): Promise<PickerImage> {
|
||||
return await getFile()
|
||||
}
|
||||
|
||||
export async function openCropper(opts: CropperOptions) {
|
||||
const item = await openCropperFn({
|
||||
export async function openCropper(opts: OpenCropperOptions) {
|
||||
const item = await ExpoImageCropTool.openCropperAsync({
|
||||
...opts,
|
||||
forceJpg: true, // ios only
|
||||
format: 'jpeg',
|
||||
})
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
import {
|
||||
ImagePickerOptions,
|
||||
type ImagePickerOptions,
|
||||
launchImageLibraryAsync,
|
||||
MediaTypeOptions,
|
||||
} from 'expo-image-picker'
|
||||
// TODO: replace global i18n instance with one returned from useLingui -sfn
|
||||
import {t} from '@lingui/macro'
|
||||
|
||||
import * as Toast from '#/view/com/util/Toast'
|
||||
import {getDataUriSize} from './util'
|
||||
|
||||
export type PickerImage = {
|
||||
mime: string
|
||||
height: number
|
||||
width: number
|
||||
path: string
|
||||
size: number
|
||||
}
|
||||
|
||||
export async function openPicker(opts?: ImagePickerOptions) {
|
||||
const response = await launchImageLibraryAsync({
|
||||
exif: false,
|
||||
|
||||
+23
-25
@@ -1,36 +1,34 @@
|
||||
import {
|
||||
Image as RNImage,
|
||||
openCamera as openCameraFn,
|
||||
openCropper as openCropperFn,
|
||||
} from 'react-native-image-crop-picker'
|
||||
import ExpoImageCropTool, {type OpenCropperOptions} from 'expo-image-crop-tool'
|
||||
import {type ImagePickerOptions, launchCameraAsync} from 'expo-image-picker'
|
||||
|
||||
import {CameraOpts, CropperOptions} from './types'
|
||||
export {openPicker} from './picker.shared'
|
||||
export {openPicker, type PickerImage as RNImage} from './picker.shared'
|
||||
|
||||
export async function openCamera(opts: CameraOpts): Promise<RNImage> {
|
||||
const item = await openCameraFn({
|
||||
width: opts.width,
|
||||
height: opts.height,
|
||||
freeStyleCropEnabled: opts.freeStyleCropEnabled,
|
||||
cropperCircleOverlay: opts.cropperCircleOverlay,
|
||||
cropping: false,
|
||||
forceJpg: true, // ios only
|
||||
compressImageQuality: 0.8,
|
||||
})
|
||||
export async function openCamera(customOpts: ImagePickerOptions) {
|
||||
const opts: ImagePickerOptions = {
|
||||
mediaTypes: 'images',
|
||||
...customOpts,
|
||||
}
|
||||
const res = await launchCameraAsync(opts)
|
||||
|
||||
if (!res || !res.assets) {
|
||||
throw new Error('Camera was closed before taking a photo')
|
||||
}
|
||||
|
||||
const asset = res?.assets[0]
|
||||
|
||||
return {
|
||||
path: item.path,
|
||||
mime: item.mime,
|
||||
size: item.size,
|
||||
width: item.width,
|
||||
height: item.height,
|
||||
path: asset.uri,
|
||||
mime: asset.mimeType ?? 'image/jpeg',
|
||||
size: asset.fileSize ?? 0,
|
||||
width: asset.width,
|
||||
height: asset.height,
|
||||
}
|
||||
}
|
||||
|
||||
export async function openCropper(opts: CropperOptions) {
|
||||
const item = await openCropperFn({
|
||||
export async function openCropper(opts: OpenCropperOptions) {
|
||||
const item = await ExpoImageCropTool.openCropperAsync({
|
||||
...opts,
|
||||
forceJpg: true, // ios only
|
||||
format: 'jpeg',
|
||||
})
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
/// <reference lib="dom" />
|
||||
|
||||
import {Image as RNImage} from 'react-native-image-crop-picker'
|
||||
import {type OpenCropperOptions} from 'expo-image-crop-tool'
|
||||
|
||||
import {CameraOpts, CropperOptions} from './types'
|
||||
export {openPicker} from './picker.shared'
|
||||
import {unstable__openModal} from '#/state/modals'
|
||||
import {type PickerImage} from './picker.shared'
|
||||
import {type CameraOpts} from './types'
|
||||
|
||||
export async function openCamera(_opts: CameraOpts): Promise<RNImage> {
|
||||
export {openPicker, type PickerImage as RNImage} from './picker.shared'
|
||||
|
||||
export async function openCamera(_opts: CameraOpts): Promise<PickerImage> {
|
||||
// const mediaType = opts.mediaType || 'photo' TODO
|
||||
throw new Error('TODO')
|
||||
}
|
||||
|
||||
export async function openCropper(opts: CropperOptions): Promise<RNImage> {
|
||||
export async function openCropper(
|
||||
opts: OpenCropperOptions,
|
||||
): Promise<PickerImage> {
|
||||
// TODO handle more opts
|
||||
return new Promise((resolve, reject) => {
|
||||
unstable__openModal({
|
||||
name: 'crop-image',
|
||||
uri: opts.path,
|
||||
dimensions:
|
||||
opts.width && opts.height
|
||||
? {width: opts.width, height: opts.height}
|
||||
: undefined,
|
||||
aspect: opts.webAspectRatio,
|
||||
circular: opts.webCircularCrop,
|
||||
onSelect: (img?: RNImage) => {
|
||||
uri: opts.imageUri,
|
||||
aspect: opts.aspectRatio,
|
||||
circular: opts.shape === 'circle',
|
||||
onSelect: (img?: PickerImage) => {
|
||||
if (img) {
|
||||
resolve(img)
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import {openCropper} from 'react-native-image-crop-picker'
|
||||
|
||||
export interface Dimensions {
|
||||
width: number
|
||||
height: number
|
||||
@@ -17,8 +15,3 @@ export interface CameraOpts {
|
||||
freeStyleCropEnabled?: boolean
|
||||
cropperCircleOverlay?: boolean
|
||||
}
|
||||
|
||||
export type CropperOptions = Parameters<typeof openCropper>[0] & {
|
||||
webAspectRatio?: number
|
||||
webCircularCrop?: boolean
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user