PNG.cpp

Go to the documentation of this file.
00001 #pragma ident "$Id: PNG.cpp 2091 2009-08-21 14:24:47Z afarris $"
00002 
00004 
00005 //============================================================================
00006 //
00007 //  This file is part of GPSTk, the GPS Toolkit.
00008 //
00009 //  The GPSTk is free software; you can redistribute it and/or modify
00010 //  it under the terms of the GNU Lesser General Public License as published
00011 //  by the Free Software Foundation; either version 2.1 of the License, or
00012 //  any later version.
00013 //
00014 //  The GPSTk is distributed in the hope that it will be useful,
00015 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 //  GNU Lesser General Public License for more details.
00018 //
00019 //  You should have received a copy of the GNU Lesser General Public
00020 //  License along with GPSTk; if not, write to the Free Software Foundation,
00021 //  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 //  
00023 //  Copyright 2004, The University of Texas at Austin
00024 //
00025 //============================================================================
00026 
00027 #include "PNG.hpp"
00028 #include <cstdio>
00029 
00030 namespace vdraw
00031 {
00032   const std::string PNG::header = "\211PNG\r\n\032\n";
00033 
00034   std::string PNG::png(const Bitmap &b)
00035   {
00036     InterpolatedColorMap icm;
00037     ColorMap cm;
00038     if(b.getICM(&icm))
00039     {
00040       return *png(icm,b.osr,b.osc);
00041     }
00042     else if(b.getCM(&cm))
00043     {
00044       return *png(cm,b.osr,b.osc); 
00045     }
00046     else
00047     { 
00048       printf("PNG::png(const Bitmap &b); Invalid Bitmap.\n");
00049       exit(1);
00050     }
00051   }
00052 
00053   PNG::string_ptr PNG::png(const ColorMap &c, int osr, int osc)
00054   {
00055     std::stringstream s;
00056     s << header 
00057       << *ihdr_full(c.getCols()*osc,c.getRows()*osr)
00058       << *srgb() 
00059       //<< phys()
00060       << *idat(c,osr,osc)
00061       << *iend();
00062     return string_ptr(new std::string(s.str()));
00063   }
00064 
00065   PNG::string_ptr PNG::png(const InterpolatedColorMap &c, int osr, int osc)
00066   {
00067     std::stringstream s;
00068     s << header 
00069       << *ihdr_indexed(c.getCols()*osc,c.getRows()*osr)
00070       << *srgb() 
00071       //<< phys()
00072       << *plte(c)
00073       << *idat(c,osr,osc)
00074       << *iend();
00075     return string_ptr(new std::string(s.str()));
00076   }
00077 
00078   /*
00079    * TODO Future ideas for optimization
00080    * -- Indexed Color Map 
00081    *    When it is optimal to use the non-indexed version, by these simple
00082    *    calculations then it would be worthwhile to make an indexed color map
00083    *    which might end up with far fewer colors to index
00084    */
00085 
00086   int PNG::cost_indexed(const Bitmap& b)
00087   {
00088     InterpolatedColorMap icm;
00089     if(b.getICM(&icm))
00090     {
00091       return cost_indexed(icm.getRows()*b.osr,icm.getCols()*b.osc,256);
00092     }
00093     return -1;
00094   }
00095   
00096   int PNG::cost_indexed(int rows, int cols, int numcol)
00097   {
00098     int i = 8;          // PNG
00099     i += 13 + 12;       // IHDR Len + 12 Chunk bytes
00100     i += 1  + 12;       // sRGB Len + 12 Chunk bytes
00101     i += numcol*3 + 12; // PLTE Len + 12 Chunk bytes
00102     i += cost_idat(rows*(cols+1));   // IDAT
00103     i += 12;            // IEND
00104     return i;
00105   }
00106 
00107   int PNG::cost_constant(const Bitmap& b)
00108   {
00109     InterpolatedColorMap icm;
00110     ColorMap cm;
00111     if(b.getICM(&icm))
00112     {
00113       return cost_constant(icm.getRows()*b.osr,icm.getCols()*b.osc);
00114     }
00115     else if(b.getCM(&cm))
00116     {
00117       return cost_constant(cm.getRows()*b.osr,cm.getCols()*b.osc);
00118     }
00119     return -1;
00120   }
00121 
00122   int PNG::cost_constant(int rows, int cols)
00123   {
00124     int i = 8;    // PNG
00125     i += 13 + 12; // IHDR Len + 12 Chunk bytes
00126     i += 1  + 12; // sRGB Len + 12 Chunk bytes
00127     i += cost_idat(rows*(3*cols+1)); // IDAT
00128     i += 12;      // IEND
00129     return i;
00130   }
00131 
00132   int PNG::cost_idat(int stream)
00133   {
00134     int i = stream;
00135     // Huffman bits, 5 per 0xFFFF and 5 for whats left
00136     i += 5*(stream>>16 + (stream&0xFFFF?1:0));
00137     i += 4; // Adler-32 checksum
00138     i += 2; // zlib bytes
00139     i += 12*(stream/0x2000 + (stream%0x2000?1:0)); //Chunk bits (if split)
00140     return i;
00141   }
00142 
00143   PNG::string_ptr PNG::ihdr_full(int width, int height)
00144   {
00145     std::stringstream s;
00146     s << *itos(width)  // width              -- 4 bytes
00147       << *itos(height) // height             -- 4 bytes
00148       << btoc(8)      // bit depth          -- 1 byte
00149       << btoc(2)      // color type         -- 1 byte -- Truecolor
00150       << btoc(0)      // compression method -- 1 byte
00151       << btoc(0)      // filter method      -- 1 byte
00152       << btoc(0);     // interlace method   -- 1 byte
00153     return chunk("IHDR",s.str());
00154   }
00155 
00156   PNG::string_ptr PNG::ihdr_indexed(int width, int height)
00157   {
00158     std::stringstream s;
00159     s << *itos(width)  // width              -- 4 bytes
00160       << *itos(height) // height             -- 4 bytes
00161       << btoc(8)      // bit depth          -- 1 byte
00162       << btoc(3)      // color type         -- 1 byte -- Interpolated
00163       << btoc(0)      // compression method -- 1 byte
00164       << btoc(0)      // filter method      -- 1 byte
00165       << btoc(0);     // interlace method   -- 1 byte
00166     return chunk("IHDR",s.str());
00167   }
00168 
00169 
00170   PNG::string_ptr PNG::srgb()
00171   {
00172     std::stringstream s;
00173     s << btoc(0);     // We want the colors to look good
00174     return chunk("sRGB",s.str());
00175   }
00176 
00177   PNG::string_ptr PNG::phys()
00178   {
00179     std::stringstream s;
00180     s << *itos(1)  // Pixels per unit x axis
00181       << *itos(1)  // Pixels per unit y axis
00182       << btoc(1); // We know the unit
00183     return chunk("pHYs",s.str());
00184   }
00185 
00186   PNG::string_ptr PNG::plte(const InterpolatedColorMap &c)
00187   {
00188     // TODO Smaller palette on request?
00189     Palette p = c.getPalette();
00190     std::stringstream s;
00191     for(int i=0;i<256;i++)
00192       s << *ctos(p.getColor(i/256.0));
00193     return chunk("PLTE",s.str());
00194   }
00195 
00196   /*
00197    * ZLIB flag information
00198    * First two bytes:
00199    * +-----+-----+
00200    * | CMP | FLG |
00201    * +-----+-----+
00202    * CMP:
00203    *  - Bits 0-3 = 0x08 (deflate compression)
00204    *  - Bits 4-7 = For CM = 8, CINFO is the base-2 logarithm 
00205    *    of the LZ77 window size, minus eight
00206    *
00207    */
00208 
00209   PNG::string_ptr PNG::idat(const InterpolatedColorMap &c, int osr, int osc)
00210   {
00211     std::stringstream s;
00212     string_ptr tmp = data(c,osr,osc);
00213     unsigned int a = alder(tmp);
00214     s << *huff(*tmp)
00215       << *itos(a);
00216     tmp = string_ptr(new std::string(s.str()));
00217     return split(*prefix(*tmp));
00218   }
00219 
00220   PNG::string_ptr PNG::idat(const ColorMap &c, int osr, int osc)
00221   {
00222     std::stringstream s;
00223     string_ptr tmp = data(c,osr,osc);
00224     unsigned int a = alder(tmp);
00225     s << *huff(*tmp)
00226       << *itos(a);
00227     tmp = string_ptr(new std::string(s.str()));
00228     return split(*prefix(*tmp));
00229   }
00230 
00231   PNG::string_ptr PNG::split(const std::string &str)
00232   {
00233     std::stringstream s;
00234     int len = str.size();
00235     int pos = 0;
00236     do
00237     {
00238       //printf("split() :: len=%08x pos=%08x \n",len,pos);
00239       int dist=0;
00240       if(len>0x02000)
00241         dist = 0x02000;
00242       else
00243         dist = len;
00244       len -= dist;
00245 
00246       s << *chunk("IDAT",str.substr(pos,dist));
00247 
00248       pos += dist;
00249     } while(len);
00250     return string_ptr(new std::string(s.str()));            
00251   }
00252 
00253   PNG::string_ptr PNG::prefix(const std::string &str)
00254   {
00255     // TODO There are limits to IDAT length...check and split
00256     int len = str.size();
00257     int cmp = (int)(log((double)len)/log(2.0))-8;
00258     if(cmp<0) cmp = 0;
00259     else if(cmp>7) cmp = 7;
00260     cmp = (cmp<<4) | 0x08;
00261     int flg = 0;
00262     int tmp = (cmp*256+flg)%31;
00263     if(tmp!=0) flg += 31-tmp;
00264     std::stringstream s;
00265     // TODO ZLIB data stream...? Adler-32
00266     s << btoc(cmp)          // See CMP notes above
00267       << btoc(flg)          // Flag
00268       << str;
00269     return string_ptr(new std::string(s.str()));            
00270   }
00271 
00272   PNG::string_ptr PNG::huff(const std::string &str)
00273   {
00274     // Add huff information
00275     std::stringstream s;
00276     int len = str.size();
00277     int pos = 0;
00278     do
00279     {
00280       //printf("huff() :: len=%08x pos=%08x\n",len,pos);          
00281       int dist=0;
00282       if(len>0x0FFFF)
00283         dist = 0x0FFFF;
00284       else
00285         dist = len;
00286       len -= dist;
00287 
00288       // These go backwards
00289       s << btoc((len?0x00:0x01)) // Set final bit on last block
00290         << btoc(dist) 
00291         << btoc(dist>>8)
00292         << btoc(~dist)
00293         << btoc((~dist)>>8)
00294         << str.substr(pos,dist);
00295 
00296       pos += dist;
00297     } while(len);
00298     return string_ptr(new std::string(s.str()));            
00299   }
00300 
00301   PNG::string_ptr PNG::data(const ColorMap &c, int osr, int osc)
00302   {
00303     // For oversampling, we make a row buffer and a column one and repeat as
00304     // necessary to create the image.
00305     std::stringstream s;
00306     for(int row=0; row<c.getRows(); row++)
00307     {
00308       std::stringstream r;
00309       r << btoc(0x00);   // Filter method 0 (identity)
00310       for(int col=0; col<c.getCols(); col++)
00311       {
00312         string_ptr t = ctos(c.get(row,col));
00313         for(int cc=0; cc<osc; cc++) 
00314           r << *t;
00315       }
00316       std::string rstr = r.str();
00317       for(int rr=0; rr<osr; rr++) 
00318         s << rstr;
00319     }
00320     return string_ptr(new std::string(s.str()));            
00321   }
00322 
00323   PNG::string_ptr PNG::data(const InterpolatedColorMap &c, int osr, int osc)
00324   {
00325     // For oversampling, we make a row buffer and a column one and repeat as
00326     // necessary to create the image.
00327     std::stringstream s;
00328     for(int row=0; row<c.getRows(); row++)
00329     {
00330       std::stringstream r;
00331       r << btoc(0x00);   // Filter method 0 (no filter)
00332       for(int col=0; col<c.getCols(); col++)
00333       {
00334         char t = btoc((int)(c.getIndex(row,col)*255));
00335         for(int cc=0; cc<osc; cc++) 
00336           r << t;
00337       }
00338       std::string rstr = r.str();      
00339       for(int rr=0; rr<osr; rr++) 
00340         s << rstr;
00341     }
00342     return string_ptr(new std::string(s.str()));            
00343   }
00344 
00345 
00346   unsigned int PNG::alder(const PNG::string_ptr &str)
00347   {
00348     Adler32 a;
00349     a.update(str);
00350     return a.getValue();
00351   }
00352 
00353   PNG::string_ptr PNG::iend()
00354   {
00355     return chunk("IEND","");
00356   }
00357 
00358   PNG::string_ptr PNG::chunk(const std::string &title, const std::string &text)
00359   {
00360     CRC32 c;
00361     c.update(title);
00362     c.update(text);
00363     std::stringstream s;
00364     s << *itos(text.length())
00365       << title
00366       << text
00367       << *itos(c.getValue());
00368     return string_ptr(new std::string(s.str()));    
00369   }
00370 
00371   PNG::string_ptr PNG::itos(int i)
00372   {
00373     std::stringstream s;
00374     s << btoc((i>>24)&0x000000FF)
00375       << btoc((i>>16)&0x000000FF)
00376       << btoc((i>>8) &0x000000FF)
00377       << btoc(i      &0x000000FF);
00378     return string_ptr(new std::string(s.str()));        
00379   }
00380 
00381   PNG::string_ptr PNG::ctos(const Color &color)
00382   {
00383     unsigned int l = color.getRGB();
00384     std::stringstream s;
00385     s << btoc((l>>16)&0x000000FF)
00386       << btoc((l>>8) &0x000000FF)
00387       << btoc(l      &0x000000FF);
00388     return string_ptr(new std::string(s.str()));            
00389   }
00390 
00391 
00392   char PNG::btoc(int b)
00393   {
00394     return (char)(b&0x000000FF);
00395   }
00396 
00397 } // namespace vdraw
00398 
00399 

Generated on Thu Sep 9 03:30:55 2010 for GPS ToolKit Software Library by  doxygen 1.3.9.1