FileOnQ / Imaging.Heif

A C#/.NET wrapper around libheif for decoding and processing high efficiency image formats (heif, heic).
GNU Lesser General Public License v3.0
15 stars 4 forks source link

Sample Code Throws Debug Assertion Failed Exception #3

Closed SkyeHoefling closed 3 years ago

SkyeHoefling commented 3 years ago

Description

When using the generated NuGet FileOnQ.Imaging.Heif.1.0.0-pr.20 I am unable to run the Save() code as it fails with a VC++ Runtime Library error. See screenshot below

When I run the build locally it works without issue, it only fails when using the generated artifacts from the build.

Local Steps

The build.yml follows a similar set of instructions I am doing locally.

  1. Ensure build tools are all installed
  2. build FileOnQ.Imaging.Heif this will also compile all native binaries
  3. Update NuGets for all ConsoleApp targets
  4. Run console app

The console app will save correctly. If you swap the NuGet out for the generated one it will fail on the save.

Screenshot

image

Additional Information

I am working on putting together getting started docs to make is easier to get up and running. This hasn't been merged into the main branch and can be found in the docs branch.

SkyeHoefling commented 3 years ago

I wonder if there is an issue with how the GitHub Action is installing the build dependency or maybe Visual Studio's VC++ dependencies

SkyeHoefling commented 3 years ago

Right now the major difference I have noticed is I am using Visual Studio v16.10.3 and the build agent is using v16.11.0

local

**********************************************************************
** Visual Studio 2019 Developer Command Prompt v16.10.3
** Copyright (c) 2021 Microsoft Corporation
**********************************************************************

GH action

**********************************************************************
** Visual Studio 2019 Developer Command Prompt v16.11.0
** Copyright (c) 2021 Microsoft Corporation
**********************************************************************
SkyeHoefling commented 3 years ago

I installed a fresh Virtual Machine with Visual Studio 2019 and followed the steps in building.md. I was able to generate a NuGet package that worked on both my host machine and my VM. I am still not 100% sure why the build script isn't generating the NuGet correctly.

Attached is a NuGet generated from my VM FileOnQ.Imaging.Heif.1.0.0-local.25.zip

SkyeHoefling commented 3 years ago

Root Cause - Potentially Found

~~I think I found the problem and it has nothing to do with the build server or build dependencies. The vcxproj is compiling correctly in Debug mode and when I generate the NuGet package locally I am using dotnet pack which generates a debug NuGet package. The build server is using dotnet pack -c Release which generates a NuGet package with release binaries.

There appears to be a compilation issue when building FileOnQ.Imaging.Heif.Encoders in release mode. I am going to do some more investigation but I think if I resolve this the generated package will work~~

When compiling FileOnQ.Imaging.Heif.Encoders in Debug and using that binary in the NuGet file locally everything works as expected. When compiling that binary in Release mode and generating the NuGet we are failing to write to disk correctly. This happens from libjpeg-turbo code. We ran into a similar issue when compiling libheif and have defaulted our libjpeg-turbo compilation to debug mode. This means we should be compiling FileOnQ.Imaging.Heif.Encoders in Debug mode so it can link correctly to a debug assembly of libjpeg-turbo

The custom jpeg encoder loops through the image writing a scan line at a time, consider the code snippet below

while (cinfo.next_scanline < cinfo.image_height) {
    size_t offset_y = cinfo.next_scanline * stride_y;
    const uint8_t* start_y = &row_y[offset_y];
    size_t offset_u = (cinfo.next_scanline / 2) * stride_u;
    const uint8_t* start_u = &row_u[offset_u];
    size_t offset_v = (cinfo.next_scanline / 2) * stride_v;
    const uint8_t* start_v = &row_v[offset_v];

    JOCTET* bufp = buffer[0];
    for (JDIMENSION x = 0; x < cinfo.image_width; ++x) {
        *bufp++ = start_y[x];
        *bufp++ = start_u[x / 2];
        *bufp++ = start_v[x / 2];
    }
    jpeg_write_scanlines(&cinfo, row, 1);
}

The last stement is where the exception is thrown

jpeg_write_scanlines(&cinfo, row, 1);

Resolution

I think once we figure out how to solve #2 we can attempt to build FileOnQ.Imaging.Heif.Encoders in release mode until then let's update the build instructions to be debug mode.

SkyeHoefling commented 3 years ago

This is now considered a duplicate of #2 closing issue

SkyeHoefling commented 3 years ago

I am going to reopen this issue as it isn't a problem with libjpeg-turbo but our JPEG encoder code. When compiling a native application in debug mode all structs are initialized to 0. When you compile it in release mode the struct is not initialized and you have random data. The other problem with our encoder is it was written for non-windows OS most likely macOS or Linux and doesn't handle UTF8 strings correctly.

I did some research and have a proof of concept where I am returning a memory buffer instead of writing to disk. This approach will allow us to encode in C++ and then either return a byte[] or write to disk.