mirror of
https://github.com/iib0011/omni-tools.git
synced 2025-12-29 16:16:02 +00:00
refactor: tools folder inside pages
This commit is contained in:
148
src/pages/tools/video/gif/change-speed/index.tsx
Normal file
148
src/pages/tools/video/gif/change-speed/index.tsx
Normal file
@@ -0,0 +1,148 @@
|
||||
import { Box } from '@mui/material';
|
||||
import React, { useState } from 'react';
|
||||
import * as Yup from 'yup';
|
||||
import ToolFileInput from '@components/input/ToolFileInput';
|
||||
import ToolFileResult from '@components/result/ToolFileResult';
|
||||
import ToolOptions from '@components/options/ToolOptions';
|
||||
import TextFieldWithDesc from 'components/options/TextFieldWithDesc';
|
||||
import ToolInputAndResult from '@components/ToolInputAndResult';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { FrameOptions, GifReader, GifWriter } from 'omggif';
|
||||
import { gifBinaryToFile } from '../../../../../utils/gif';
|
||||
|
||||
const initialValues = {
|
||||
newSpeed: 200
|
||||
};
|
||||
const validationSchema = Yup.object({
|
||||
// splitSeparator: Yup.string().required('The separator is required')
|
||||
});
|
||||
export default function ChangeSpeed() {
|
||||
const [input, setInput] = useState<File | null>(null);
|
||||
const [result, setResult] = useState<File | null>(null);
|
||||
|
||||
const compute = (optionsValues: typeof initialValues, input: File) => {
|
||||
if (!input) return;
|
||||
const { newSpeed } = optionsValues;
|
||||
|
||||
const processImage = async (file: File, newSpeed: number) => {
|
||||
const reader = new FileReader();
|
||||
reader.readAsArrayBuffer(file);
|
||||
|
||||
reader.onload = async () => {
|
||||
const arrayBuffer = reader.result;
|
||||
|
||||
if (arrayBuffer instanceof ArrayBuffer) {
|
||||
const intArray = new Uint8Array(arrayBuffer);
|
||||
|
||||
const reader = new GifReader(intArray as Buffer);
|
||||
const info = reader.frameInfo(0);
|
||||
const imageDataArr: ImageData[] = new Array(reader.numFrames())
|
||||
.fill(0)
|
||||
.map((_, k) => {
|
||||
const image = new ImageData(info.width, info.height);
|
||||
|
||||
reader.decodeAndBlitFrameRGBA(k, image.data);
|
||||
|
||||
return image;
|
||||
});
|
||||
const gif = new GifWriter(
|
||||
[],
|
||||
imageDataArr[0].width,
|
||||
imageDataArr[0].height,
|
||||
{ loop: 20 }
|
||||
);
|
||||
|
||||
imageDataArr.forEach((imageData) => {
|
||||
const palette = [];
|
||||
const pixels = new Uint8Array(imageData.width * imageData.height);
|
||||
|
||||
const { data } = imageData;
|
||||
for (let j = 0, k = 0, jl = data.length; j < jl; j += 4, k++) {
|
||||
const r = Math.floor(data[j] * 0.1) * 10;
|
||||
const g = Math.floor(data[j + 1] * 0.1) * 10;
|
||||
const b = Math.floor(data[j + 2] * 0.1) * 10;
|
||||
const color = (r << 16) | (g << 8) | (b << 0);
|
||||
|
||||
const index = palette.indexOf(color);
|
||||
|
||||
if (index === -1) {
|
||||
pixels[k] = palette.length;
|
||||
palette.push(color);
|
||||
} else {
|
||||
pixels[k] = index;
|
||||
}
|
||||
}
|
||||
|
||||
// Force palette to be power of 2
|
||||
|
||||
let powof2 = 1;
|
||||
while (powof2 < palette.length) powof2 <<= 1;
|
||||
palette.length = powof2;
|
||||
|
||||
const delay = newSpeed / 10; // Delay in hundredths of a sec (100 = 1s)
|
||||
const options: FrameOptions = {
|
||||
palette,
|
||||
delay
|
||||
};
|
||||
gif.addFrame(
|
||||
0,
|
||||
0,
|
||||
imageData.width,
|
||||
imageData.height,
|
||||
// @ts-ignore
|
||||
pixels,
|
||||
options
|
||||
);
|
||||
});
|
||||
const newFile = gifBinaryToFile(gif.getOutputBuffer(), file.name);
|
||||
|
||||
setResult(newFile);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
processImage(input, newSpeed);
|
||||
};
|
||||
return (
|
||||
<Box>
|
||||
<ToolInputAndResult
|
||||
input={
|
||||
<ToolFileInput
|
||||
value={input}
|
||||
onChange={setInput}
|
||||
accept={['image/gif']}
|
||||
title={'Input GIF'}
|
||||
/>
|
||||
}
|
||||
result={
|
||||
<ToolFileResult
|
||||
title={'Output GIF with new speed'}
|
||||
value={result}
|
||||
extension={'gif'}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<ToolOptions
|
||||
compute={compute}
|
||||
getGroups={({ values, updateField }) => [
|
||||
{
|
||||
title: 'New GIF speed',
|
||||
component: (
|
||||
<Box>
|
||||
<TextFieldWithDesc
|
||||
value={values.newSpeed}
|
||||
onOwnChange={(val) => updateField('newSpeed', Number(val))}
|
||||
description={'Default new GIF speed.'}
|
||||
InputProps={{ endAdornment: <Typography>ms</Typography> }}
|
||||
type={'number'}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
]}
|
||||
initialValues={initialValues}
|
||||
input={input}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
14
src/pages/tools/video/gif/change-speed/meta.ts
Normal file
14
src/pages/tools/video/gif/change-speed/meta.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { defineTool } from '@tools/defineTool';
|
||||
import { lazy } from 'react';
|
||||
// import image from '@assets/text.png';
|
||||
|
||||
export const tool = defineTool('gif', {
|
||||
name: 'Change speed',
|
||||
path: 'change-speed',
|
||||
// image,
|
||||
description:
|
||||
'This online utility lets you change the speed of a GIF animation. You can speed it up or slow it down. You can set the same constant delay between all frames or change the delays of individual frames. You can also play both the input and output GIFs at the same time and compare their speeds',
|
||||
shortDescription: 'Quickly change GIF speed',
|
||||
keywords: ['change', 'speed'],
|
||||
component: lazy(() => import('./index'))
|
||||
});
|
||||
3
src/pages/tools/video/gif/index.ts
Normal file
3
src/pages/tools/video/gif/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { tool as gifChangeSpeed } from './change-speed/meta';
|
||||
|
||||
export const gifTools = [gifChangeSpeed];
|
||||
3
src/pages/tools/video/index.ts
Normal file
3
src/pages/tools/video/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { gifTools } from './gif';
|
||||
|
||||
export const videoTools = [...gifTools];
|
||||
Reference in New Issue
Block a user