SFML community forums

General => SFML projects => Topic started by: Tenry on March 16, 2014, 10:08:53 pm

Title: libgfx - Image file format (PNG) with custom data
Post by: Tenry on March 16, 2014, 10:08:53 pm
A long time ago, I started a topic (http://en.sfml-dev.org/forums/index.php?topic=9419.msg63899#msg63899) about custom information in the PNG file format, which can be useful to store sprite animation data and other stuff, so you don't need extra data files or your own, possibly quite poor graphics file format, just to get these extra data stored.

Finally, I am working on a library for my current project, that is able to read and even write PNG files with custom chunks, named libgfx. It can even be used for loading and writing PNG files without the need of SFML/sfml-graphics (e.g., if you write a low-overhead console application, that shall read/write PNG files), and it will also convert the pixels data to your need (e.g. to 32-bit RGBA, no matter if the file format is 24-bit RGB or palette). And if I remember well, SFML does not support PNG based on palettes (did it change already?).

Download Beta (0.1.0)
https://github.com/tenry92/libgfx (https://github.com/tenry92/libgfx)

Download Alpha (obsolete)
Source Code + Linux Compiled: libgfx-source-unix.tar.gz (http://www.mediafire.com/download/dkiq0qoiye4d4ym/libgfx-source-unix.tar.gz)
Source Code + Windows Compiled: libgfx-source-win32.zip (http://www.mediafire.com/download/x8ekkqzhgmetrn9/libgfx-source-win32.zip)

Issues
Example writing PNG file with custom chunk:

GfxImage gfx;
gfx.colorFormat = GfxFormat_RGBA;
gfx.bitDepth = 8;
gfx.width = ...; gfx.height = ...;
/* allocate the memory based on the specs given above */
libgfx_createImage(&img);
/* now you can set your data in gfx.pixels */

libgfx_createChunk(&gfx, "isPR");
GfxChunk *myChunk = gfx.userChunks[gfx.nUserChunks - 1];

int err = libgfx_writeGfxFile(&gfx, "output.png");

libgfx_destroyImage(&gfx);

Example reading PNG file with custom chunk:

GfxImage gfx;

/* no matter what the input format is, give me 8-bit RGBA */
gfx.colorFormat = GfxFormat_RGBA;
gfx.bitDepth = 8;

int err = libgfx_loadGfxFile(&gfx, "input.png");
if(err != GfxError_None) return 1; // error occurred

if(gfx.nUserChunks > 0)
{
  GfxChunk *myChunk = gfx.userChunks[0];
  /* do something with the user chunk... */
}

libgfx_destroyImage(&gfx);


EDIT: This is, how I currently use libgfx for loading my graphics into OpenGL, might be useful for you:

GfxImage img;

int ret = libgfx_loadGfxFile(&img, filename);
switch(ret)
{
  case GfxError_None: break;
  default: throw std::runtime_error("Unknown error loading " + filename);
  case GfxError_ColorFormat: case GfxError_BitDepth:
    throw std::runtime_error(filename + ": Color format not supported");
  case GfxError_File: throw std::runtime_error(filename + ": Not found");
  case GfxError_FileFormat: throw std::runtime_error(filename + ": Unknown format");
}

if(img.bitDepth != 8)
  throw std::runtime_error(filename + ": Color format not supported (8-bit rgba expected)");


/* OpenGL usually only supports dimensions like 128x64 or 256x256. */
int nearestWidth = exp2(ceil(log2(img.width)));
int nearestHeight = exp2(ceil(log2(img.height)));

tex->actualWidth = img.width;
tex->actualHeight = img.height;
tex->textureWidth = nearestWidth;
tex->textureHeight = nearestHeight;

/* We need to resize the image to fit OpenGL's requirements. */
if(img.width < nearestWidth || img.height < nearestHeight)
{
  /* resize actual texture. note: pixels out of bounds may have random data */
  std::vector<uint8_t> pixels;
  pixels.resize(nearestWidth * nearestHeight * 4);
 
  for(int y = 0; y < img.height; ++y)
  {
    memcpy(&pixels[y * nearestWidth * 4], &img.pixels[y * img.width * 4],
      img.width * 4);
  }
 
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, nearestWidth, nearestHeight,
    0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
}
/* The image's dimensions already fit the requirements, pass it already. */
else
{
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, nearestWidth, nearestHeight,
    0, GL_RGBA, GL_UNSIGNED_BYTE, img.pixels);
}
Title: libgfx Alpha released!
Post by: Tenry on April 02, 2014, 05:36:23 pm
libgfx 0.0.1 (Alpha) released!

Linux (with source code): libgfx-source-unix.tar.gz (http://www.mediafire.com/download/dkiq0qoiye4d4ym/libgfx-source-unix.tar.gz)
Windows (with source code): libgfx-source-win32.zip (http://www.mediafire.com/download/x8ekkqzhgmetrn9/libgfx-source-win32.zip)
Title: Re: libgfx - Image file format (PNG) with custom data
Post by: Tenry on October 06, 2015, 10:15:14 pm
libgfx 0.0.1 (Beta) released on github!

There have been minor changes and bugfixes in my library and I started using git and publishing it on github (https://github.com/tenry92/libgfx). I forgot to increase the version number, but as it is already working quite well in my projects, I consider it now being beta.

You can go to the github page (https://github.com/tenry92/libgfx) and download the most recent version. It is currently designed to be compiled and installed on a unix or unix-like environment, i.e., it depends (by default) on /usr/local, pkg-config and pre-installed libpng.
Title: Re: libgfx - Image file format (PNG) with custom data
Post by: Nexus on October 07, 2015, 10:01:38 am
That looks interesting! It's surprising that existing PNG libraries don't handle metadata or at least not easily. The feature is probably too rarely used.

Your API uses a strong C style. Don't you want to write it in C directly? It seems like you're hardly using any C++ features anyway. Such low-level libraries are likely to become much more popular when written in C, as they can be used in C code and easily be invoked from other languages.

It would still be fairly trivial to write a C++ wrapper on top. But the current state is not ideal: C++ developers have to use a mix of C and C++ style interfaces, but C developers are not able to work with libgfx because it's written in C++.

By the way, isn't "libgfx" a rather generic name, especially since it doesn't express anything about PNG and metadata? I'd choose something more precise, also to make it easier to search and distinguish your library from other projects named the same.
Title: Re: libgfx - Image file format (PNG) with custom data
Post by: Tenry on October 07, 2015, 06:35:26 pm
Thank you for your feedback :)

It's surprising that existing PNG libraries don't handle metadata or at least not easily. The feature is probably too rarely used.
I'm not sure, if that, what my lib does, can be considered "handling metadata", as it does not handle the author, creation date, comments etc. yet. It only handles the actual image data and private chunks with arbitrary data in it, where you define its format yourself.

Your API uses a strong C style. Don't you want to write it in C directly? It seems like you're hardly using any C++ features anyway. Such low-level libraries are likely to become much more popular when written in C, as they can be used in C code and easily be invoked from other languages.

It would still be fairly trivial to write a C++ wrapper on top. But the current state is not ideal: C++ developers have to use a mix of C and C++ style interfaces, but C developers are not able to work with libgfx because it's written in C++.
I guess, when I started this library, I considered writing it as a pure C library, hence this overall design. Then I wanted to use std::vector for pixels, chunks etc., and you see what happened :D
After reading your response, I reconsidered it, and yeah, pure C would definitely better. So, I'm going to change the implementation a bit, so that it is really pure C then.

By the way, isn't "libgfx" a rather generic name, especially since it doesn't express anything about PNG and metadata? I'd choose something more precise, also to make it easier to search and distinguish your library from other projects named the same.
When developing games, I liked the idea of using my very own graphics format, that exactly fits the needs of my games, and I would have given it the file name extension ".gfx". But why making another graphics format, possibly with poor or no compression, if PNG is already good at it and even officially support private data (chunks), you can embed in your PNG file?
That's where the name comes from. You may even handle the file signature yourself, so I could replace the usual PNG signature with my very own one, disallowing others to open my graphics in an image program that easy :P
So, it could be possible that I will really use that feature of using my own signature and use the .gfx extension, so that not everybody immediately sees, that it's actually a PNG file.

Anyways, do you have an idea for another name? Maybe "metapng", but... as mentioned above, my library is not intended to handle "meta" data, but private chunks and the actual image data.
Title: Re: libgfx - Image file format (PNG) with custom data
Post by: Nexus on October 07, 2015, 07:06:21 pm
There are many sources talking about "metadata", but it seems like "chunks" is the official term [1] (http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html) [2] (https://en.wikipedia.org/wiki/Portable_Network_Graphics#.22Chunks.22_within_the_file).

About names... Some ideas:
Title: Re: libgfx - Image file format (PNG) with custom data
Post by: Tenry on October 07, 2015, 08:19:20 pm
There are many sources talking about "metadata", but it seems like "chunks" is the official term [1] (http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html) [2] (https://en.wikipedia.org/wiki/Portable_Network_Graphics#.22Chunks.22_within_the_file).

About names... Some ideas:
  • "png" + something along "chunk" or "meta"
  • "png" + adjective expressing the versatility or self-containedness
  • use cases in games... something along "attribute", "property", "trait", or better more specific ones
  • names (like I did with Thor). Just don't choose one that will be a movie in the future :P
Thanks for these ideas, I might think about it later.

It's fully ported to C now and my existing project (after minor updates) still loads my png files successfully :)