view src/pngwrite.cc @ 249:4023b90892ff

FSF address update
author adb014
date Fri, 23 Mar 2007 20:59:58 +0000
parents 8fe38c1c25c5
children 3da7ef6dd4ee
line wrap: on
line source

/*
 *  pngwrite.cc
 *
 *  Copyright (C) 2003 Nadav Rotem <nadav256@hotmail.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/*

Write PNG files to disk from octave

       PNG  (Portable  Network  Graphics) is an extensible file format for the
       lossless, portable, well-compressed storage of raster images. PNG  pro-
       vides  a patent-free replacement for GIF and can also replace many com-
       mon uses of TIFF. Indexed-color, grayscale, and  truecolor  images  are
       supported,  plus  an optional alpha channel. Sample depths range from 1
       to 16 bits.

*/

/*
 * Modified: Stefan van der Walt <stefan@sun.ac.za>
 * Date: 28 January 2005
 * - Fix bugs, restructure
 */

#include "png.h"
#include "pngcanvas.h"
#include <octave/oct.h>

void save_canvas(canvas *can, char *filename);

DEFUN_DLD (pngwrite, args, ,"\
-*- texinfo -*-\n\
@deftypefn {Function File} pngwrite(@var{filename}, @var{R}, @var{G}, @var{B}, @var{A})\n\
Writes a png file to the disk using the Red, Green, Blue and Alpha matrices.\n\
\n\
Data must be [0 255] or the high bytes will be lost.\n\
@seealso{imwrite}\n\
@end deftypefn\n\
") {
   octave_value_list retval;
   int nargin  = args.length();
   
   //
   // We bail out if the input parameters are bad
   //
   if (nargin < 5 || !args(0).is_string() ) {
     print_usage ();
     return retval;
   }

   Matrix red  = args(1).matrix_value();
   Matrix green= args(2).matrix_value();
   Matrix blue = args(3).matrix_value();
   Matrix alpha= args(4).matrix_value();
   
   long image_width  = args(1).columns();
   long image_height = args(1).rows();
   
   if ( args(2).columns() != image_width  ||
	args(3).columns() != image_width  ||
	args(4).columns() != image_width  ||
	args(2).rows()    != image_height ||
	args(3).rows()    != image_height ||
	args(4).rows()    != image_height )  
     {
       error("pngwrite R,G,B,A matrix sizes aren't the same");
       return retval;
     }
   
   canvas *pic=new_canvas(image_width, image_height, image_width*4);
   if (!pic) {
       error("pngwrite out of memory");
       return retval;
   }

   for(int i=0; i < pic->width; i++) {
       for(int j=0; j < pic->height; j++) {
	   pic->row_pointers[j][i*4+0]=(unsigned char)(red(j,i));
	   pic->row_pointers[j][i*4+1]=(unsigned char)(green(j,i));
	   pic->row_pointers[j][i*4+2]=(unsigned char)(blue(j,i));
	   pic->row_pointers[j][i*4+3]=(unsigned char)(alpha(j,i));
       }
   }
   

   save_canvas(pic,(char *)args(0).string_value().c_str());
   delete_canvas(pic);

   return retval;
}

void save_canvas(canvas *can,char *filename)
{
  FILE            *fp;
  png_structp     png_ptr;
  png_infop       info_ptr;
  
  fp = fopen(filename, "wb");
  if (fp == NULL) {
    error("pngwrite could not open %s", filename);
    return;
  }

  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if (!png_ptr) {
      fclose(fp);
      error("pngwrite: cannot create write structure");
      return;
  }

  info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr) {
      fclose(fp);
      error("pngwrite: cannot not create image structure");
      png_destroy_write_struct(&png_ptr, png_infopp_NULL);
      return;
  }

  if (setjmp(png_jmpbuf(png_ptr))) {
      fclose(fp);
      png_destroy_write_struct(&png_ptr, &info_ptr);
      error("pngread: libpng exited abnormally");
      return;
  }

  png_init_io(png_ptr, fp);
  png_set_compression_level(png_ptr, 3);
  
  png_set_IHDR(png_ptr, info_ptr, can->width, can->height,         
	       can->bit_depth, can->color_type, PNG_INTERLACE_NONE,
	       PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
  
  
  png_set_gAMA(png_ptr, info_ptr, 0.7);
  
  time_t          gmt;
  png_time        mod_time;
  png_text        text_ptr[2];
  time(&gmt);
  png_convert_from_time_t(&mod_time, gmt);
  png_set_tIME(png_ptr, info_ptr, &mod_time);
  text_ptr[0].key = "Created by";
  text_ptr[0].text = "Octave";
  text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
  
  png_set_text(png_ptr, info_ptr, text_ptr, 1);
  
  png_write_info(png_ptr, info_ptr);
  png_write_image(png_ptr, can->row_pointers);
  png_write_end(png_ptr, info_ptr);                      
  png_destroy_write_struct(&png_ptr, &info_ptr);          
  fclose(fp); 
}

/*

%!test
%! if exist("jpgwrite","file")
%!   ## build test image for r/w tests
%!   x=linspace(-8,8,200);
%!   [xx,yy]=meshgrid(x,x);
%!   r=sqrt(xx.^2+yy.^2) + eps;
%!   map=colormap(hsv);
%!   A=sin(r)./r;
%!   minval = min(A(:));
%!   maxval = max(A(:));
%!   z = round ((A-minval)/(maxval - minval) * (rows(colormap) - 1)) + 1;
%!   Rw=Gw=Bw=z;
%!   Rw(:)=fix(255*map(z,1));
%!   Gw(:)=fix(255*map(z,2));
%!   Bw(:)=fix(255*map(z,3));
%!   Aw=fix(255*(1-r/max(r(:)))); ## Fade to nothing at the corners
%!   pngwrite('test.png',Rw,Gw,Bw,Aw);
%!   stats=stat("test.png");
%!   assert(stats.size,24738);
%!   im = pngread('test.png');
%!   Rr = im(:,:,1); Gr = im(:,:,2); Br = im(:,:,3);
%!   assert(all(double(Rr(:))==Rw(:)));
%!   assert(all(double(Gr(:))==Gw(:)));
%!   assert(all(double(Br(:))==Bw(:)));
%!   [im,Ar] = pngread('test.png');
%!   Rr = im(:,:,1); Gr = im(:,:,2); Br = im(:,:,3);
%!   assert(all(double(Rr(:))==Rw(:)));
%!   assert(all(double(Gr(:))==Gw(:)));
%!   assert(all(double(Br(:))==Bw(:)));
%!   assert(all(double(Ar(:))==Aw(:)));
%!   unlink('test.png');
%! endif

*/