refactor: work with percentage crops

This commit is contained in:
Mary
2024-05-08 12:03:47 +07:00
parent 9a260c944b
commit dda330f0a0
2 changed files with 29 additions and 25 deletions
@@ -2,10 +2,12 @@ import 'react-image-crop/dist/ReactCrop.css'
import React from 'react' import React from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {Path, Svg} from 'react-native-svg'
import {msg, Trans} from '@lingui/macro' import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import ReactCrop, {PixelCrop} from 'react-image-crop' import ReactCrop, {PercentCrop} from 'react-image-crop'
import {manipulateImage} from '#/state/gallery'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
import {Button, ButtonText} from '#/components/Button' import {Button, ButtonText} from '#/components/Button'
import * as Dialog from '#/components/Dialog' import * as Dialog from '#/components/Dialog'
@@ -30,15 +32,15 @@ const EditImageInner = ({control, image, onChange}: EditImageDialogProps) => {
const {initialCrop, initialAspect, sourceAspect} = React.useMemo(() => { const {initialCrop, initialAspect, sourceAspect} = React.useMemo(() => {
const initialArea = manips?.crop const initialArea = manips?.crop
let crop: PixelCrop | undefined let crop: PercentCrop | undefined
if (initialArea) { if (initialArea) {
crop = { crop = {
unit: 'px', unit: '%',
x: initialArea.originX, x: (initialArea.originX / source.width) * 100,
y: initialArea.originY, y: (initialArea.originY / source.height) * 100,
width: initialArea.width, width: (initialArea.width / source.width) * 100,
height: initialArea.height, height: (initialArea.height / source.height) * 100,
} }
} }
@@ -46,7 +48,9 @@ const EditImageInner = ({control, image, onChange}: EditImageDialogProps) => {
return { return {
initialCrop: crop, initialCrop: crop,
initialAspect: crop ? crop.width / crop.height : originalAspect, initialAspect: initialArea
? initialArea.width / initialArea.height
: originalAspect,
sourceAspect: originalAspect, sourceAspect: originalAspect,
} }
}, [source, manips]) }, [source, manips])
@@ -61,17 +65,17 @@ const EditImageInner = ({control, image, onChange}: EditImageDialogProps) => {
const result = await manipulateImage(image, { const result = await manipulateImage(image, {
crop: !isEmpty crop: !isEmpty
? { ? {
originX: crop.x, originX: (crop.x * source.width) / 100,
originY: crop.y, originY: (crop.y * source.height) / 100,
width: crop.width, width: (crop.width * source.width) / 100,
height: crop.height, height: (crop.height * source.height) / 100,
} }
: undefined, : undefined,
}) })
onChange(result) onChange(result)
control.close() control.close()
}, [crop, isEmpty, image, control, onChange]) }, [crop, isEmpty, image, source, control, onChange])
const changeAspect = (next: number) => { const changeAspect = (next: number) => {
if (next !== aspect) { if (next !== aspect) {
@@ -90,7 +94,7 @@ const EditImageInner = ({control, image, onChange}: EditImageDialogProps) => {
<ReactCrop <ReactCrop
aspect={aspect} aspect={aspect}
crop={crop} crop={crop}
onChange={setCrop} onChange={(_, next) => setCrop(next)}
className="ReactCrop--no-animate"> className="ReactCrop--no-animate">
<img src={source.path} style={{maxHeight: `50vh`}} /> <img src={source.path} style={{maxHeight: `50vh`}} />
</ReactCrop> </ReactCrop>
@@ -183,6 +187,3 @@ const ToolbarButton = ({
</Button> </Button>
) )
} }
import {Path, Svg} from 'react-native-svg'
import {manipulateImage} from '#/state/gallery'
+11 -8
View File
@@ -5,7 +5,7 @@ import {manipulateAsync, SaveFormat} from 'expo-image-manipulator'
import {LinearGradient} from 'expo-linear-gradient' import {LinearGradient} from 'expo-linear-gradient'
import {msg, Trans} from '@lingui/macro' import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import ReactCrop, {PixelCrop} from 'react-image-crop' import ReactCrop, {PercentCrop} from 'react-image-crop'
import {useModalControls} from '#/state/modals' import {useModalControls} from '#/state/modals'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
@@ -27,7 +27,8 @@ export function Component({
const {closeModal} = useModalControls() const {closeModal} = useModalControls()
const [crop, setCrop] = React.useState<PixelCrop>() const imageRef = React.useRef<HTMLImageElement>(null)
const [crop, setCrop] = React.useState<PercentCrop>()
const isEmpty = !crop || (crop.width || crop.height) === 0 const isEmpty = !crop || (crop.width || crop.height) === 0
@@ -37,15 +38,17 @@ export function Component({
} }
const onPressDone = async () => { const onPressDone = async () => {
if (!isEmpty) { if (!isEmpty) {
const img = imageRef.current!
const result = await manipulateAsync( const result = await manipulateAsync(
uri, uri,
[ [
{ {
crop: { crop: {
originX: crop.x, originX: (crop.x * img.width) / 100,
originY: crop.y, originY: (crop.y * img.height) / 100,
width: crop.width, width: (crop.width * img.width) / 100,
height: crop.height, height: (crop.height * img.height) / 100,
}, },
}, },
], ],
@@ -72,8 +75,8 @@ export function Component({
return ( return (
<View> <View>
<View style={[styles.cropper, pal.borderDark]}> <View style={[styles.cropper, pal.borderDark]}>
<ReactCrop crop={crop} onChange={setCrop}> <ReactCrop crop={crop} onChange={(_, next) => setCrop(next)}>
<img src={uri} style={{maxHeight: '75vh'}} /> <img ref={imageRef} src={uri} style={{maxHeight: '75vh'}} />
</ReactCrop> </ReactCrop>
</View> </View>
<View style={styles.btns}> <View style={styles.btns}>