00001 #include "image.h"
00002
00008 #include <misc/endian.h>
00009 #include <glt/color.h>
00010
00011 #include <cassert>
00012 #include <cstring>
00013 #include <cstdio>
00014 #include <cmath>
00015
00016 #include <set>
00017 #include <map>
00018 #include <list>
00019 #include <iostream>
00020 using namespace std;
00021
00022 bool isGreyscale(const string &rgb)
00023 {
00024 assert(rgb.size()%3==0);
00025
00026 if (rgb.size()%3)
00027 return false;
00028
00029 for (size_t i=0; i<rgb.size(); i+=3)
00030 if (rgb[i]!=rgb[i+1] || rgb[i]!=rgb[i+2])
00031 return false;
00032
00033 return true;
00034 }
00035
00036 bool is256Colors(const string &rgb)
00037 {
00038 assert(rgb.size()%3==0);
00039
00040 if (rgb.size()%3)
00041 return false;
00042
00043 set<uint32> colors;
00044
00045 for (size_t i=0; i<rgb.size(); i+=3)
00046 {
00047 const uint32 col = (byte(rgb[i])<<16) | (byte(rgb[i+1])<<8) | byte(rgb[i+2]);
00048
00049 colors.insert(col);
00050
00051 if (colors.size()>256)
00052 return false;
00053 }
00054
00055 return true;
00056 }
00057
00058 void getChannel(string &dest,const string &rgb,const uint32 size,const uint32 channel)
00059 {
00060 assert(rgb.size()%size==0);
00061 assert(channel<size);
00062
00063 if (rgb.size()%size || channel>=size)
00064 return;
00065
00066 dest.resize(rgb.size()/size);
00067
00068 for (size_t i=channel,j=0; i<rgb.size(); i+=size,j++)
00069 dest[j] = rgb[i];
00070 }
00071
00072 void rgb2Indexed(string &dest,const string &rgb)
00073 {
00074 assert(rgb.size()%3==0);
00075
00076 if (rgb.size()%3)
00077 return;
00078
00079
00080
00081
00082 const int tableSize = 256*3;
00083 dest.resize(tableSize+rgb.size()/3);
00084
00085
00086
00087
00088 map<uint32,byte> colors;
00089
00090 for (size_t i=0,j=0; i<rgb.size();)
00091 {
00092 const uint32 col = (byte(rgb[i])<<16) | (byte(rgb[i+1])<<8) | byte(rgb[i+2]);
00093
00094
00095
00096 if (colors.find(col)==colors.end())
00097 {
00098
00099 colors.insert(make_pair(col,j/3));
00100
00101
00102 dest[j++] = rgb[i++];
00103 dest[j++] = rgb[i++];
00104 dest[j++] = rgb[i++];
00105
00106
00107 if (colors.size()==256)
00108 break;
00109 }
00110 else
00111 i += 3;
00112 }
00113
00114
00115
00116 {
00117 for (size_t i=0,j=tableSize; i<rgb.size(); i+=3,j++)
00118 {
00119 const uint32 col = (byte(rgb[i])<<16) | (byte(rgb[i+1])<<8) | byte(rgb[i+2]);
00120 assert(colors.find(col)!=colors.end());
00121 dest[j] = colors[col];
00122 }
00123 }
00124 }
00125
00126 void indexed2rgb(string &dest,const string &indexed)
00127 {
00128 const int tableSize = 256*3;
00129 const int pixels = indexed.size()-tableSize;
00130
00131 assert(pixels>=0);
00132 if (pixels<0)
00133 return;
00134
00135 dest.resize(pixels*3);
00136
00137 for (size_t i=tableSize,j=0; i<indexed.size(); i++,j+=3)
00138 {
00139 const size_t p = 3*(byte)(indexed[i]);
00140
00141 dest[j] = indexed[p];
00142 dest[j+1] = indexed[p+1];
00143 dest[j+2] = indexed[p+2];
00144 }
00145 }
00146
00147 void flipImage(string &dest,const string &src,const int width,const int height)
00148 {
00149 const int lineSize = src.size()/height;
00150
00151 assert(lineSize>0);
00152 assert(src.size()%lineSize==0);
00153
00154 if (lineSize==0 || src.size()%lineSize!=0)
00155 return;
00156
00157 dest.resize(src.size());
00158
00159 const char *i = src.c_str();
00160 const char *j = dest.c_str()+dest.size()-lineSize;
00161
00162 for (int k=0; k<height; i+=lineSize,j-=lineSize,k++)
00163 memcpy((void *)j,i,lineSize);
00164 }
00165
00166 void
00167 mirrorImage(std::string &dest,const std::string &src,const int width,const int height)
00168 {
00169 const int lineSize = static_cast<int>(src.size())/height;
00170 const int channels = lineSize/width;
00171
00172 assert(channels>0);
00173 assert(src.size()%lineSize==0);
00174 assert(src.size()==width*height*channels);
00175
00176 if (channels==0 || src.size()%lineSize!=0 || src.size()!=width*height*channels)
00177 return;
00178
00179 dest.resize(src.size());
00180
00181 const char *i = src.c_str();
00182 const char *j = dest.c_str()+lineSize-channels;
00183
00184 for (int k=0; k<height; j+=lineSize*2,k++)
00185 for (int l=0; l<width; i+=channels,j-=channels,l++)
00186 memcpy((void *)j,i,channels);
00187 }
00188
00189 void adjustGamma(std::string &image,const double gamma)
00190 {
00191 byte table[256];
00192 for (int i=0; i<256; i++)
00193 table[i] = (byte) floor( pow(double(i)/255.0, 1.0/gamma)*255.0 + 0.5);
00194
00195 byte *j = (byte *) image.c_str();
00196 const byte *end = (const byte *) image.c_str() + image.size();
00197
00198 for (;j<end;j++)
00199 *j = table[*j];
00200 }
00201
00202 void
00203 adjustHSV
00204 (
00205 std::string &image,
00206 const int width,
00207 const int height,
00208 const real hue,
00209 const real saturation,
00210 const real value
00211 )
00212 {
00213 const int channels = image.size()/(width*height);
00214 assert(channels*width*height==image.size());
00215
00216 byte *i = (byte *) image.data();
00217 const byte *end = (const byte *) image.data() + image.size();
00218
00219 for (;i<end;i+=channels)
00220 {
00221 GltColor col(*i/255.0,*(i+1)/255.0,*(i+2)/255.0);
00222
00223 real h,s,v;
00224 col.toHSV(h,s,v);
00225
00226 h = fmod(h+hue+360.0,360.0);
00227 s = CLAMP(s+saturation,0.0,1.0);
00228 v = CLAMP(v+value,0.0,1.0);
00229
00230 col.fromHSV(h,s,v);
00231
00232 *i = (byte) floor(col.red() *255.0+0.5);
00233 *(i+1) = (byte) floor(col.green()*255.0+0.5);
00234 *(i+2) = (byte) floor(col.blue() *255.0+0.5);
00235 }
00236 }
00237
00238 bool stitchImages(string &image,const int dx,const int dy,const vector<string> &src,const int lineSize)
00239 {
00240 const int n=src.size();
00241
00242 if (dx<1 || dy<1 || dx*dy!=n)
00243 return false;
00244
00245 const int tileSize = src[0].size();
00246
00247
00248 image.resize(n*tileSize);
00249
00250
00251
00252 for (int y=0; y<dy; y++)
00253 for (int x=0; x<dx; x++)
00254 {
00255 const int k = x+y*dx;
00256
00257 byte *i = (byte *) image.data()+x*lineSize+y*dx*tileSize;
00258 const byte *iMax = (const byte *) image.data()+image.size();
00259 const byte *j = (const byte *) src[k].data();
00260 const byte *jMax = (const byte *) src[k].data() + src[k].size();
00261
00262 while (i<iMax && j<jMax)
00263 {
00264 memcpy(i,j,lineSize);
00265 i += lineSize*dx;
00266 j += lineSize;
00267 }
00268 }
00269
00270 return true;
00271 }
00272
00273
00274
00275
00276
00277 bool decode(uint32 &width,uint32 &height,std::string &image,const std::string &data)
00278 {
00279 string type;
00280
00281
00282
00283 if (decodePPM(type,width,height,image,data))
00284 return true;
00285
00286
00287
00288 if (decodeBMP(width,height,image,data))
00289 return true;
00290
00291
00292
00293 #ifdef GLT_PNG
00294 if (decodePNG(width,height,image,data))
00295 return true;
00296 #endif
00297
00298
00299
00300 return decodeTGA(width,height,image,data);
00301 }
00302
00303 bool decodePPM(string &type,uint32 &width,uint32 &height,string &image,const string &data)
00304 {
00305 if (data.size()<1 || data[0]!='P')
00306 return false;
00307
00308
00309
00310 size_t channels = 0;
00311
00312 if (data[1]=='6')
00313 {
00314 channels = 3;
00315 type = "P6";
00316 }
00317 else
00318 if (data[1]=='5')
00319 {
00320 channels = 1;
00321 type = "P5";
00322 }
00323 else
00324 return false;
00325
00326
00327
00328 const string eol("\n");
00329 const string digits("0123456789");
00330
00331 size_t i = 0;
00332
00333 int depth = 0;
00334
00335 for (;;)
00336 {
00337
00338
00339 i = data.find_first_of(eol,i);
00340 if (i==string::npos)
00341 break;
00342 else
00343 i++;
00344
00345
00346
00347 if (data[i]=='#')
00348 continue;
00349
00350
00351
00352 width = atoi(data.c_str()+i);
00353 i = data.find_first_not_of(digits,i); if (i==string::npos) break;
00354 i = data.find_first_of(digits,i); if (i==string::npos) break;
00355
00356
00357
00358 height = atoi(data.c_str()+i);
00359 i = data.find_first_not_of(digits,i); if (i==string::npos) break;
00360 i = data.find_first_of(digits,i); if (i==string::npos) break;
00361
00362
00363
00364 depth = atoi(data.c_str()+i);
00365 i = data.find(eol,i);
00366 if (i!=string::npos)
00367 i++;
00368
00369 break;
00370 }
00371
00372
00373
00374 const uint32 imageSize = width*height*channels;
00375 const uint32 rowSize = width*channels;
00376
00377 if (width!=0 && height!=0 && depth==255 && imageSize==data.size()-i)
00378 {
00379
00380 flipImage(image,data.substr(i),width,height);
00381 }
00382
00383 return true;
00384 }
00385
00386 bool decodeBMP(uint32 &width,uint32 &height,string &image,const string &data)
00387 {
00388
00389
00390
00391
00392
00393
00394
00395 const uint32 fileHeaderSize = 14;
00396 if (data.size()<fileHeaderSize)
00397 return false;
00398
00399
00400
00401 if (data[0]!='B' || data[1]!='M')
00402 return false;
00403
00404
00405
00406 const uint32 fileSize = littleEndian((uint32 *)(data.data()+2));
00407 if (data.size()!=fileSize)
00408 return false;
00409
00410
00411
00412 const uint32 imageHeaderSize = littleEndian((uint32 *)(data.data()+fileHeaderSize));
00413 if (fileHeaderSize+imageHeaderSize>data.size())
00414 return false;
00415
00416
00417
00418 const uint32 imageWidth = littleEndian((uint32 *)(data.data()+fileHeaderSize+4 ));
00419 const uint32 imageHeight = littleEndian((uint32 *)(data.data()+fileHeaderSize+8 ));
00420 const uint16 imageBits = littleEndian((uint16 *)(data.data()+fileHeaderSize+14));
00421 const uint32 imageCompress = littleEndian((uint32 *)(data.data()+fileHeaderSize+16));
00422
00423
00424
00425
00426
00427 if (imageBits!=24)
00428 return false;
00429
00430
00431
00432
00433
00434
00435 if (imageCompress!=0)
00436 return false;
00437
00438 const uint32 imagePos = littleEndian((uint32 *)(data.data()+10));
00439 const uint32 imagePixels = imageWidth*imageHeight;
00440 const uint32 lineBytes = (imageWidth*3+3)&~3;
00441 const uint32 imageBytes = lineBytes*imageHeight;
00442
00443 if (imagePos+imageBytes!=data.size())
00444 return false;
00445
00446
00447
00448 width = imageWidth;
00449 height = imageHeight;
00450 image.resize(imagePixels*3);
00451
00452
00453
00454 byte *i = (byte *) image.data();
00455
00456 for (uint32 y=0; y<imageHeight; y++)
00457 {
00458
00459
00460 const byte *j = (const byte *) data.data()+imagePos+lineBytes*y;
00461
00462
00463
00464
00465 for (uint32 x=0; x<imageWidth; x++)
00466 {
00467 *(i++) = *(j++ + 2);
00468 *(i++) = *(j++);
00469 *(i++) = *(j++ - 2);
00470 }
00471 }
00472
00473 return true;
00474 }
00475
00476 bool
00477 decodeTGA(uint32 &width,uint32 &height,string &image,const string &data)
00478 {
00479
00480
00481 const uint32 tgaHeaderSize = 18;
00482 if (data.size()<tgaHeaderSize)
00483 {
00484 cerr << "TGA Header seems to be invalid." << endl;
00485 return false;
00486 }
00487
00488
00489
00490 const uint32 tgaType = data[2];
00491
00492 if (tgaType!=1 && tgaType!=2 && tgaType!=10)
00493 {
00494 cerr << "Found TGA type: " << tgaType << endl;
00495 return false;
00496 }
00497
00498
00499
00500 if (tgaType==1 && data[1]!=1)
00501 {
00502 cerr << "Expecting color map in type 1 TGA." << endl;
00503 return false;
00504 }
00505
00506
00507
00508 uint32 bytesPerPixel=0;
00509
00510 if (tgaType==1)
00511 bytesPerPixel = data[7]==24 ? 3 : 4;
00512 else
00513 bytesPerPixel = data[16]==24 ? 3 : 4;
00514
00515 if (bytesPerPixel!=3 && bytesPerPixel!=4)
00516 {
00517 cerr << "Found TGA pixel depth: " << bytesPerPixel << endl;
00518 return false;
00519 }
00520
00521
00522
00523 const byte idSize = data[0];
00524
00525 const uint16 origin = littleEndian((uint16 *)(data.data()+3));
00526 const uint16 length = littleEndian((uint16 *)(data.data()+5));
00527 const byte size = data[7]>>3;
00528 const uint32 mapSize = length*size;
00529 const byte *mapData = (const byte *) data.data()+tgaHeaderSize+idSize;
00530
00531
00532
00533 width = littleEndian((uint16 *)(data.data()+12));
00534 height = littleEndian((uint16 *)(data.data()+14));
00535
00536
00537
00538
00539
00540 switch (tgaType)
00541 {
00542 case 1:
00543 {
00544
00545 }
00546 break;
00547
00548 case 2:
00549 {
00550 if (data.size()<tgaHeaderSize+idSize+width*height*bytesPerPixel)
00551 return false;
00552 }
00553 break;
00554
00555 case 10:
00556 {
00557
00558 }
00559 break;
00560 }
00561
00562
00563 image.resize(width*height*bytesPerPixel);
00564
00565
00566
00567 byte *i = (byte *) image.data();
00568 const byte *j = (const byte *) data.data()+tgaHeaderSize+idSize+mapSize;
00569
00570 switch (tgaType)
00571 {
00572
00573
00574
00575 case 1:
00576 {
00577 const uint32 pixels = width*height;
00578
00579 for (uint32 p=0; p<pixels; p++)
00580 {
00581 const byte *entry = mapData+(*(j++))*bytesPerPixel;
00582
00583 *(i++) = entry[2];
00584 *(i++) = entry[1];
00585 *(i++) = entry[0];
00586
00587 if (bytesPerPixel==4)
00588 *(i++) = entry[3];
00589 }
00590 }
00591 break;
00592
00593
00594
00595 case 2:
00596 {
00597 for (uint32 y=0; y<height; y++)
00598 {
00599
00600
00601
00602 for (int x=0; x<width; x++)
00603 {
00604 *(i++) = *(j++ + 2);
00605 *(i++) = *(j++);
00606 *(i++) = *(j++ - 2);
00607
00608 if (bytesPerPixel==4)
00609 *(i++) = *(j++);
00610 }
00611 }
00612 }
00613 break;
00614
00615
00616
00617 case 10:
00618 {
00619 const byte *iMax = (const byte *) image.data()+image.size();
00620 const byte *jMax = (const byte *) data.data()+data.size();
00621
00622 while (i<iMax && j<jMax)
00623 {
00624 const bool rle = ((*j)&128)==128;
00625 const int count = ((*j)&127) + 1;
00626
00627 j++;
00628
00629
00630 if (i+count*bytesPerPixel>iMax)
00631 return false;
00632
00633 if (rle)
00634 {
00635
00636 if (j+bytesPerPixel>jMax)
00637 return false;
00638
00639 byte *pixel = i;
00640
00641
00642
00643 *(i++) = *(j++ + 2);
00644 *(i++) = *(j++);
00645 *(i++) = *(j++ - 2);
00646
00647 if (bytesPerPixel==4)
00648 *(i++) = *(j++);
00649
00650
00651
00652 for (int k=0; k<count-1; k++,i+=bytesPerPixel)
00653 memcpy(i,pixel,bytesPerPixel);
00654 }
00655 else
00656 {
00657
00658 if (j+count*bytesPerPixel>jMax)
00659 return false;
00660
00661
00662
00663
00664 for (int k=0; k<count; k++)
00665 {
00666 *(i++) = *(j++ + 2);
00667 *(i++) = *(j++);
00668 *(i++) = *(j++ - 2);
00669
00670 if (bytesPerPixel==4)
00671 *(i++) = *(j++);
00672 }
00673
00674 }
00675 }
00676
00677 if (i!=iMax)
00678 return false;
00679 }
00680 break;
00681 }
00682
00683
00684
00685
00686 if ((data[17]&32)==32)
00687 {
00688
00689 string tmp = image;
00690 flipImage(image,tmp,width,height);
00691 }
00692
00693 return true;
00694 }
00695
00696
00697
00698 #ifdef GLT_PNG
00699
00700 #include <png.h>
00701
00702 class GltPngReader
00703 {
00704 public:
00705
00706 GltPngReader(const std::string &data,png_structp png_ptr)
00707 : pos(data.c_str()), end(data.c_str()+data.size())
00708 {
00709 png_set_read_fn(png_ptr,this,(png_rw_ptr) &GltPngReader::read);
00710 }
00711
00712 size_t remaining() const { return end-pos; }
00713
00714 private:
00715
00716 static void read(png_structp png_ptr, png_bytep data, png_uint_32 length)
00717 {
00718 GltPngReader *reader = (GltPngReader *) png_get_io_ptr(png_ptr);
00719
00720 assert(reader);
00721 if (!reader)
00722 return;
00723
00724 const char *&pos = reader->pos;
00725 const char *&end = reader->end;
00726
00727 assert(pos);
00728 assert(end);
00729
00730 if (pos && end)
00731 {
00732 if (pos+length<=end)
00733 {
00734 memcpy(data,pos,length);
00735 pos += length;
00736 }
00737 else
00738 {
00739 memcpy(data,pos,end-pos);
00740 pos = end = NULL;
00741 }
00742 }
00743 }
00744
00745 const char *pos;
00746 const char *end;
00747 };
00748
00749 class GltPngWriter
00750 {
00751 public:
00752
00753 GltPngWriter(std::string &data,png_structp png_ptr)
00754 : _png(png_ptr), _data(data), _size(0)
00755 {
00756 png_set_write_fn(_png,this,(png_rw_ptr) &GltPngWriter::write,(png_flush_ptr) &GltPngWriter::flush);
00757 }
00758
00759 ~GltPngWriter()
00760 {
00761 GltPngWriter::flush(_png);
00762 png_set_write_fn(_png,NULL,NULL,NULL);
00763 }
00764
00765 private:
00766
00767 static void write(png_structp png_ptr, png_bytep data, png_uint_32 length)
00768 {
00769 GltPngWriter *writer = (GltPngWriter *) png_get_io_ptr(png_ptr);
00770
00771 assert(writer);
00772 if (!writer)
00773 return;
00774
00775 list<string> &blocks = writer->_blocks;
00776 size_t &size = writer->_size;
00777
00778 if (length>0)
00779 {
00780 blocks.push_back(string());
00781 string &block = blocks.back();
00782 block.resize(length);
00783 memcpy((void *) block.data(),data,length);
00784 size += length;
00785 }
00786 }
00787
00788 static void flush(png_structp png_ptr)
00789 {
00790 GltPngWriter *writer = (GltPngWriter *) png_get_io_ptr(png_ptr);
00791
00792 assert(writer);
00793 if (!writer)
00794 return;
00795
00796 string &data = writer->_data;
00797 list<string> &blocks = writer->_blocks;
00798 size_t &size = writer->_size;
00799
00800 if (size>0)
00801 {
00802 size_t begin = data.size();
00803 data.resize(begin+size);
00804 for (list<string>::iterator i=blocks.begin(); i!=blocks.end(); i++)
00805 {
00806 memcpy((void *)(data.data()+begin),(void *) i->data(),i->size());
00807 begin += i->size();
00808 }
00809 blocks.clear();
00810 size = 0;
00811 }
00812 }
00813
00814 png_structp _png;
00815 string &_data;
00816 list<string> _blocks;
00817 size_t _size;
00818 };
00819
00820
00821
00822 bool
00823 decodePNG(uint32 &width,uint32 &height,std::string &image,const std::string &data)
00824 {
00825 const char *pngSignature = "\211PNG\r\n\032\n";
00826 if (data.size()<8 || strncmp(data.c_str(),pngSignature,8))
00827 return false;
00828
00829 png_structp png_ptr =
00830 png_create_read_struct(PNG_LIBPNG_VER_STRING,(png_voidp) NULL,NULL,NULL);
00831
00832 if (!png_ptr)
00833 return false;
00834
00835 png_infop info_ptr = png_create_info_struct(png_ptr);
00836
00837 if (!info_ptr)
00838 {
00839 png_destroy_read_struct(&png_ptr,(png_infopp)NULL, (png_infopp)NULL);
00840 return false;
00841 }
00842
00843
00844
00845 GltPngReader read(data,png_ptr);
00846
00847 png_read_info(png_ptr, info_ptr);
00848
00849 int bit_depth, color_type, interlace_type,
00850 compression_type, filter_type;
00851
00852 png_uint_32 w,h;
00853
00854 png_get_IHDR(png_ptr, info_ptr, &w, &h,
00855 &bit_depth, &color_type, &interlace_type,
00856 &compression_type, &filter_type);
00857
00858 width = w;
00859 height = h;
00860
00861
00862
00863 if (bit_depth<8)
00864 png_set_packing(png_ptr);
00865
00866 if (bit_depth==16)
00867 png_set_strip_16(png_ptr);
00868
00869 int channels = png_get_channels(png_ptr,info_ptr);
00870
00871 switch (color_type)
00872 {
00873 case PNG_COLOR_TYPE_GRAY: image.resize(width*height); break;
00874 case PNG_COLOR_TYPE_GRAY_ALPHA: image.resize(width*height*2); break;
00875 case PNG_COLOR_TYPE_RGB: image.resize(width*height*3); break;
00876 case PNG_COLOR_TYPE_RGB_ALPHA: image.resize(width*height*4); break;
00877 case PNG_COLOR_TYPE_PALETTE:
00878 image.resize(width*height*3);
00879 png_set_palette_to_rgb(png_ptr);
00880 break;
00881 }
00882
00883 int rowbytes = image.size()/height;
00884 assert(image.size()==rowbytes*height);
00885
00886 const char **row_pointers = (const char **) malloc(height*sizeof(char *));
00887 for(int i=0;i<height;i++)
00888 row_pointers[i] = image.c_str() + rowbytes*(height-1-i);
00889
00890 png_read_image(png_ptr, (png_bytepp)row_pointers);
00891
00892 free(row_pointers);
00893 free(info_ptr);
00894 free(png_ptr);
00895
00896 return true;
00897 }
00898
00899 bool
00900 encodePNG(std::string &data,const uint32 &width,const uint32 &height,const std::string &image)
00901 {
00902 png_structp png_ptr =
00903 png_create_write_struct(PNG_LIBPNG_VER_STRING,(png_voidp) NULL,NULL,NULL);
00904
00905 if (!png_ptr)
00906 return false;
00907
00908 png_infop info_ptr = png_create_info_struct(png_ptr);
00909
00910 if (!info_ptr)
00911 {
00912 png_destroy_write_struct(&png_ptr,(png_infopp)NULL);
00913 return false;
00914 }
00915
00916 {
00917 GltPngWriter write(data,png_ptr);
00918
00919 const int channels = image.size()/(width*height);
00920 const int bit_depth = 8;
00921 int color_type = 0;
00922
00923 switch (channels)
00924 {
00925 case 1: color_type = PNG_COLOR_TYPE_GRAY; break;
00926 case 2: color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break;
00927 case 3: color_type = PNG_COLOR_TYPE_RGB; break;
00928 case 4: color_type = PNG_COLOR_TYPE_RGB_ALPHA; break;
00929 }
00930
00931 assert(color_type);
00932
00933 png_set_IHDR(
00934 png_ptr,info_ptr,width,height,bit_depth,color_type,
00935 PNG_INTERLACE_ADAM7,PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
00936
00937 png_set_strip_16(png_ptr);
00938 png_set_packing(png_ptr);
00939
00940 int rowbytes = image.size()/height;
00941 assert(image.size()==rowbytes*height);
00942
00943 const char **row_pointers = (const char **) malloc(height*sizeof(char *));
00944 for(int i=0;i<height;i++)
00945 row_pointers[i] = image.c_str() + rowbytes*(height-1-i);
00946
00947 png_write_info(png_ptr, info_ptr);
00948 png_write_image(png_ptr,(png_bytepp) row_pointers);
00949 png_write_end(png_ptr,info_ptr);
00950
00951 free(row_pointers);
00952 }
00953
00954 free(info_ptr);
00955 free(png_ptr);
00956
00957 return true;
00958 }
00959
00960 #endif
00961
00962
00963
00964
00965
00966 bool
00967 encodePPM(string &data,const uint32 width,const uint32 height,const string &image)
00968 {
00969 const bool ppm = width*height*3==image.size();
00970 const bool pgm = width*height ==image.size();
00971
00972
00973
00974 if (!ppm && !pgm)
00975 return false;
00976
00977
00978
00979 char header[100];
00980 sprintf(header,"%s\n%u %u\n255\n",ppm ? "P6" : "P5",width,height);
00981
00982
00983
00984 data.resize(strlen(header)+image.size());
00985 assert(data.size()==strlen(header)+image.size());
00986 strcpy((char *) data.data(),header);
00987
00988
00989
00990 const uint32 lineSize = ppm ? width*3 : width;
00991
00992
00993 byte *i = (byte *) data.data() + strlen(header);
00994
00995
00996 const byte *j = (const byte *) image.data() + image.size() - lineSize;
00997
00998
00999 for (int k=0; k<height; i+=lineSize, j-=lineSize, k++)
01000 memcpy(i,j,lineSize);
01001
01002 return true;
01003 }
01004
01005 bool
01006 eencodeBMP(string &data,const uint32 width,const uint32 height,const string &image)
01007 {
01008
01009 return false;
01010 }
01011
01012 bool
01013 encodeTGA(string &data,const uint32 width,const uint32 height,const string &image)
01014 {
01015
01016
01017
01018 if (width*height*3!=image.size())
01019 return false;
01020
01021
01022 data.resize(18+image.size());
01023
01024 data[0] = 0;
01025 data[1] = 0;
01026 data[2] = 2;
01027 data[3] = 0;
01028 data[4] = 0;
01029 data[5] = 0;
01030 data[6] = 0;
01031 data[7] = 0;
01032 data[8] = 0;
01033 data[9] = 0;
01034 data[10] = 0;
01035 data[11] = 0;
01036 *(uint16 *) (data.data()+12) = littleEndian(uint16(width));
01037 *(uint16 *) (data.data()+14) = littleEndian(uint16(height));
01038 data[16] = 24;
01039 data[17] = 0;
01040
01041
01042
01043 byte *i = (byte *) data.data()+18;
01044 const byte *j = (const byte *) image.data();
01045
01046 for (int y=0; y<height; y++)
01047 {
01048
01049
01050
01051 for (int x=0; x<width; x++)
01052 {
01053 *(i++) = *(j++ + 2);
01054 *(i++) = *(j++);
01055 *(i++) = *(j++ - 2);
01056 }
01057 }
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115
01116
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180 return true;
01181 }