lvandeve / lodepng

PNG encoder and decoder in C and C++.
zlib License
2.04k stars 420 forks source link

Failed to decode png Image [Error Code 58] [WebAssembly] [NodeJS] #134

Open ShivaHaze opened 3 years ago

ShivaHaze commented 3 years ago

Hello,

I'm trying to decode a normal .png file but encouter an error with the code 58 every single time. I can open the picture without any problems, it's not corrupted or anything similar.

The context I'm using this in is WebAssembly (NodeJS).

/* global WebAssembly */

const fs = require('fs')
const path = require('path')

const ImageData = require('@canvas/image-data')

const code = fs.readFileSync(path.join(__dirname, 'lodepng.wasm'))
const wasmModule = new WebAssembly.Module(code)
const instance = new WebAssembly.Instance(wasmModule)

exports.decode = function (input) {
  // Allocate memory to hand over the input data to WASM
  const inputPointer = instance.exports.malloc(input.byteLength)
  const targetView = new Uint8Array(instance.exports.memory.buffer, inputPointer, input.byteLength)

  // Copy input data into WASM readable memory
  targetView.set(input)

  // Allocate metadata (outputPointer, width, and height)
  const metadataPointer = instance.exports.malloc(12)

  // Decode input data
  const error = instance.exports.lodepng_decode32(metadataPointer, metadataPointer + 4, metadataPointer + 8, inputPointer, input.byteLength)

  // Free the input data in WASM land
  instance.exports.free(inputPointer)

  // Guard return value for NULL pointer
  if (error !== 0) {
    instance.exports.free(metadataPointer)
    throw new Error('Failed to decode png image')
  }

  // Read returned metadata
  const metadata = new Uint32Array(instance.exports.memory.buffer, metadataPointer, 3)
  const [outputPointer, width, height] = metadata

  // Free the metadata in WASM land
  instance.exports.free(metadataPointer)

  // Create an empty buffer for the resulting data
  const outputSize = (width * height * 4)
  const output = new Uint8ClampedArray(outputSize)

  // Copy decoded data from WASM memory to JS
  output.set(new Uint8Array(instance.exports.memory.buffer, outputPointer, outputSize))

  // Free WASM copy of decoded data
  instance.exports.free(outputPointer)

  // Return decoded image as raw data
  return new ImageData(output, width, height)
}

The weird part is, when I drastically change the middle part of the source code to this, it works on the second but only the second run! On all other runs it says "RuntimeError: memory access out of bounds"

// Guard return value for NULL pointer
  //if (error !== 0) {
    instance.exports.free(metadataPointer)
    //throw new Error('Failed to decode png image')
  //}

Does anyone know whats going on here? Regards