dloebl / cgif

GIF encoder written in C

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Danke for this repo, a few thoughts/questions, possible funding opportunity

lovell opened this issue · comments

Hi Daniel,

I'm researching permissively-licenced open source GIF encoding libraries to add as a possible dependency of libvips and am very happy to discover this repo, including the huge bonus that it has tests 🎉

I realise this code is less than a month old but it already seems to be well-written and fully-featured, which is a very good sign, thank you.

I have a few questions after briefly reading and testing the code. I suspect these are things you've already thought of but not got round to yet so I can break these out into separate enhancement issues if that's easier.

  • Should constants/structs exposed by the header file be "namespaced" with a consistent CGIF prefix, e.g. CGIFFrameConfig, CGIF_FRAME_ATTR_... etc.?
  • Would allowing for output other than the filesystem e.g. to memory or pipe/stream be something of interest, perhaps by adding a configurable write function pointer to the GIFConfig (CGIFConfig?) struct?
  • I notice there are comments about the endianess of converting 16-bit integers to byte arrays. Are big endian systems something you'd like to support?
  • An initial valgrind report suggests there may be cases where uninitialised memory is being used, where e.g. the use of calloc would be safer than malloc, but this is still something I need to test properly (all_optim appears to segfault randomly).
  • To make things easier for me locally, I've created a small meson configuration file for this repo as it removes most of the pain of (cross-)compilation/testing, as libvips supports many platforms, should that be of interest to you.

I'd be happy to use some of our Open Collective donations to help fund this work, and/or submit PRs where appropriate too.

Hi Lovell,

I'm very happy that you are interested in our GIF encoder! Thanks for all the suggestions.

A bit of background on this GIF encoder:
I've developed this encoder together with my brother @MCLoebl for one of our hobby projects aigram.org/. AIgram is a search tool for anagrams where users also can create GIF animations for anagram pairs (AIgram video).

Your questions:

Should constants/structs exposed by the header file be "namespaced" with a consistent CGIF prefix?

Thanks for mentioning it. We will pay attention to keep names as consistent as possible in the future. We will probably keep the examples that you mentioned as is to guarantee backward compatibility.

Would allowing for output other than the filesystem e.g. to memory or pipe/stream be something of interest?

That was actually the way our encoder worked in a previous version before we published the code on GitHub. In this version, the GIF was kept in memory until closed. We switched to a streaming mode (to file) to keep memory usage stable (not linear with the number of frames). Adding support for a custom write function should be doable and we may include it as an option in the future. I would think of a write callback as follows:
write(void* pContext, const uint8_t* pData, const size_t numBytes)
You require to keep the GIF in memory or does the current method work for you (stream to file)?

Are big-endian systems something you'd like to support?

Yes, it is something we would like to add support for in the future but we did not prioritize this so far. Right now, only little-endian systems are supported. Are you actively working with big-endian systems?

An initial valgrind report suggests there may be cases where uninitialized memory is being used.

Thanks for letting us know! We think this issue only applies to the test, not the encoder itself. In (all_optim.c) the image data (pImageData) was not completely set to a defined state before being passed to the encoding layer. I've resolved this issue accordingly. Other tests might still be affected by this.
Are you still facing issues with all_optim.c?

To make things easier for me locally, I've created a small meson configuration

Sounds interesting. I am not familiar with meson, but we already planned to add a simple Makefile to this repro. Of course, we also would be happy if you would share the meson config file with us.

libvips, funding, further enhancement issues

Please feel free to create further pull requests/issues when necessary. Of course, we would appreciate it if our code is integrated as an external dependency into libvips. Thanks for mentioning funding options, how does that typically work? Would we need a profile on OpenCollective as well? Also, feel free to contact us directly or create additional enhancement issues for further discussions.

Thanks & Best regards,
Daniel

Thank you for the quick and detailed answers, aigram looks great too. If you didn't see I've opened a couple of PRs to cover a few of the topics.

Adding support for a custom write function should be doable and we may include it as an option in the future. I would think of a write callback as follows:
write(void* pContext, const uint8_t* pData, const size_t numBytes)
You require to keep the GIF in memory or does the current method work for you (stream to file)?

libvips uses streaming I/O everywhere and the destination can be a file, pipe or memory buffer etc. Would the void* pContext in this example be an opaque pointer provided by the caller? If so, that makes sense, as it should provide enough of a "hook" for me to store which output stream is involved (I'll probably implement something that builds on GOutputStream in libvips).

Right now, only little-endian systems are supported. Are you actively working with big-endian systems?

Yes, for example libvips is packaged by Debian and Ubuntu for use on IBM s390x mainframes.

Thanks for mentioning funding options, how does that typically work?

You can submit an expense claim via Open Collective and payment is via PayPal. I'll have a chat with the other libvips maintainers and send you a private message with further details - is there an email address I can use?

Would the void* pContext in this example be an opaque pointer provided by the caller?

Yes.
Introducing a write callback should be doable short-term, basically all calls to fwrite would be replaced by writecb(void*, ..)

libvips is packaged by Debian and Ubuntu for use on IBM s390x mainframes

OK. Right now I can think of these two options to add support for big endian:

  1. Detect endianness dynamically on runtime and change byte-order accordingly (the GIF spec requires little-endian for 16bit fields).
  2. Set endianness during compile time (have to check how to do this portably across compilers).

private message with further details - is there an email address I can use?

You can send private messages to this mail: dloebl.2000@gmail.com

Meson provides the endianness of the host, so will work when cross-compiling, via the host_machine.endian() method.

if host_machine.endian() == 'big'
  add_project_arguments(
    '-DBIG_ENDIAN',
    language : 'c'
  )
endif
  • Now big-endian systems are supported as well, and the endianness is detected during runtime.
  • A write callback option is included now (merged from your pull request).

Thanks again for all the excellent suggestions! Just let us know if you would like to include additional features.

Danke schön, das ist wunderbar!