Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gifsave output is in grayscale in Avalonia desktop app while is colored as console app without Avalonia package #185

Closed
lanyusan opened this issue Nov 28, 2022 · 8 comments
Labels
bug Something isn't working

Comments

@lanyusan
Copy link

lanyusan commented Nov 28, 2022

Hi,

I have encountered a very strange problem.

I have an inhouse tool for generative art. In console mode without Avalonia all works great.

Now we are developing a desktop app with Avalonia, the same code generated gif output in grayscale.

Would it have something to do with conflicts in some shared libs with Avalonia?

For debugging I have generated each frame in png and also the concatenated multiple page image in png. All seem to be right.

It seems to be the problem with that last gifsave call. Not sure why it happened.

Here is the code:

                    var delayArr = ...; // delays

                    var framesJoined = Image.Arrayjoin(generatedFrames, 1);

                    var frames = framesJoined.Mutate(mutable =>
                    {
                        // Set the number of loops, libvips uses iterations like this:
                        // 0 - set 0 loops (infinite)
                        // 1 - loop once
                        // 2 - loop twice etc.
                        mutable.Set(GValue.GIntType, "loop", 0);

                        // Set the frame delay(s)
                        // We use a 1000ms delay for all frames in this example
                        mutable.Set(GValue.ArrayIntType, "delay", delayArr);

                        // Set page height
                        mutable.Set(GValue.GIntType, "page-height", height);
                    });
                    frames.Pngsave(fileName + "-joined.png");

                    frames.Gifsave(fileName,dither : 0.5, effort : 1, bitdepth : 8);

And sample files:

each frame
1 gif-0
1 gif-1
1 gif-2

joined frames in one png
1 gif-joined

generated gif with gifsave
1

@lanyusan lanyusan changed the title gifsave output is in grayscale in Avalonia desktop app while is colored in batch mode gifsave output is in grayscale in Avalonia desktop app while is colored as console app without Avalonia package Nov 28, 2022
@kleisauke kleisauke added the triage This issue is being investigated label Nov 28, 2022
@kleisauke
Copy link
Owner

kleisauke commented Nov 28, 2022

Was this tested on Linux? Are you able to provide a standalone code sample that exhibits this behavior?

It might possibly collide with the g_object_unref() and g_object_ref() DllImport-attributes here:
https://github.com/AvaloniaUI/Avalonia/blob/a64f57df8a64f5468cd7c6984a545749d0aa8af2/src/Avalonia.X11/NativeDialogs/Gtk.cs#L21
https://github.com/AvaloniaUI/Avalonia/blob/a64f57df8a64f5468cd7c6984a545749d0aa8af2/src/Avalonia.X11/NativeDialogs/Gtk.cs#L28
(hence my question about Linux)

A simple way to sanity check this is to enable libvips' internal mechanism to track and debug reference counts. It can be enabled with the VIPS_LEAK environment variable or by setting NetVips.Leak = true; within NetVips.

@kleisauke
Copy link
Owner

It might possibly collide with the g_object_unref() and g_object_ref() DllImport-attributes

This should not be a issue, at least for C-programs. See for example:

test.c
#include <stdio.h>
#include <vips/vips.h>

int main(int argc, char **argv) {
  VipsImage *in;
  double mean;
  VipsImage *out;

  if (VIPS_INIT(argv[0]))
    vips_error_exit(NULL);

  if (argc != 3)
    vips_error_exit("usage: %s infile outfile", argv[0]);

  vips_leak_set(TRUE);

  if (!(in = vips_image_new_from_file(argv[1], NULL)))
    vips_error_exit(NULL);

  printf("image width = %d\n", vips_image_get_width(in));

  if (vips_avg(in, &mean, NULL))
    vips_error_exit(NULL);

  printf("mean pixel value = %g\n", mean);

  if (vips_invert(in, &out, NULL))
    vips_error_exit(NULL);

  g_object_unref(in);

  if (vips_image_write_to_file(out, argv[2], NULL))
    vips_error_exit(NULL);

  g_object_unref(out);
  
  vips_shutdown();

  return 0;
}
$ mkdir linux-x64
$ curl -fsSL https://github.com/kleisauke/libvips-packaging/releases/download/v8.13.2/libvips-8.13.2-linux-x64.tar.gz | tar xzC linux-x64
$ gcc -O3 -Ilinux-x64/include -Ilinux-x64/include/glib-2.0 -Ilinux-x64/lib/glib-2.0/include test.c -Llinux-x64/lib -l:libvips.so.42 -Wl,-rpath=\$ORIGIN/linux-x64/lib
$ readelf -Wd a.out | grep 'RPATH'
 0x000000000000000f (RPATH)              Library rpath: [$ORIGIN/linux-x64/lib]
$ ./a.out zebra.jpg x.jpg
image width = 4120
mean pixel value = 96.8319
memory: high-water mark 41.81 MB
$ LD_PRELOAD="/lib64/libgobject-2.0.so.0" ./a.out zebra.jpg x.jpg
image width = 4120
mean pixel value = 96.8319
memory: high-water mark 41.62 MB
$ LD_DEBUG=bindings LD_PRELOAD="/lib64/libgobject-2.0.so.0" ./a.out zebra.jpg x.jpg 2>&1 | grep "a.out .* to /lib64/libgobject-2.0.so.0"
   3870775:     binding file ./a.out [0] to /lib64/libgobject-2.0.so.0 [0]: normal symbol `g_object_unref'
$ readelf -Wd linux-x64/lib/libvips.so.42 | grep 'FLAGS\|RPATH'
 0x000000000000000f (RPATH)              Library rpath: [$ORIGIN/]
 0x000000006ffffffb (FLAGS_1)            Flags: NODELETE

That said, I'm not sure if this also applies to C#.

@lanyusan
Copy link
Author

lanyusan commented Nov 29, 2022

Tried on linux, with fedora 37.

Output is in color but with pretty big decline in quality.

Again in console mode all work fine.

Unfortunately pretty busy lately. I will try to put together a reproducible repo with avanolia in the weekend.

group_0_1

group_1_6

@lanyusan
Copy link
Author

lanyusan commented Nov 30, 2022

@kleisauke

I managed to find some time today to create a reproduce repo.

https://github.com/lanyusan/net-vips-avanolia-bug

Please select the folder images under project root.

Output is written to images/out.

For debugging I have also written joined frames before gifsave to output folder.

Thanks for your attention.

@lanyusan
Copy link
Author

lanyusan commented Dec 1, 2022

@kleisauke
I have found a workaround to fix the problem.

                    var pngBuffer = framesJoined.PngsaveBuffer();

                    framesJoined = NetVips.Image.NewFromBuffer(pngBuffer);

So I guess it has something to do with the encoding of composited frames, either my code needs to take care of or it is something gifsave needs to take care of.

I have created a branch fix with the above workaround.

Obviously it is preferrable I don't have to do the above calls.

Thanks.

@kleisauke kleisauke added bug Something isn't working blocked-upstream-dependency Upstream dependency needs to be updated and removed triage This issue is being investigated labels Dec 5, 2022
@kleisauke
Copy link
Owner

Fixed with PR libvips/libvips#3213. It'll be in libvips 8.14, due RSN.

@kleisauke
Copy link
Owner

A release candidate of NetVips.Native v8.14.0 is now available for testing.
https://www.nuget.org/packages/NetVips.Native/8.14.0-rc1

@kleisauke kleisauke removed the blocked-upstream-dependency Upstream dependency needs to be updated label Mar 24, 2023
@kleisauke
Copy link
Owner

NetVips v2.3.0 and NetVips.Native v8.14.2 is now available.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants