From d87c232660f215608c26280f4cfbd5af3948f9d1 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Wed, 27 Sep 2023 09:08:21 -0700 Subject: [PATCH] Improve image cropping on android and introduce aspect ratio field (#1525) * Fix image cropping on android * Store and use aspect ratio field in post images (close #1392) --- src/lib/api/index.ts | 2 ++ src/state/models/media/image.ts | 13 +++++++++---- src/view/com/util/images/AutoSizedImage.tsx | 4 +++- src/view/com/util/post-embeds/index.tsx | 9 +++++++-- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/lib/api/index.ts b/src/lib/api/index.ts index 4ecd320467..8a9389a183 100644 --- a/src/lib/api/index.ts +++ b/src/lib/api/index.ts @@ -133,10 +133,12 @@ export async function post(store: RootStoreModel, opts: PostOpts) { opts.onStateChange?.(`Uploading image #${images.length + 1}...`) await image.compress() const path = image.compressed?.path ?? image.path + const {width, height} = image.compressed || image const res = await uploadBlob(store, path, 'image/jpeg') images.push({ image: res.data.blob, alt: image.altText ?? '', + aspectRatio: {width, height}, }) } diff --git a/src/state/models/media/image.ts b/src/state/models/media/image.ts index 844ecb7782..10aef0ff48 100644 --- a/src/state/models/media/image.ts +++ b/src/state/models/media/image.ts @@ -8,6 +8,7 @@ import {openCropper} from 'lib/media/picker' import {ActionCrop, FlipType, SaveFormat} from 'expo-image-manipulator' import {Position} from 'react-avatar-editor' import {Dimensions} from 'lib/media/types' +import {isIOS} from 'platform/detection' export interface ImageManipulationAttributes { aspectRatio?: '4:3' | '1:1' | '3:4' | 'None' @@ -164,8 +165,13 @@ export class ImageModel implements Omit { // Mobile async crop() { try { - // openCropper requires an output width and height hence - // getting upload dimensions before cropping is necessary. + // NOTE + // on ios, react-native-image-cropper gives really bad quality + // without specifying width and height. on android, however, the + // crop stretches incorrectly if you do specify it. these are + // both separate bugs in the library. we deal with that by + // providing width & height for ios only + // -prf const {width, height} = this.getUploadDimensions({ width: this.width, height: this.height, @@ -175,8 +181,7 @@ export class ImageModel implements Omit { mediaType: 'photo', path: this.path, freeStyleCropEnabled: true, - width, - height, + ...(isIOS ? {width, height} : {}), }) runInAction(() => { diff --git a/src/view/com/util/images/AutoSizedImage.tsx b/src/view/com/util/images/AutoSizedImage.tsx index da2f7ab45d..035e29c25a 100644 --- a/src/view/com/util/images/AutoSizedImage.tsx +++ b/src/view/com/util/images/AutoSizedImage.tsx @@ -11,6 +11,7 @@ const MAX_ASPECT_RATIO = 5 // 5/1 interface Props { alt?: string uri: string + dimensionsHint?: Dimensions onPress?: () => void onLongPress?: () => void onPressIn?: () => void @@ -21,6 +22,7 @@ interface Props { export function AutoSizedImage({ alt, uri, + dimensionsHint, onPress, onLongPress, onPressIn, @@ -29,7 +31,7 @@ export function AutoSizedImage({ }: Props) { const store = useStores() const [dim, setDim] = React.useState( - store.imageSizes.get(uri), + dimensionsHint || store.imageSizes.get(uri), ) const [aspectRatio, setAspectRatio] = React.useState( dim ? calc(dim) : 1, diff --git a/src/view/com/util/post-embeds/index.tsx b/src/view/com/util/post-embeds/index.tsx index ce6da4a1b2..2d79eed8fd 100644 --- a/src/view/com/util/post-embeds/index.tsx +++ b/src/view/com/util/post-embeds/index.tsx @@ -93,7 +93,11 @@ export function PostEmbeds({ const {images} = embed if (images.length > 0) { - const items = embed.images.map(img => ({uri: img.fullsize, alt: img.alt})) + const items = embed.images.map(img => ({ + uri: img.fullsize, + alt: img.alt, + aspectRatio: img.aspectRatio, + })) const openLightbox = (index: number) => { store.shell.openLightbox(new ImagesLightbox(items, index)) } @@ -104,12 +108,13 @@ export function PostEmbeds({ } if (images.length === 1) { - const {alt, thumb} = images[0] + const {alt, thumb, aspectRatio} = images[0] return ( openLightbox(0)} onPressIn={() => onPressIn(0)} style={[