00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <errno.h>
00021 #include <string.h>
00022 #include <setjmp.h>
00023
00024 #include <archon/util/thread.H>
00025 #include <archon/util/image.H>
00026 #include <archon/util/stream.H>
00027
00028 #include <archon/util/image_png.H>
00029 #include <archon/util/image_tiff.H>
00030 #include <archon/util/image_pnm.H>
00031 #include <archon/util/image_jpeg.H>
00032 #include <archon/util/image_gif.H>
00033
00034 namespace Archon
00035 {
00036 namespace Utilities
00037 {
00038 using namespace std;
00039
00040 namespace
00041 {
00042 struct DefaultContext: Image::Context
00043 {
00044 size_t getNumberOfFormats() const
00045 {
00046 return formats.size();
00047 }
00048
00049 const Image::Format *getFormat(size_t i) const
00050 {
00051 return formats[i];
00052 }
00053
00054 void add(const Image::Format *f)
00055 {
00056 if(f) formats.push_back(f);
00057 }
00058
00059 DefaultContext()
00060 {
00061 add(getDefaultPngFormat());
00062 add(getDefaultTiffFormat());
00063 add(getDefaultPnmFormat());
00064 add(getDefaultJpegFormat());
00065 add(getDefaultGifFormat());
00066 }
00067
00068 vector<const Image::Format *> formats;
00069 };
00070 }
00071
00072 const string Image::PNG = "png";
00073 const string Image::TIFF = "tiff";
00074 const string Image::PNM = "pnm";
00075 const string Image::JPEG = "jpeg";
00076 const string Image::GIF = "gif";
00077
00078 Image::Image(unsigned width, unsigned height,
00079 ComponentSpecifier components,
00080 unsigned bitsPerComponent,
00081 string comment)
00082 {
00083 if(width<1 || height<1)
00084 ARCHON_THROW1(ArgumentException,
00085 "Invalid zero size image");
00086 if(bitsPerComponent != 1 &&
00087 bitsPerComponent != 2 &&
00088 bitsPerComponent != 4 &&
00089 bitsPerComponent != 8 &&
00090 bitsPerComponent != 16)
00091 ARCHON_THROW1(ArgumentException, "Unsupported component width: " +
00092 Text::toString(bitsPerComponent));
00093
00094 unsigned charsPerPixel = (bitsPerComponent*components+7)/8;
00095 unsigned charsPerRow = charsPerPixel*width;
00096
00097 MemoryBuffer buffer(sizeof(Rep) + charsPerRow*height);
00098 r.reset(new(buffer.get()) Rep(width, height, bitsPerComponent,
00099 charsPerPixel, charsPerRow,
00100 (1<<bitsPerComponent)-1, components,
00101 comment));
00102 buffer.out();
00103 }
00104
00105 const Image::Context *Image::Context::get()
00106 {
00107 static DefaultContext c;
00108 return &c;
00109 }
00110
00111 Image::Rep *Image::Rep::refClone() const
00112 {
00113 MemoryBuffer buffer(sizeof(Rep) + charsPerRow*height);
00114 Rep *r = new(buffer.get()) Rep(width, height, bitsPerComponent,
00115 charsPerPixel, charsPerRow,
00116 maxComponentValue, components,
00117 comment);
00118 buffer.out();
00119 return r;
00120 }
00121
00122 void Image::Rep::refDelete() throw()
00123 {
00124
00125 this->~Rep();
00126
00127
00128 MemoryBuffer buffer(reinterpret_cast<char *>(this));
00129 }
00130
00131
00132
00133
00134 unsigned Image::Rep::getComponent(char *pixel, unsigned component)
00135 {
00136 switch(bitsPerComponent)
00137 {
00138 case 8:
00139 return *(reinterpret_cast<unsigned char *>(pixel)+component);
00140 case 16:
00141 {
00142 unsigned char *const c = reinterpret_cast<unsigned char *>(pixel)+component*2;
00143 return *c + (static_cast<unsigned>(*(c+1))<<8);
00144 }
00145 case 1:
00146 return *reinterpret_cast<unsigned char *>(pixel)>>component & 1;
00147 case 2:
00148 return *reinterpret_cast<unsigned char *>(pixel)>>component*2 & 3;
00149 case 4:
00150 return component<2 ?
00151 component==0 ? *reinterpret_cast<unsigned char *>(pixel) & 15 : *reinterpret_cast<unsigned char *>(pixel)>>4 & 15 :
00152 component==2 ? *(reinterpret_cast<unsigned char *>(pixel)+1) & 15 : *(reinterpret_cast<unsigned char *>(pixel)+1)>>4 & 15;
00153 }
00154 ARCHON_THROW1(InternalException,
00155 "Illegal component bit width");
00156 }
00157
00158
00159
00160
00161 void Image::Rep::setComponent(char *pixel, unsigned component, unsigned v)
00162 {
00163 unsigned char mask;
00164 switch(bitsPerComponent)
00165 {
00166 case 8:
00167 *(reinterpret_cast<unsigned char *>(pixel)+component) = static_cast<unsigned char>(v);
00168 break;
00169 case 16:
00170 {
00171 unsigned char *const c = reinterpret_cast<unsigned char *>(pixel)+component*2;
00172 *c = static_cast<unsigned char>(v);
00173 *(c+1) = static_cast<unsigned char>(v>>8);
00174 break;
00175 }
00176 case 1:
00177 mask = static_cast<unsigned char>(1)<<component;
00178 *reinterpret_cast<unsigned char *>(pixel) = *reinterpret_cast<unsigned char *>(pixel) & ~mask |
00179 static_cast<unsigned char>(v)<<component & mask;
00180 break;
00181 case 2:
00182 mask = static_cast<unsigned char>(3)<<component*2;
00183 *reinterpret_cast<unsigned char *>(pixel) = *reinterpret_cast<unsigned char *>(pixel) & ~mask |
00184 static_cast<unsigned char>(v)<<component*2 & mask;
00185 break;
00186 case 4:
00187 if(component<2)
00188 *reinterpret_cast<unsigned char *>(pixel) = component==0 ?
00189 *reinterpret_cast<unsigned char *>(pixel) & 240 | static_cast<unsigned char>(v) & 15 :
00190 *reinterpret_cast<unsigned char *>(pixel) & 15 | static_cast<unsigned char>(v)<<4 & 240;
00191 else
00192 *(reinterpret_cast<unsigned char *>(pixel)+1) = component==2 ?
00193 *(reinterpret_cast<unsigned char *>(pixel)+1) & 240 | static_cast<unsigned char>(v) & 15 :
00194 *(reinterpret_cast<unsigned char *>(pixel)+1) & 15 | static_cast<unsigned char>(v)<<4 & 240;
00195 break;
00196 default:
00197 ARCHON_THROW1(InternalException,
00198 "Illegal component bit width");
00199 }
00200 }
00201
00202
00203 void Image::Rep::getPixel(int x, int y, unsigned &l)
00204 {
00205 char *p = getPixelPtr(x, y);
00206 switch(components)
00207 {
00208 case components_l:
00209 l = getComponent(p, 0);
00210 break;
00211 case components_la:
00212 l = static_cast<unsigned>(getComponent(p, 0)*toFloat(getComponent(p, 1)));
00213 break;
00214 case components_rgb:
00215 l = static_cast<unsigned>((static_cast<unsigned long>(getComponent(p, 0))+getComponent(p, 1)+getComponent(p, 2))/3);
00216 break;
00217 case components_rgba:
00218 l = static_cast<unsigned>((static_cast<double>(getComponent(p, 0))+getComponent(p, 1)+getComponent(p, 2))/3*toFloat(getComponent(p, 3)));
00219 break;
00220 }
00221 }
00222
00223 void Image::Rep::setPixel(int x, int y, unsigned l)
00224 {
00225 char *p = getPixelPtr(x, y);
00226 switch(components)
00227 {
00228 case components_la:
00229 setComponent(p, 1, maxComponentValue);
00230 case components_l:
00231 setComponent(p, 0, l);
00232 break;
00233 case components_rgba:
00234 setComponent(p, 3, maxComponentValue);
00235 case components_rgb:
00236 setComponent(p, 0, l);
00237 setComponent(p, 1, l);
00238 setComponent(p, 2, l);
00239 break;
00240 }
00241 }
00242
00243 void Image::Rep::getPixel(int x, int y, unsigned &l, unsigned &a)
00244 {
00245 char *p = getPixelPtr(x, y);
00246 switch(components)
00247 {
00248 case components_l:
00249 l = getComponent(p, 0);
00250 a = maxComponentValue;
00251 break;
00252 case components_la:
00253 l = getComponent(p, 0);
00254 a = getComponent(p, 1);
00255 break;
00256 case components_rgb:
00257 l = static_cast<unsigned>((static_cast<unsigned long>(getComponent(p, 0))+getComponent(p, 1)+getComponent(p, 2))/3);
00258 a = maxComponentValue;
00259 break;
00260 case components_rgba:
00261 l = static_cast<unsigned>((static_cast<unsigned long>(getComponent(p, 0))+getComponent(p, 1)+getComponent(p, 2))/3);
00262 a = getComponent(p, 3);
00263 break;
00264 }
00265 }
00266
00267 void Image::Rep::setPixel(int x, int y, unsigned l, unsigned a)
00268 {
00269 char *p = getPixelPtr(x, y);
00270 switch(components)
00271 {
00272 case components_l:
00273 setComponent(p, 0, static_cast<unsigned>(l*toFloat(a&maxComponentValue)));
00274 break;
00275 case components_la:
00276 setComponent(p, 0, l);
00277 setComponent(p, 1, a);
00278 break;
00279 case components_rgb:
00280 {
00281 const unsigned _l = static_cast<unsigned>(l*toFloat(a&maxComponentValue));
00282 setComponent(p, 0, _l);
00283 setComponent(p, 1, _l);
00284 setComponent(p, 2, _l);
00285 break;
00286 }
00287 case components_rgba:
00288 setComponent(p, 0, l);
00289 setComponent(p, 1, l);
00290 setComponent(p, 2, l);
00291 setComponent(p, 3, a);
00292 break;
00293 }
00294 }
00295
00296 void Image::Rep::getPixel(int x, int y, unsigned &r, unsigned &g, unsigned &b)
00297 {
00298 char *p = getPixelPtr(x, y);
00299 switch(components)
00300 {
00301 case components_l:
00302 r = g = b = getComponent(p, 0);
00303 break;
00304 case components_la:
00305 r = g = b = static_cast<unsigned>(getComponent(p, 0)*toFloat(getComponent(p, 1)));
00306 break;
00307 case components_rgb:
00308 r = getComponent(p, 0);
00309 g = getComponent(p, 1);
00310 b = getComponent(p, 2);
00311 break;
00312 case components_rgba:
00313 {
00314 const double a = toFloat(getComponent(p, 3));
00315 r = static_cast<unsigned>(getComponent(p, 0)*a);
00316 g = static_cast<unsigned>(getComponent(p, 1)*a);
00317 b = static_cast<unsigned>(getComponent(p, 2)*a);
00318 break;
00319 }
00320 }
00321 }
00322
00323 void Image::Rep::setPixel(int x, int y, unsigned r, unsigned g, unsigned b)
00324 {
00325 char *p = getPixelPtr(x, y);
00326 switch(components)
00327 {
00328 case components_la:
00329 setComponent(p, 1, maxComponentValue);
00330 case components_l:
00331 setComponent(p, 0, static_cast<unsigned>((static_cast<unsigned long>(r)+b+g)/3));
00332 break;
00333 case components_rgba:
00334 setComponent(p, 3, maxComponentValue);
00335 case components_rgb:
00336 setComponent(p, 0, r);
00337 setComponent(p, 1, g);
00338 setComponent(p, 2, b);
00339 break;
00340 }
00341 }
00342
00343 void Image::Rep::getPixel(int x, int y, unsigned &r, unsigned &g, unsigned &b, unsigned &a)
00344 {
00345 char *p = getPixelPtr(x, y);
00346 switch(components)
00347 {
00348 case components_l:
00349 r = g = b = getComponent(p, 0);
00350 a = maxComponentValue;
00351 break;
00352 case components_la:
00353 r = g = b = getComponent(p, 0);
00354 a = getComponent(p, 1);
00355 break;
00356 case components_rgb:
00357 r = getComponent(p, 0);
00358 g = getComponent(p, 1);
00359 b = getComponent(p, 2);
00360 a = maxComponentValue;
00361 break;
00362 case components_rgba:
00363 r = getComponent(p, 0);
00364 g = getComponent(p, 1);
00365 b = getComponent(p, 2);
00366 a = getComponent(p, 3);
00367 break;
00368 }
00369 }
00370
00371 void Image::Rep::setPixel(int x, int y, unsigned r, unsigned g, unsigned b, unsigned a)
00372 {
00373 char *p = getPixelPtr(x, y);
00374 switch(components)
00375 {
00376 case components_l:
00377 setComponent(p, 0, static_cast<unsigned>((static_cast<double>(r)+b+g)/3*toFloat(a&maxComponentValue)));
00378 break;
00379 case components_la:
00380 setComponent(p, 0, static_cast<unsigned>((static_cast<unsigned long>(r)+b+g)/3));
00381 setComponent(p, 1, a);
00382 break;
00383 case components_rgb:
00384 {
00385 const double _a = toFloat(a&maxComponentValue);
00386 setComponent(p, 0, static_cast<unsigned>(r*_a));
00387 setComponent(p, 1, static_cast<unsigned>(g*_a));
00388 setComponent(p, 2, static_cast<unsigned>(b*_a));
00389 break;
00390 }
00391 case components_rgba:
00392 setComponent(p, 0, r);
00393 setComponent(p, 1, g);
00394 setComponent(p, 2, b);
00395 setComponent(p, 3, a);
00396 break;
00397 }
00398 }
00399
00400
00401 void Image::_load(Ref<Stream::Reader> reader,
00402 string sourceName, string formatSpecifier,
00403 ProgressTracker *tracker, Logger *logger,
00404 const Context *context)
00405 throw(UnknownFormatException, InvalidFormatException,
00406 IOException, UnexpectedException)
00407 {
00408 if(!context) context = Context::get();
00409
00410 Ref<Stream::RewindReader> rewindReader(Stream::RewindReader::get(reader));
00411
00412
00413 if(formatSpecifier.empty())
00414 for(unsigned i=0; i<context->getNumberOfFormats(); ++i)
00415 {
00416 const Format *f = context->getFormat(i);
00417 bool s = f->checkSignature(rewindReader);
00418 rewindReader->rewind();
00419 if(!s) continue;
00420 formatSpecifier = f->getSpecifier();
00421 break;
00422 }
00423 rewindReader->release();
00424
00425
00426 if(formatSpecifier.empty())
00427 {
00428 string suffix = Text::toLowerCase(File::suffixOf(sourceName));
00429 if(!suffix.empty())
00430 for(unsigned i=0; i<context->getNumberOfFormats(); ++i)
00431 {
00432 const Format *f = context->getFormat(i);
00433 if(!f->checkSuffix(suffix)) continue;
00434 formatSpecifier = f->getSpecifier();
00435 break;
00436 }
00437 }
00438
00439 if(formatSpecifier.empty())
00440 ARCHON_THROW1(UnknownFormatException,
00441 "Image format could not be detected from the initial "
00442 "data nor from the file name: \"" + sourceName + "\"");
00443
00444 for(unsigned i=0; i<context->getNumberOfFormats(); ++i)
00445 {
00446 const Format *f = context->getFormat(i);
00447 if(formatSpecifier != f->getSpecifier()) continue;
00448 *this = f->load(rewindReader, tracker, logger);
00449 return;
00450 }
00451
00452 ARCHON_THROW1(ArgumentException, "Unrecognized format "
00453 "specifier: \"" + formatSpecifier + "\"");
00454 }
00455
00456 void Image::_save(Ref<Stream::Writer> writer,
00457 string targetName, string formatSpecifier,
00458 ProgressTracker *tracker, Logger *logger,
00459 const Context *context) const
00460 throw(UnknownFormatException, IOException, UnexpectedException)
00461 {
00462 if(!context) context = Context::get();
00463
00464 if(formatSpecifier.empty())
00465 {
00466
00467 string suffix = Text::toLowerCase(File::suffixOf(targetName));
00468 if(!suffix.empty()) for(unsigned i=0; i<context->getNumberOfFormats(); ++i)
00469 {
00470 const Format *f = context->getFormat(i);
00471 if(!f->checkSuffix(suffix)) continue;
00472 formatSpecifier = f->getSpecifier();
00473 break;
00474 }
00475 }
00476
00477 if(formatSpecifier.empty())
00478 ARCHON_THROW1(UnknownFormatException, "Image format could not be "
00479 "detected from the file name: \"" + targetName + "\"");
00480
00481 for(unsigned i=0; i<context->getNumberOfFormats(); ++i)
00482 {
00483 const Format *f = context->getFormat(i);
00484 if(formatSpecifier != f->getSpecifier()) continue;
00485 f->save(*this, writer, tracker, logger);
00486 return;
00487 }
00488
00489 ARCHON_THROW1(ArgumentException, "Unrecognized format "
00490 "specifier: \"" + formatSpecifier + "\"");
00491 }
00492 }
00493 }