png.cpp

00001
00002 /***************************************************************************
00003  *  png.cpp - Implementation of a PNG writer
00004  *
00005  *  Generated: Thu Jun 02 15:23:56 2005
00006  *  Copyright  2005-2007  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023
00024 #include <core/exception.h>
00025 #include <fvutils/writers/png.h>
00026 #include <fvutils/color/yuvrgb.h>
00027
00028 #include <cstdio>
00029 #include <png.h>
00030 #include <string.h>
00031 #include <stdlib.h>
00032
00033 using namespace fawkes;
00034 
00035 /** @class PNGWriter <fvutils/writers/png.h>
00036  * PNG file writer.
00037  */
00038 
00039 /** Constructor. */
00040 PNGWriter::PNGWriter()
00041   : Writer("png")
00042 {
00043 }
00044 
00045 /** Constructor.
00046  * @param filename filename
00047  * @param width width
00048  * @param height height
00049  */
00050 PNGWriter::PNGWriter(const char *filename, unsigned int width, unsigned int height)
00051   : Writer("png")
00052 {
00053   set_filename(filename);
00054
00055   this->width    = width;
00056   this->height   = height;
00057 }
00058 
00059 /** Destructor. */
00060 PNGWriter::~PNGWriter()
00061 {
00062 }
00063
00064 void
00065 PNGWriter::set_buffer(colorspace_t cspace, unsigned char *buffer)
00066 {
00067   if( cspace == BGR )
00068     {
00069       __isBGR = true;
00070       this->buffer = buffer;
00071     }
00072   else if (cspace == YUV422_PLANAR) {
00073     this->buffer = buffer;
00074     __isBGR  = false;
00075   } else {
00076     __isBGR = false;
00077     throw Exception("Color space not supported, can only write YUV422_PLANAR images");
00078   }
00079 }
00080
00081
00082 void
00083 PNGWriter::write()
00084 {
00085   if ( (filename == 0) ||
00086        (width == 0) ||
00087        (height == 0) ) {
00088     throw Exception("PNGWriter::write(): Illegal data, width==0 || height == 0 || filename=\"\".");
00089   }
00090
00091   FILE *fp = fopen(filename, "wb");
00092   if (!fp) {
00093     throw Exception("Could not open file for writing");
00094   }
00095
00096   png_structp png_ptr = png_create_write_struct
00097     (PNG_LIBPNG_VER_STRING,png_voidp_NULL,
00098      png_error_ptr_NULL, png_error_ptr_NULL);
00099   if (!png_ptr) {
00100     throw Exception("Could not create PNG write struct");
00101   }
00102
00103   png_infop info_ptr = png_create_info_struct(png_ptr);
00104   if (!info_ptr) {
00105     png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
00106     throw Exception("Could not create PNG info struct");
00107   }
00108
00109   if (setjmp(png_jmpbuf(png_ptr))) {
00110     png_destroy_write_struct(&png_ptr, &info_ptr);
00111     fclose(fp);
00112     png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
00113     throw Exception("Could not create setjmp");
00114   }
00115
00116   // Use default io via fwrite
00117   png_init_io(png_ptr, fp);
00118
00119   // Can be used to get informed about progress
00120   // png_set_write_status_fn(png_ptr, write_row_callback);
00121
00122     png_set_IHDR(png_ptr, info_ptr, width, height,
00123                  8 /* bit per channel */,  PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
00124                PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
00125
00126   png_write_info(png_ptr, info_ptr);
00127
00128   // png_byte == unsigned char, create one row, three bytes 
00129   //  png_byte row[width * 3];
00130   png_byte row[width*3];
00131   png_byte *row_p;
00132   unsigned char *yp, *up, *vp;
00133   unsigned char y1, y2, u = 0, v = 0;
00134
00135
00136   yp = buffer;
00137   up = YUV422_PLANAR_U_PLANE(buffer, width, height);
00138   vp = YUV422_PLANAR_V_PLANE(buffer, width, height);
00139
00140   for (unsigned int i = 0; i < height; ++i) {
00141     if( !__isBGR ) {
00142       // pack row
00143       row_p = row;
00144       for (unsigned int j = 0; j < (width / 2); ++j) {
00145         y1 = *yp++;
00146         y2 = *yp++;
00147         u  = *up++;
00148         v  = *vp++;
00149         pixel_yuv_to_rgb(y1, u, v, &row_p[0], &row_p[1], &row_p[2]);
00150         row_p += 3;
00151         pixel_yuv_to_rgb(y2, u, v, &row_p[0], &row_p[1], &row_p[2]);
00152         row_p += 3;
00153       }
00154
00155       if ( (width % 2) == 1 ) {
00156         // odd number of columns, we have to take care of this
00157         // use last u,v values and new y value for this
00158         y1 = *yp++;
00159         pixel_yuv_to_rgb(y1, u, v, &row_p[0], &row_p[1], &row_p[2]);
00160       }
00161     } else  {
00162       convert_line_bgr_rgb( (buffer + width*3*i), row,
00163                             width,  height );
00164
00165     }
00166     png_write_row(png_ptr, row);
00167   }
00168
00169   png_write_end(png_ptr, info_ptr);
00170   png_destroy_write_struct(&png_ptr, &info_ptr);
00171   fclose(fp);
00172
00173 }