Monogame: Implement PNG and JPG Reader/Writer

Created on 25 Apr 2014  Â·  24Comments  Â·  Source: MonoGame/MonoGame

Our current path of using platform provided PNG/JPG readers/writers is unreliable. Not implemented one some platforms, threading issues on others, and generally different behaviors across all platforms.

We want to remove these platform differences by including our own simple implementations written purely in C#. Some rules for these readers/writers:

  • Requires no extra binary dependencies.
  • Single source file.
  • Must be safe to read/write PNGs from multiple threads simultaneously.
  • No GPL or LGPL licenses.
  • Readers should be pretty flexible.
  • Writes need little flexibility if any.

For PNG we talked about these for readers...

http://code.google.com/p/pngcs/
http://lodev.org/lodepng/
http://lodev.org/lodepng/picopng.cpp

PicoPNG seems like the best choice being under 500 lines of code, but it needs conversion to C#.

We haven't identified a good PNG writer yet.

For JPEG we have a few suggestions...

http://keyj.emphy.de/nanojpeg/
https://github.com/Deathspike/NanoJPEG.NET
http://code.google.com/p/fjcore/

NanoJPG which already has a C# port seems like the best choice so far.

We haven't identified a good JPG writer yet.

We will put these implementations into the existing utilities folder:

https://github.com/mono/MonoGame/tree/develop/MonoGame.Framework/Utilities

... one file for each with names like PngReader, PngWriter, JpgReader, JpgWriter. We change their namespace to be within MonoGame.Utilities and make sure API feels sufficiently C# like and common possibly passing a Stream to them directly. We need to make sure the only things public are the external API to use the library. We will keep all the original author comments and license info for attribution of the original work.

We would then use these helpers across all platforms removing all platform specific PNG/JPG code within MonoGame.

Feature Request

All 24 comments

I have some 'me' time on Sunday so I'll take a crack at this.

In plain C, I've had excellent luck with stb_image.c. It is a single source file containing decoders/encoders for most common image formats. Huge props to Sean Barrett for releasing this to the public domain.

The memory-only API is compilable with C++/CLI and it appears that you can use that to generate a Mono-compatible assembly. Although implementing single-file C# decoders/encoders would be awesome, this might be worth a try first. (And even if it doesn't work out, stb_image is still excellent reference material.)

Edit: memory-only as in #define STBI_NO_STDIO

while fun, stb_image.c only supports 8 bpc PNG ... some of the MonoGame users are using CLUT based PNG-8 files.

Good idea though.

stb_image.c appears to do some de-palette operations (see line 2734). The file could be converted to csharp easily by someone with good C experience. It even claims to support a little TGA:

TGA (not sure what subset, if a subset)

Bonus! He also has setup data structures that are SIMD-ready. So one could make use of:

http://www.nuget.org/packages/Microsoft.Bcl.Simd

for desktop decoding of images, or devices that support SIMD extensions in .NET ...

Remember the goal here is not to support every file format ever. It is simply to solve the most common PNG/JPG cases for the FromStream() and SaveAs APIs.

XNA and MonoGame are focused on the content pipeline... we will not pervert the design by supporting dozens of ridiculous image formats. Even if it is easy to support... we won't do it.

If stb_image has good routines for PNG and JPEG then lets use those, but we need nothing else from it.

I've spent half an hour porting stb_image to C++/CLI. This is compiled with /clr:pure and /NODEFAULTLIB, and should, in theory, run on Mono.

https://github.com/thefiddler/stb_image/

I won't be able to spend any more time on this for the foreseeable future, but it might be a good starting point for someone. What is still missing is a public API (PngReader / JpgReader) to wrap stbi_load_from_memory and stbi_info_from_memory. Alternatively, one could use a decompiler to port this to C#.

The code is in the public domain and can be used at will.

hey i just saw this, i was doing tons of from file stuff in xna , since mono-game is using mono right
why not just include the system.drawing bitmap/image
i dunno maybe its not thread safe or what not i tried to use that load png before
then i was like oh this exist i have a entire color-array manipulation class built on it
that does everything

https://github.com/mono/sysdrawing-coregraphics/blob/master/System.Drawing/Image.cs
https://github.com/mono/sysdrawing-coregraphics/blob/master/System.Drawing/Bitmap.cs

since mono-game is using mono right

It only uses Mono on some platforms, not all, which is part of the problem.

ah i c
edit : ok i spent hours looking thru this stuff lol
i was looking thru wc3. org 's png site http://www.w3.org/TR/PNG/index-noobject.html and found the below reference thru that
http://www.libpng.org/pub/png/libpng.html _this might be worth a look not 100% but
it appears these are the guys that made the png format and have a open source lib_
here is the source link http://sourceforge.net/p/libpng/code/ci/master/tree/

For Dxt algorithms this looks pretty good , it looks like it can do png also.
( might be worth a look )
this has dxt 1 3 and 5 support the 3 major ones and simd support,
its under the mit license
https://code.google.com/p/libsquish/ in his links there are some others

im no lawyer so not sure about the copyrights, i always get mixed up, looking at that type of stuff

there appears to also be a few jpeg open source projects the first one here has arm support
but im not sure if their bsd is ok
http://sourceforge.net/projects/libjpeg-turbo/ , http://www.openjpeg.org/ , http://www.ijg.org/
the wc3 page for jpeg is under graphics at the wc3 site

Doesn't look like stb_Image_write can handle jpgs just PNG and BMP https://github.com/nothings/stb/blob/master/stb_image_write.h

extern int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
extern int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
extern int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);

right now we only require readers so this could work for us but I'm going to hunt around a little more.

We also need the resizing option in .FromStream so stb_image_resize would work there. Though there no guarantee of pixel equivalence with WIndows or any other platforms resize code.

I found this which has read/write and resize http://www.imagemagick.org/index.php and is Apache 2.0. I dont know how easy it is to pull apart though its a significant code base.

stb is good because it is truly public domain and it is simple. It does
one job and does it well.​ He only recently added the resize module, which
is convenient.

Yeah I like the look of it but with no JPG writer we'd have to go and source that from libJPG or something else anyway.

Or I can cop out and only do the bits _I_ need but that's not nice :-)

I found a fairly simple C# JPEG encoder here...

http://www.codeproject.com/Articles/83225/A-Simple-JPEG-Encoder-in-C

... could be paired up with C# ported STB code to get a complete PNG/JPEG reader/writer combo.

I talked to some Microsoft folk and got background info.

The PNG/JPG reader writer, resizer is a wrapper around WIC http://msdn.microsoft.com/en-us/library/windows/desktop/ee719902(v=vs.85).aspx

It uses WIC for all operations including the resize and clipping and uses BiCubic filtering for resize operations.

I found a fully managed JPG reader and Writer here https://github.com/BitMiracle

I note that from stream also supports GIF http://msdn.microsoft.com/en-us/library/ff434103.aspx

Though there's no GIF writer required only PNG and JPG http://msdn.microsoft.com/en-us/library/Microsoft.Xna.Framework.Graphics.Texture2D_methods.aspx

This is one of the last things I need for guncraft so I am going to have to make some choices soon :-)

I don't want to see us add a dependency on another assembly if we can avoid it. Unless that assembly is PCL and solves JPEG and PNG reading and writing.

IMO the best path forward still seems to be porting some code from stb_image.c.

BitMiracle is Open source and has a decent license - I was just going to grab the code. I've been testing pngcs and its also a good implementation of the standard.

stb_image doesn't have a JPG writer and nobody should have to write that code ever...

stb_image doesn't have a JPG writer

That is why I linked this a few days ago...

http://www.codeproject.com/Articles/83225/A-Simple-JPEG-Encoder-in-C

A simple JPG encoder in 2 or 3 source files.

If someone wants to do those ports that's cool... I'm just more comfortable in c# so if you prefer C ports then I will defer to someone else.

We only need PNG anyway so I'll take the fast track in our fork and just use one of the c# PNG implementations.

if you prefer C ports then I will defer to someone else.

I don't prefer C ports. What i prefer is the least amount of code/source files that get the job done.

Note that link I posted was C# code and not C... the URL is just stupid.

I have a basic PNG reader/writer going, implemented from spec and using source from ZLIB.NET (which is BSD licensed) for the Deflate compression algorithm.

I'm working on making it a bit more robust; a pull request should be forthcoming later this week.

@disportium - Cool... i'm looking forward to it.

We're using StbImageSharp now! :)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

MichaelDePiazzi picture MichaelDePiazzi  Â·  4Comments

harry-cpp picture harry-cpp  Â·  5Comments

monsieurmax picture monsieurmax  Â·  5Comments

griseus picture griseus  Â·  5Comments

willmotil picture willmotil  Â·  5Comments