Files
red-valley/resources/[framework]/[depends]/phone-render/module/crop.js
2026-03-29 21:41:17 +03:00

55 lines
2.0 KiB
JavaScript

function cropX(imageData, { left = 0, right = 0 }) {
const { data, width, height } = imageData;
const dataLength = data.length;
const newWidth = width - left - right;
const rowLength = width * 4;
const newRowLength = newWidth * 4;
const leftCrop = left * 4;
const newData = [];
// loop through each row
for (let x = 0; x < dataLength; x += rowLength) {
const newRowStart = x + leftCrop;
const newRowEnd = newRowStart + newRowLength;
for (let i = newRowStart; i < newRowEnd; i += 4) {
newData.push(data[i], data[i + 1], data[i + 2], data[i + 3]);
}
}
return { data: newData, height, width: newWidth };
}
function cropY(imageData, { top = 0, bottom = 0 }) {
const { data, width, height } = imageData;
const rowLength = width * 4;
const topIndex = top * rowLength;
const bottomIndex = bottom * rowLength;
const newHeight = height - top - bottom;
const newDataEnd = data.length - bottomIndex;
const newData = [];
// save each index within the cropped area (avoid .slice() for performance)
for (let i = topIndex; i < newDataEnd; i++) {
newData.push(data[i]);
}
return { data: newData, height: newHeight, width };
}
function toNumber(options) {
return Object.fromEntries(Object.entries(options).map(([key, value]) => [key, Number(value || 0)]));
}
export default function cropImageData(imageData, cropOptions) {
const { top, right, bottom, left } = toNumber(cropOptions);
if (imageData.height < top + bottom || imageData.width < left + right) {
return new ImageData(1, 1);
}
let newImageData = {
data: imageData.data,
width: imageData.width,
height: imageData.height,
};
if (top || bottom) {
newImageData = cropY(newImageData, { top, bottom });
}
if (left || right) {
newImageData = cropX(newImageData, { left, right });
}
const { data, height, width } = newImageData;
return new ImageData(Uint8ClampedArray.from(data), width, height);
}