Test images in support of the development of an RGB to GRAY conversion capability in libpng, July 1998.

Images copyright © 1998, Glenn Randers-Pehrson. Permission is granted to reproduce and use the images and included Fortran program for any purpose.

The files mixrgb.png, mix045.png, and mix100.png demonstrate conversion of a color PNG to grayscale.


mixrgb.png:


mixrgb.png is the source, which contains 216 color patches (the so-called "browser safe" palette) against a gray background. It has a gamma of 0.45455, or 1/2.2, as do the two grayscale images.

There are six blocks, each containing a 6 by 6 matrix of patches, with increasing amounts of red from left to right and increasing amounts of green from top to bottom. Each 6 by 6 group has an increasing amount of blue. Pure black is at the top left corner and pure white is at the lower left corner of the entire assembly. The other saturated colors appear at the remaining three corners of the upper left group and remaining three corners of the lower right group.


mix100.png:


mix100.png is the result of converting the image to grayscale, using the equation given in Poynton's ColorFAQ at <http://www.inforamp.net/~poynton/> Copyright © 1998-01-04 Charles Poynton poynton@inforamp.net
     Y = 0.212671 * R + 0.715160 * G + 0.072169 * B     (1)
We approximate this with
     Y = 0.211 * R    + 0.715 * G    + 0.074 * B        (2)
which can be expressed with integers as
     Y = (54 * R + 183 * G + 19 * B)/256                (3)
As recommended in the ColorFAQ, the mixing was done in a linear colorspace. The 8-bit-per-channel RGB colors were converted to the linear space by normalizing to 1.0, raising to the power 2.2, and 255. Then Y was computed to get the luminance. Grayscale pixels were determined by normalizing the Y value to 1.0, raising it to the power 1/2.2, and multiplying by 255. Conversion to and from the linear colorspace was actually done with a 16-bit lookup table, which produces the same result (after reducing to 8 bits) as performing equation (3) in 32-bit floating point arithmetic. In fact, 14-bit tables could have been used with the same result. In order to use the 16-bit tables, the 8-bit samples were multiplied by 256 and the low bytes filled with 0x80.


mix045.png:


mix045.png is the result of converting the image to grayscale, using the equation for luminance given in the ColorFAQ, the mixing done in the gamma=0.45455 colorspace (i.e. no gamma corrections were done before or after computing Y).

There is a little strip of colored or grayscale pixels in the top left corner of each image for easy determination of the resulting palette after the various conversions. You can use ImageMagick's

"convert -compress none mix100.png mix100.pgm"
and then use a text editor or text viewer to examine the first 216 pixels.

The original color image was produced with the following Fortran program, which produced a NetPBM PGM file that was subsequently converted to PNG with ImageMagick's "convert". Conversion to grayscale, and final compression of the color image, were done with a modified version of "pngcrush" and a test version of libpng-1.0.2a.

      program make_216_pgm
c     (c) Glenn Randers-Pehrson, July 1998
      implicit integer (a-z)
      write(*,'(a2)')'P3'
      write(*,*)'600 400 255'

      do n=0,1

c        top border
         if(n .eq. 0) then
            npix = 600 - 216
            do green = 0,255,51
              do blue = 0,255,51
                 do red = 0,255,51
                   write(*,'(3i4)') red, green, blue
                 enddo
              enddo
            enddo
         else
            npix = 600
         endif

         do k=1,8
            do i=1,npix
               write(*,*)' 128 128 128'
            enddo
            npix=600
         enddo

         do green = 0,255,51
            do k=1,24
               do blue = n*3*51, (3*n+2)*51, 51
                  do i = 1, 8
                     write(*,*) ' 128 128 128'
                  enddo
                  do red = 0,255,51
                     do i = 1, 24
                        write(*,'(3i4)') red, green, blue
                     enddo

                     do i = 1, 8
                        write(*,*) ' 128 128 128'
                     enddo
                  enddo
               enddo
            enddo

c           bottom border

            do i=1,4800
               write(*,*)' 128 128 128'
            enddo
         enddo
      enddo
      end