image.C

00001 /*
00002  * This file is part of the "Archon" framework.
00003  * (http://files3d.sourceforge.net)
00004  *
00005  * Copyright © 2002 by Kristian Spangsege and Brian Kristiansen.
00006  *
00007  * Permission to use, copy, modify, and distribute this software and
00008  * its documentation under the terms of the GNU General Public License is
00009  * hereby granted. No representations are made about the suitability of
00010  * this software for any purpose. It is provided "as is" without express
00011  * or implied warranty. See the GNU General Public License
00012  * (http://www.gnu.org/copyleft/gpl.html) for more details.
00013  *
00014  * The characters in this file are ISO8859-1 encoded.
00015  *
00016  * The documentation in this file is in "Doxygen" style
00017  * (http://www.doxygen.org).
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       // Explicit call to destructor
00125       this->~Rep();
00126       // A MemoryBuffer allocated this memory, so let the
00127       // MemoryBuffer deallocate it too.
00128       MemoryBuffer buffer(reinterpret_cast<char *>(this));
00129     }
00130 
00131     /*
00132      * Assumes that a 'char' is 8 bit wide
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      * Assumes that a 'char' is 8 bit wide
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       // Primary auto-detection
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       // Secondary auto-detection
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         // Determine format by suffix
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 }

Generated on Sun Jul 30 22:55:43 2006 for Archon by  doxygen 1.4.4