How to write png file from scratch?

Hi,
I want to write a.png file from scratch.
For example a red 8 x 8 pixel square.
Do I need a special library?

Thanks for your input.
You could of course read up on the PNG format and output the file in the correct format yourself using std::ofstream but using a library such as libpng is probably much easier.
Last edited on
https://docs.fileformat.com/image/png/
which tells you that

PNG compression method 0 (the only compression method presently defined for PNG) specifies deflate/inflate compression with a sliding window of at most 32768 bytes. Deflate compression is an LZ77 derivative used in zip, gzip, pkzip, and related programs.

which means that doing it from scratch is a pain in the backside. If you allow yourself a zip library, its not too bad, but if you are going to do that, why not just use a png library and be done with it?

Conclusion: use the library. There are simpler image formats that support little more than an RGB array with a header, but PNG apparently isn't one of them.

There is no uncompressed variant of PNG.
Last edited on
If you are using Windows you can use GDI+ to create the image, and save as PNG.

https://stackoverflow.com/questions/39551863/creating-gdi-bitmaps-in-memory-and-then-saving-as-png

GDI+ can read and write a number of supported image formats.

https://learn.microsoft.com/en-us/windows/win32/gdiplus/-gdiplus-using-image-encoders-and-decoders-use
jonnin: Keep reading.

The compressed data within the zlib datastream is stored as a series of blocks, each of which can represent raw (uncompressed) data, LZ77-compressed data encoded with fixed Huffman codes, or LZ77-compressed data encoded with custom Huffman codes.

Not only is it possible to write uncompressed PNGs, it's quite easy. It's not much harder than writing a Windows bitmap (BMP).

https://www.w3.org/TR/2003/REC-PNG-20031110/
You just need to write the header and then lay out the data in chunks. It can be done in 100-200 lines.
Last edited on
Ah, I saw and misread that. I thought it was saying it was in uncompressed LZW type format (eg zip with compression set to 'store' or 0) not pure raw. That makes it easier...
I found this talking about image magic?
https://stackoverflow.com/questions/36288421/c-create-png-bitmap-from-array-of-numbers

Isn’t there something easier? Then png?
Format doesn’t matter. As long as it is uncompressed

Edit... check this out.
https://stackoverflow.com/questions/32203347/create-a-png-from-an-array-of-bytes

This is exactly what I'm trying to do.

How do I convert the following into C++ code?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
byte[] data = new byte[] {
  // B    G    R    A     B    G    R    A     B    G    R    A
      0,   0, 255, 255,    0,   0,   0, 255,    0, 255,   0, 255,
      0,   0,   0, 255,    0, 255,   0, 255,  255, 255, 255, 255,
      0, 255,   0, 255,    0,   0,   0, 255,  255,   0,   0, 255
  };
  int width = 3;
  int height = 3;

  Bitmap bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
  var bitmapData = bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, bmp.PixelFormat);
  Marshal.Copy(data, 0, bitmapData.Scan0, data.Length);
  bmp.UnlockBits(bitmapData);
  bmp.Save(@"c:\tmp.png");
Last edited on
How do I convert the following into C++ code?
That code is using a library built into .NET to write the PNG, so since C++ doesn't have that capability built-in, to translate that to C++ you'd still need to link to a PNG implementation.

If you don't care about format, what I usually do when I need to output bitmaps is just dump the pixels to a file named whatever.raw and open the file in IrfanView. That's the quickest way to do it, for me.
Thanks for your reply.
Sorry I wasn’t clear. I am using c++ cli and .net
So that above example should do what I want.
Just don’t know how to convert the syntax.
OK. I have something like this

1
2
3
	 Image^ bmp = gcnew Bitmap(8, 8, System::Drawing::Imaging::PixelFormat::Format32bppArgb);

	 bmp.SetPixel(NULL, 0, 0, RGB(255, 255, 255));


but SetPixel doesn't exist...
void SetPixel(int x, int y, COLORREF color)

Are you sure that you need that first NULL?
I don't know. I got that from the link above.

I removed the NULL but that didn't fix it.

I looked on google for it but no one has the problem of SetPixel not showing up.

Edit...
To be clear I need to set a pixel of a bitmap image.

Thanks.
Last edited on
IIRC, the syntax in C++/CLI to access members of managed pointers (T ^) is ->, not ..
Yes I tried that but it doesn't exist.
This code is from the link that George P posted.
However it won't compile. Identifier GdiplusInit undifined.

The first line of the error Says Music_FormB.h(1218,7): warning C4101: 'location': unreferenced local variable

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

#include <windows.h>
#include <objidl.h>
#include <gdiplus.h>
using namespace Gdiplus;
#pragma comment (lib,"Gdiplus.lib")


void drawImage( int width, int height ) {
    GdiplusInit gdiplusinit;

    //Create a bitmap
    Bitmap myBitmap( width, height, PixelFormat32bppARGB );
    Graphics g( &myBitmap );
    Pen blackpen( Color( 255, 0, 0, 0 ), 3 );

    //draw on bitmap
    g.DrawLine( &blackpen, 1, 1, 200, 200 );

    // Save bitmap (as a png)
    CLSID pngClsid;
    int result = GetEncoderClsid( L"image/png", &pngClsid );
    if ( result == -1 )
        throw runtime_error( "GetEncoderClsid" );
    if ( Ok != myBitmap.Save( L"C:\\test\\test.png", &pngClsid, NULL ) )
        throw runtime_error( "Bitmap::Save" );
}
Last edited on
I turned the above into a complete sample program. This is my first time using GDI+, so be sceptical.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <windows.h>
#include <objidl.h>
#include <gdiplus.h>
#pragma comment (lib,"Gdiplus.lib")
using namespace Gdiplus;

#include <algorithm>
#include <vector>

int constexpr width = 400;
int constexpr height = 300;

static constexpr bool not_ok(Gdiplus::Status r) { return r != Gdiplus::Status::Ok; }

int main()
{
  ULONG_PTR token;
  GdiplusStartupInput si;
  GdiplusStartupOutput so;
  // TODO(mbozzi): Ensure (using RAII) that GDIPlus is shut down after all GDI+ objects are dead
  Status r = GdiplusStartup(&token, &si, &so);
  if (not_ok(r)) return 1;

  //Create a bitmap
  Bitmap myBitmap(width, height, PixelFormat32bppARGB);
  Graphics g(&myBitmap);
  SolidBrush b(Color(255, 255, 0, 255));
  g.FillRectangle(&b, 0, 0, width, height);

  // Save bitmap (as a png)
  CLSID pngClsid; 

  { // find the CLSID for PNG encoder
    UINT codec_info_array_size = 0;
    UINT codec_info_array_size_bytes = 0;
    r = GetImageEncodersSize(&codec_info_array_size, &codec_info_array_size_bytes);
    if (not_ok(r)) return 1;

    ImageCodecInfo* codec_info_array = (ImageCodecInfo*)malloc(codec_info_array_size_bytes);
    // NOTE(mbozzi): std::vector<ImageCodecInfo> codec_info_array(codec_info_array_size);
    // is wrong since sizeof(ImageCodecInfo) * codec_info_array_size != codec_info_array_size_bytes
    // GetImageEncoders is (kind of) allocating a FAM; inspect memory if you're curious

    r = GetImageEncoders(codec_info_array_size, codec_info_array_size_bytes, codec_info_array);
    if (not_ok(r)) return 1;

    auto const b = codec_info_array;
    auto const e = codec_info_array + codec_info_array_size;
    auto const i = std::find_if(b, e, [](ImageCodecInfo const& i) { return i.FormatID == ImageFormatPNG; });

    if (i == e) return 1; else pngClsid = i->Clsid;
  }

  r == myBitmap.Save(L".\\test.png", &pngClsid, NULL);
  if (not_ok(r)) return 1;
}
Topic archived. No new replies allowed.