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)
zio/stable
Paul Frazee 2023-09-27 09:08:21 -07:00 committed by GitHub
parent 6325eff938
commit d87c232660
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 21 additions and 7 deletions

View File

@ -133,10 +133,12 @@ export async function post(store: RootStoreModel, opts: PostOpts) {
opts.onStateChange?.(`Uploading image #${images.length + 1}...`) opts.onStateChange?.(`Uploading image #${images.length + 1}...`)
await image.compress() await image.compress()
const path = image.compressed?.path ?? image.path const path = image.compressed?.path ?? image.path
const {width, height} = image.compressed || image
const res = await uploadBlob(store, path, 'image/jpeg') const res = await uploadBlob(store, path, 'image/jpeg')
images.push({ images.push({
image: res.data.blob, image: res.data.blob,
alt: image.altText ?? '', alt: image.altText ?? '',
aspectRatio: {width, height},
}) })
} }

View File

@ -8,6 +8,7 @@ import {openCropper} from 'lib/media/picker'
import {ActionCrop, FlipType, SaveFormat} from 'expo-image-manipulator' import {ActionCrop, FlipType, SaveFormat} from 'expo-image-manipulator'
import {Position} from 'react-avatar-editor' import {Position} from 'react-avatar-editor'
import {Dimensions} from 'lib/media/types' import {Dimensions} from 'lib/media/types'
import {isIOS} from 'platform/detection'
export interface ImageManipulationAttributes { export interface ImageManipulationAttributes {
aspectRatio?: '4:3' | '1:1' | '3:4' | 'None' aspectRatio?: '4:3' | '1:1' | '3:4' | 'None'
@ -164,8 +165,13 @@ export class ImageModel implements Omit<RNImage, 'size'> {
// Mobile // Mobile
async crop() { async crop() {
try { try {
// openCropper requires an output width and height hence // NOTE
// getting upload dimensions before cropping is necessary. // 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({ const {width, height} = this.getUploadDimensions({
width: this.width, width: this.width,
height: this.height, height: this.height,
@ -175,8 +181,7 @@ export class ImageModel implements Omit<RNImage, 'size'> {
mediaType: 'photo', mediaType: 'photo',
path: this.path, path: this.path,
freeStyleCropEnabled: true, freeStyleCropEnabled: true,
width, ...(isIOS ? {width, height} : {}),
height,
}) })
runInAction(() => { runInAction(() => {

View File

@ -11,6 +11,7 @@ const MAX_ASPECT_RATIO = 5 // 5/1
interface Props { interface Props {
alt?: string alt?: string
uri: string uri: string
dimensionsHint?: Dimensions
onPress?: () => void onPress?: () => void
onLongPress?: () => void onLongPress?: () => void
onPressIn?: () => void onPressIn?: () => void
@ -21,6 +22,7 @@ interface Props {
export function AutoSizedImage({ export function AutoSizedImage({
alt, alt,
uri, uri,
dimensionsHint,
onPress, onPress,
onLongPress, onLongPress,
onPressIn, onPressIn,
@ -29,7 +31,7 @@ export function AutoSizedImage({
}: Props) { }: Props) {
const store = useStores() const store = useStores()
const [dim, setDim] = React.useState<Dimensions | undefined>( const [dim, setDim] = React.useState<Dimensions | undefined>(
store.imageSizes.get(uri), dimensionsHint || store.imageSizes.get(uri),
) )
const [aspectRatio, setAspectRatio] = React.useState<number>( const [aspectRatio, setAspectRatio] = React.useState<number>(
dim ? calc(dim) : 1, dim ? calc(dim) : 1,

View File

@ -93,7 +93,11 @@ export function PostEmbeds({
const {images} = embed const {images} = embed
if (images.length > 0) { 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) => { const openLightbox = (index: number) => {
store.shell.openLightbox(new ImagesLightbox(items, index)) store.shell.openLightbox(new ImagesLightbox(items, index))
} }
@ -104,12 +108,13 @@ export function PostEmbeds({
} }
if (images.length === 1) { if (images.length === 1) {
const {alt, thumb} = images[0] const {alt, thumb, aspectRatio} = images[0]
return ( return (
<View style={[styles.imagesContainer, style]}> <View style={[styles.imagesContainer, style]}>
<AutoSizedImage <AutoSizedImage
alt={alt} alt={alt}
uri={thumb} uri={thumb}
dimensionsHint={aspectRatio}
onPress={() => openLightbox(0)} onPress={() => openLightbox(0)}
onPressIn={() => onPressIn(0)} onPressIn={() => onPressIn(0)}
style={[ style={[