00001 #pragma ident "$Id: PNG.cpp 2091 2009-08-21 14:24:47Z afarris $"
00002
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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
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
00072 << *plte(c)
00073 << *idat(c,osr,osc)
00074 << *iend();
00075 return string_ptr(new std::string(s.str()));
00076 }
00077
00078
00079
00080
00081
00082
00083
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;
00099 i += 13 + 12;
00100 i += 1 + 12;
00101 i += numcol*3 + 12;
00102 i += cost_idat(rows*(cols+1));
00103 i += 12;
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;
00125 i += 13 + 12;
00126 i += 1 + 12;
00127 i += cost_idat(rows*(3*cols+1));
00128 i += 12;
00129 return i;
00130 }
00131
00132 int PNG::cost_idat(int stream)
00133 {
00134 int i = stream;
00135
00136 i += 5*(stream>>16 + (stream&0xFFFF?1:0));
00137 i += 4;
00138 i += 2;
00139 i += 12*(stream/0x2000 + (stream%0x2000?1:0));
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)
00147 << *itos(height)
00148 << btoc(8)
00149 << btoc(2)
00150 << btoc(0)
00151 << btoc(0)
00152 << btoc(0);
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)
00160 << *itos(height)
00161 << btoc(8)
00162 << btoc(3)
00163 << btoc(0)
00164 << btoc(0)
00165 << btoc(0);
00166 return chunk("IHDR",s.str());
00167 }
00168
00169
00170 PNG::string_ptr PNG::srgb()
00171 {
00172 std::stringstream s;
00173 s << btoc(0);
00174 return chunk("sRGB",s.str());
00175 }
00176
00177 PNG::string_ptr PNG::phys()
00178 {
00179 std::stringstream s;
00180 s << *itos(1)
00181 << *itos(1)
00182 << btoc(1);
00183 return chunk("pHYs",s.str());
00184 }
00185
00186 PNG::string_ptr PNG::plte(const InterpolatedColorMap &c)
00187 {
00188
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
00198
00199
00200
00201
00202
00203
00204
00205
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
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
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
00266 s << btoc(cmp)
00267 << btoc(flg)
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
00275 std::stringstream s;
00276 int len = str.size();
00277 int pos = 0;
00278 do
00279 {
00280
00281 int dist=0;
00282 if(len>0x0FFFF)
00283 dist = 0x0FFFF;
00284 else
00285 dist = len;
00286 len -= dist;
00287
00288
00289 s << btoc((len?0x00:0x01))
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
00304
00305 std::stringstream s;
00306 for(int row=0; row<c.getRows(); row++)
00307 {
00308 std::stringstream r;
00309 r << btoc(0x00);
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
00326
00327 std::stringstream s;
00328 for(int row=0; row<c.getRows(); row++)
00329 {
00330 std::stringstream r;
00331 r << btoc(0x00);
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 }
00398
00399