Uint8Array.set has no effect in react-native/expo

51 Views Asked by At

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).

0

There are 0 best solutions below