0
0
お題は不問!Qiita Engineer Festa 2024で記事投稿!
Qiita Engineer Festa20242024年7月17日まで開催中!

【React + Typescript】複数枚ステージングさせた画像をトリミングしてみよう Part 3

Posted at

投稿者は初心者です。あたたかい目で見守ってくださいますと幸いです。

前回

はじめに

前回に引き続き「複数枚ステージングした画像をトリミングするロジック」の解説、今回はPart3、最終回です。
さて画像のステージング、トリミング、削除と駆け抜けてきましたが、ここでは疑似的に画像をバックエンドに送信するギミックを開発し、本シリーズを〆させていただこうと思います。

Blob形式で画像を保存するロジック

Providerとその型に以下のように追記します。

provider/Context.tsx
    const [isDragging, setIsDragging] = useState<boolean>(false); // ステージングエリアに画像をドラッグしているか
	const [uploadImages, setUploadImages] = useState<string[]>([]); // トリミング画像のプレビュー用配列
	const [originalImages, setOriginalImages] = useState<string[]>([]); // トリミング前のオリジナル画像配列

     // これを追加
	const [binaryImages, setBinaryImages] = useState<Blob[]>([]); // 実際に送信する画像データの配列
 
	const [crops, setCrops] = useState<{ x: number; y: number }[]>(initialCrops); // 画像のトリミング位置の配列
	const [zooms, setZooms] = useState<number[]>(initialZooms); // 画像の拡大率の配列

 const contextValue = {
    ...
    // contextValueにも追加
    binaryImages,
    setBinaryImages,
    ...
};
types/ProviderProps.d.ts
export interface ProviderProps {
	...
    // 追加
	binaryImages: Blob[];
	setBinaryImages: (
		originalImages: Blob[] | ((prev: Blob[]) => Blob[])
	) => void;
	...
}

つづいてuseTrimming.tsxに追記します。

hooks/useTrimming.tsx
// トリミング確定時に発火する関数
const handleTrimmingComplete = ({
    index,
    canvasRef,
}: HandleTrimmingCompleteProps) => {
    
    ...

    // 追加
    // トリミング結果をBlob形式で格納
    canvas.toBlob((blob) => {
        if (blob) {
            const newBinaryImages = [...binaryImages];
            newBinaryImages[index] = blob;
            setBinaryImages(newBinaryImages);
        }
    })
};

適当な場所でbinaryImagesを出力してみます。

スクリーンショット 2024-06-13 154221.png

きちんと保存できているみたいですね!
(トリミングしているので画像ファイルのsizeが変化しています)

疑似的にバックエンドに画像を送信するロジック

useUploadImages.tsxとその型に追記します。

hooks/useUploadImages.tsx
// 疑似的にバックエンドに画像を送信する関数
const handleSendImages = () => {
    // formDataとしてBlobデータを格納
    const formData = new FormData();
    binaryImages.forEach((image) => {
        formData.append("trimmingImage", image);
    });

    // 正しく格納できているか確認
    for (const [key, value] of formData.entries()) {
        console.log(`${key}: ${value}`);
    }
}

return {
    ...
    // 追加
    handleSendImages,
};

配列内のすべての画像をformDataに含め、通常はこれをAPIに乗せて送信します。本シリーズの趣旨ではないので今回は行いません。

types/useUploadImagesProps.d.ts
export interface useUploadImagesProps {

    ...

    // 追加
	handleSendImages: () => void;
}

この疑似送信関数はApp.tsxのButtonから呼び出すことにしましょう。

App.tsx
import { Box, Button } from '@mui/material';
import { UploadImages } from './components';
import { blue } from '@mui/material/colors';
import { useUploadImages } from './hooks';

function App() {
	const { handleSendImages } = useUploadImages();

	return (
		<>
			<Box
				sx={{
					display: 'flex',
					justifyContent: 'center',
					alignItems: 'center',
					flexDirection: 'column',
					gap: '100px',
					width: '1000px',
					maxWidth: '100vw',
					padding: '50px 0',
					margin: '0 auto',
				}}
			>
				<UploadImages />

                {/* 追加 */}
				<Button
					onClick={handleSendImages}
					sx={{ backgroundColor: blue[500] }}
					variant="contained"
				>
					送信
				</Button>
			</Box>
		</>
	);
}

export default App;

これで整いました!コンソールに刮目です!

スクリーンショット 2024-06-13 160414.png

送信ボタンを押下するとステージングしている枚数分だけ、出力されているのがお分かりいただけるかと思います。

おわりに

もっとうまく記事を書けるようになりたい...!!!

今回使用したリポジトリはコチラ!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0