Page 1 of 1

Getting PNG image info

Posted: 30 Oct 2015, 22:39
by duppy
Hi, I just wanted to share a function to get a PNG image's info, like its width, height, bits per pixel, etc. It's accomplished by simply reading the first 33 bytes of the file. The other methods I saw required using DLLs (GDIp), or creating a hidden GUI picture control, or shelling out to run IrfanView....all of them a bit overly complicated in my opinion. Here's the code:

Code: Select all

get_png_image_info(filename) {
	file := FileOpen(filename, "r")
	if !IsObject(file)
	{
		print_line("Error: Can't open '" filename "' for reading.")
		return
	}

	; note: PNG is stored in big-endian format
	signature := file.ReadInt64()
	if signature != 0xa1a0a0d474e5089
	{
		print_line("Error: Not a PNG file")
		return
	}

	file.ReadUInt() ; skip 4 bytes (IHDR's length)

	IHDR_tag := file.ReadInt()
	if IHDR_tag != 0x52444849
	{
		print_line("Error: IHDR expected as first chunk.")
		return
	}

	width := byte_swap_32(file.ReadUInt())
	height := byte_swap_32(file.ReadUInt())
	bpp := file.ReadUChar()         ; valid values are 1, 2, 4, 8, and 16
	colortype := file.ReadUChar()   ; valid values are 0, 2, 3, 4, and 6.
	compression := file.ReadUChar() ; usually 0 for deflate/inflate
	filter := file.ReadUChar()      ; usually 0
	interlace := file.ReadUChar()   ; 0 = none, 1 = Adam7

	return { width: width
		   , height: height
		   , bpp: bpp
		   , colortype: colortype
		   , compression: compression
		   , filter: filter
		   , interlace: interlace
		   , filename: filename }
}

; change endian-ness for 32-bit integer
byte_swap_32(x) {
	return ((x >> 24) & 0xff)
		 | ((x <<  8) & 0xff0000)
		 | ((x >>  8) & 0xff00)
		 | ((x << 24) & 0xff000000)
}

print_line(str) { ; output line to STDOUT for debugging in my text editor (sublime)
	FileAppend, %str%`n, *
}
It's obviously limited to PNG files, but that's all I need currently (maybe I'll add JPG, BMP, GIF later). Here's a simple example to print out (to STDOUT) the info for all PNG images in a folder:

Code: Select all

Loop, Files, d:\pics\*.png
{
	imageInfo := get_png_image_info(A_LoopFileFullPath)
	if imageInfo
	{
		print_line("""" imageInfo.filename """`n`t"
 		         . "width: " imageInfo.width
 		         . ", height: " imageInfo.height
 		         . ", bpp: " imageInfo.bpp
 		         . ", color type: " imageInfo.colortype
 		         . ", compression: " imageInfo.compression
 		         . ", filter: " imageInfo.filter
 		         . ", interlace: " imageInfo.interlace)
	}
}
Comments/questions/critiques are welcome.