EDIT: I noticed that subarray was always empty. Set might or might not work but subarray doesn't.
I am building a react-native app with expo based on https://github.com/t3-oss/create-t3-turbo. The jsEngine is set to jsc because the app uses tensorflow-js that doesn't work with hermes (https://github.com/tensorflow/tfjs/issues/6526).
I need to crop jpeg images and wrote the following:
export function cropJpegFromBufferToBuffer(
buffer: Buffer,
in_width: number,
in_height: number,
x: number,
y: number,
width: number,
height: number,
): Buffer {
// Ensure the crop dimensions are within bounds
if (x < 0 || y < 0 || x + width > in_width || y + height > in_height) {
throw new Error("Crop dimensions are out of bounds");
}
// Create a new ArrayBuffer for the cropped image data
const croppedData = new ArrayBuffer(width * height * 4);
const croppedDataView = new Uint8Array(croppedData);
// Copy the cropped portion of the image data
for (let row = y; row < y + height; row++) {
const srcOffset = (row * in_width + x) * 4;
const destOffset = (row - y) * width * 4;
console.log(
JSON.stringify({
row: row,
max: y + height,
srcOffset: srcOffset,
destOffset: destOffset,
length: width * height * 4,
destOffsetMoreThanLength: destOffset > width * height * 4,
width: width,
subArrayLength: buffer.subarray(srcOffset, srcOffset + width * 4)
.length,
buffer: buffer.length,
subArrayZeros: buffer
.subarray(srcOffset, srcOffset + width * 4)
.filter((v) => v === 0).length,
croppedDataViewZeros: croppedDataView.filter((v) => v === 0).length,
}),
);
croppedDataView.set(
buffer.subarray(srcOffset, srcOffset + width * 4),
destOffset,
);
}
const b = Buffer.from(croppedDataView);
return b;
}
It always log something like this:
LOG {"row":183,"max":364,"srcOffset":586332,"destOffset":0,"length":143352,"destOffsetMoreThanLength":false,"width":198,"subArrayLength":0,"buffer":269782,"subArrayZeros":0,"croppedDataViewZeros":143352}
where we can see that subarray result is always empty. I tried to log the code of subarray but it only says [native code] and couldn't peak at it to understand what was happening.
If I execute this function outside of expo (tried ios simulator and device via expo-go), in a jest test, it works as expected and logs:
{"row":198,"max":200,"srcOffset":380560,"destOffset":118400,"length":120000,"destOffsetMoreThanLength":false,"width":200,"subArrayZeros":0,"croppedDataViewZeros":2088}
I looked at lightweight libraries to perform cropping expo/react-native apps but found none that worked reliably / I could understand how to use it (ffmpeg works, but it's not very lightweight for simple buffer cropping).