resize image using backend;add resize radio button

frontend resize image will reduce image quality
This commit is contained in:
Qing
2021-11-27 20:37:37 +08:00
committed by Sanster
parent 1c2e7fa559
commit 1e2c8fd348
9 changed files with 163 additions and 144 deletions

View File

@@ -4,7 +4,6 @@ import { useWindowSize } from 'react-use'
import Button from './components/Button'
import FileSelect from './components/FileSelect'
import Editor from './Editor'
import { resizeImageFile } from './utils'
function App() {
const [file, setFile] = useState<File>()

View File

@@ -1,10 +1,11 @@
import { DownloadIcon, EyeIcon } from '@heroicons/react/outline'
import React, { useCallback, useEffect, useState } from 'react'
import { useWindowSize } from 'react-use'
import { useWindowSize, useLocalStorage } from 'react-use'
import inpaint from './adapters/inpainting'
import Button from './components/Button'
import Slider from './components/Slider'
import { downloadImage, loadImage, shareImage, useImage } from './utils'
import SizeSelector from './components/SizeSelector'
import { downloadImage, loadImage, useImage } from './utils'
const TOOLBAR_SIZE = 200
const BRUSH_COLOR = 'rgba(189, 255, 1, 0.75)'
@@ -55,6 +56,8 @@ export default function Editor(props: EditorProps) {
const [isInpaintingLoading, setIsInpaintingLoading] = useState(false)
const [showSeparator, setShowSeparator] = useState(false)
const [scale, setScale] = useState(1)
// ['1080', '2000', 'Original']
const [sizeLimit, setSizeLimit] = useLocalStorage('sizeLimit', '1080')
const windowSize = useWindowSize()
const draw = useCallback(() => {
@@ -144,8 +147,7 @@ export default function Editor(props: EditorProps) {
window.removeEventListener('mouseup', onPointerUp)
refreshCanvasMask()
try {
const start = Date.now()
const res = await inpaint(file, maskCanvas.toDataURL())
const res = await inpaint(file, maskCanvas.toDataURL(), sizeLimit)
if (!res) {
throw new Error('empty response')
}
@@ -221,6 +223,7 @@ export default function Editor(props: EditorProps) {
original.naturalHeight,
original.naturalWidth,
scale,
sizeLimit,
])
const undo = useCallback(() => {
@@ -252,12 +255,16 @@ export default function Editor(props: EditorProps) {
}, [renders, undo])
function download() {
const base64 = context?.canvas.toDataURL(file.type)
if (!base64) {
throw new Error('could not get canvas data')
}
const name = file.name.replace(/(\.[\w\d_-]+)$/i, '_cleanup$1')
downloadImage(base64, name)
const currRender = renders[renders.length - 1]
downloadImage(currRender.currentSrc, name)
}
const onSizeLimitChange = (_sizeLimit: string) => {
// TODO: clean renders
// if (renders.length !== 0) {
// }
setSizeLimit(_sizeLimit)
}
return (
@@ -337,7 +344,7 @@ export default function Editor(props: EditorProps) {
<div
className={[
'flex items-center w-full max-w-3xl',
'flex items-center w-full max-w-5xl',
'space-x-3 sm:space-x-5',
'p-6',
scale !== 1
@@ -345,10 +352,15 @@ export default function Editor(props: EditorProps) {
: 'relative justify-evenly sm:justify-between',
].join(' ')}
>
<SizeSelector
value={sizeLimit}
onChange={onSizeLimitChange}
originalSize={`${original.naturalWidth}x${original.naturalHeight}`}
/>
<Slider
label={
<span>
<span className="hidden md:inline">Brush</span> Size
<span className="hidden md:inline">Brush</span>
</span>
}
min={10}

View File

@@ -2,12 +2,23 @@ import { dataURItoBlob } from '../utils'
export const API_ENDPOINT = `${process.env.REACT_APP_INPAINTING_URL}/inpaint`
export default async function inpaint(imageFile: File, maskBase64: string) {
export default async function inpaint(
imageFile: File,
maskBase64: string,
sizeLimit?: string
) {
// 1080, 2000, Original
const fd = new FormData()
fd.append('image', imageFile)
const mask = dataURItoBlob(maskBase64)
fd.append('mask', mask)
if (sizeLimit === undefined) {
fd.append('sizeLimit', '1080')
} else {
fd.append('sizeLimit', sizeLimit)
}
const res = await fetch(API_ENDPOINT, {
method: 'POST',
body: fd,

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,56 @@
import React from 'react'
import { RadioGroup } from '@headlessui/react'
const sizes = [
['1080', '1080'],
['2000', '2k'],
['Original', 'Original'],
]
type SizeSelectorProps = {
value?: string
originalSize: string
onChange: (value: string) => void
}
export default function SizeSelector(props: SizeSelectorProps) {
const { value, originalSize, onChange } = props
return (
<RadioGroup
className="my-4 flex items-center space-x-2"
value={value}
onChange={onChange}
>
<RadioGroup.Label>Resize</RadioGroup.Label>
{sizes.map(size => (
<RadioGroup.Option key={size[0]} value={size[0]}>
{({ checked }) => (
<div
className={[
checked ? 'bg-gray-200' : 'border-opacity-10',
'border-3 px-2 py-2 rounded-md',
].join(' ')}
>
<div className="flex items-center space-x-4">
<div
className={[
'rounded-full w-5 h-5 border-4 ',
checked
? 'border-primary bg-black'
: 'border-black border-opacity-10',
].join(' ')}
/>
{size[0] === 'Original' ? (
<span>{`${size[1]}(${originalSize})`}</span>
) : (
<span>{size[1]}</span>
)}
</div>
</div>
)}
</RadioGroup.Option>
))}
</RadioGroup>
)
}