Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members  

Image.cc

Go to the documentation of this file.
00001 /*
00002     File:           Image.cc
00003 
00004     Function:       See header file
00005 
00006     Author(s):      Andrew Willmott
00007 
00008     Copyright:      (c) 1997-2000, Andrew Willmott
00009 */
00010 
00011 #include "gcl/Image.h"
00012 #include "gcl/GCLConfig.h"
00013 #include "gcl/VecUtil.h"
00014 
00015 #include <iostream.h>
00016 #include <stdio.h>
00017 #include <ctype.h>
00018 
00019 
00020 // --- Image class ------------------------------------------------------------
00021 
00022 
00023 
00024 Int Image::sJPEGQuality = 90;
00025 
00026 Void Image::Clear(const Colour &c)
00027 // should almost always be overridden
00028 {
00029     Int         x, y;
00030 
00031     for (y = 0; y < height; y++)
00032         for (x = 0; x < width; x++)
00033             SetPixel(x, y, c);
00034 }
00035 
00036 Void Image::CopyFrom(Int x, Int y, Image &img)
00037 {
00038     Int     test = img.Width();
00039     Int     copyWidth = Min(img.Width(), width - x);
00040     Int     copyHeight = Min(img.Height(), height - y);
00041     Colour  *buffer = new Colour[copyWidth];
00042     Int     i;
00043     
00044     for (i = 0; i < copyHeight; i++)
00045     {
00046         img.GetSpan(i, x, copyWidth, buffer);
00047         SetSpan(y++, 0, copyWidth, buffer);
00048     } 
00049     
00050     delete[] buffer;
00051 }
00052 
00053 Void Image::GammaCorrect(ClrReal gamma)
00054 {
00055     ClrReal         invGamma = 1.0 / gamma;
00056     Colour          c;
00057     Int             x, y;
00058     
00059     for (y = 0; y < Height(); y++)
00060         for (x = 0; x < Width(); x++)
00061         {
00062             c = GetPixel(x, y);
00063 
00064             c[0] = pow(c[0], invGamma);
00065             c[1] = pow(c[1], invGamma);
00066             c[2] = pow(c[2], invGamma);
00067 
00068             SetPixel(x, y, c);
00069         }
00070 }
00071 
00072 Void Image::Scale(ClrReal scale)
00073 {
00074     Colour  *buffer = new Colour[width];
00075     Int     i, j;
00076     Colour  result;
00077     
00078     for (i = 0; i < height; i++)
00079     {
00080         GetSpan(i, 0, width, buffer);
00081         for (j = 0; j < width; j++)
00082             buffer[j] *= scale;
00083         SetSpan(i, 0, width, buffer);
00084     } 
00085 }
00086 
00087 ClrReal Image::MaxComponent()
00088 {
00089     Int         x, y;
00090     ClrReal     maxCmpt = 0.0;
00091     Colour      c;
00092     
00093     for (y = 0; y < height; y++)
00094         for (x = 0; x < width; x++)
00095         {
00096             c = GetPixel(x, y);
00097             maxCmpt = Max(maxCmpt, MaxCmpt(c));
00098         }
00099 
00100     return(maxCmpt);
00101 }
00102 
00103 Colour Image::AverageColour()
00104 {
00105     Colour  *buffer = new Colour[width];
00106     Int     i, j;
00107     Colour  result = cBlack;
00108     
00109     for (i = 0; i < height; i++)
00110     {
00111         Colour  bsum = cBlack;
00112         
00113         GetSpan(i, 0, width, buffer);
00114         for (j = 0; j < width; j++)
00115             bsum += buffer[j];
00116         bsum /= width;
00117         result += bsum;
00118     }
00119 
00120     delete[] buffer;
00121     result /= height;
00122 
00123     return(result);
00124 }
00125 
00126 Void Image::FindComponentBounds(Colour &min, Colour &max)
00127 {
00128     Int         x, y;
00129     Colour      c;
00130     
00131     for (y = 0; y < height; y++)
00132         for (x = 0; x < width; x++)
00133         {
00134             c = GetPixel(x, y);
00135             FindMinCmpts(min, c, min);
00136             FindMaxCmpts(max, c, max);
00137         }
00138 }
00139 
00140 Void Image::Transform(const ClrTrans &trans)
00141 {
00142     Colour  *buffer = new Colour[width];
00143     Int     i, j;
00144     
00145     for (i = 0; i < height; i++)
00146     {
00147         GetSpan(i, 0, width, buffer);
00148         for (j = 0; j < width; j++)
00149         {
00150             buffer[j] = xform(trans, buffer[j]);
00151             ClipColour(buffer[j]);
00152         }
00153         SetSpan(i, 0, width, buffer);
00154     } 
00155 
00156     delete[] buffer;
00157 }
00158 
00159 Void Image::Over(Int x, Int y, Image &img)
00160 {
00161     Int     test = img.Width();
00162     Int     copyWidth = Min(img.Width(), width - x);
00163     Int     copyHeight = Min(img.Height(), height - y);
00164     Colour  *buffer = new Colour[copyWidth];
00165     Int     i;
00166 
00167     // XXX UNFINISHED: want to do composite operation: d = d * (1 - s.alpha) + s
00168     
00169     for (i = 0; i < copyHeight; i++)
00170     {
00171         img.GetSpan(i, x, copyWidth, buffer);
00172         SetSpan(y++, 0, copyWidth, buffer);
00173     } 
00174     
00175     delete[] buffer;
00176 }
00177 
00178 Void Image::DownSample(Image &out)
00180 {
00181     Int     i, j;
00182     static ColourList span1, span2, outSpan;
00183 
00184     out.SetSize(Width() / 2, Height() / 2); 
00185     span1.SetSize(Width());
00186     span2.SetSize(Width());
00187     outSpan.SetSize(out.Width());
00188 
00189     for (i = 0; i < out.Height(); i++)
00190     {
00191         GetSpan(2 * i, 0, Width(), span1.Ref());
00192         GetSpan(2 * i + 1, 0, Width(), span2.Ref());
00193 
00194         for (j = 0; j < out.Width(); j++)
00195         {
00196             outSpan[j]  = span1[2 * j] + span1[2 * j + 1];
00197             outSpan[j] += span2[2 * j] + span2[2 * j + 1];
00198             outSpan[j] /= 4.0;
00199         }
00200 
00201         out.SetSpan(i, 0, out.Width(), outSpan.Ref());
00202     }
00203 }
00204 
00205 
00206 // These should almost always be overridden with more efficient routines
00207 
00208 Void Image::SetRealPixel(Int x, Int y, ClrReal r, ImgChannel channel)
00209 {
00210     if (channel == chMono)
00211         SetPixel(x, y, cWhite * r);
00212     else if (channel <= chBlue)
00213     {
00214         Colour c = GetPixel(x, y);
00215 
00216         c[channel - chRed] = r;     
00217         SetPixel(x, y, c);
00218     }
00219 }
00220 
00221 ClrReal Image::GetRealPixel(Int x, Int y, ImgChannel channel) const
00222 {
00223     if (channel <= chBlue)
00224     {
00225         Colour c = GetPixel(x, y);
00226 
00227         if (channel == chMono)
00228             return(dot(cWhite, c) * (1.0 / 3.0));
00229         else
00230             return(c[channel - chRed]);
00231     }
00232     else
00233         return(0.0);
00234 }
00235 
00236 Void Image::SetRealSpan(Int row, Int start, Int length, 
00237                         const ClrReal *src, ImgChannel channel)
00238 {
00239     Int     i;
00240 
00241     for (i = 0; i < length; i++)
00242         SetRealPixel(start + i, row, src[i], channel);
00243 }
00244 
00245 Void Image::GetRealSpan(Int row, Int start, Int length, 
00246                         ClrReal *dst, ImgChannel channel) const
00247 {
00248     Int     i;
00249 
00250     for (i = 0; i < length; i++)
00251         dst[i] = GetRealPixel(start + i, row, channel);
00252 }
00253 
00254 Void Image::SetRGBASpan(Int row, Int start, Int length, const RGBAPixel *src) 
00255 {
00256     Int     i;
00257     Colour  *buffer = new Colour[length];
00258 
00259     for (i = 0; i < length; i++)
00260         buffer[i] = RGBAToColour(src[i]);
00261 
00262     SetSpan(row, start, length, buffer);
00263 
00264     delete[] buffer;
00265 }
00266 
00267 Void Image::GetRGBASpan(Int row, Int start, Int length, RGBAPixel *dst) const
00268 {
00269     Int     i;
00270     Colour  *buffer = new Colour[length];
00271 
00272     GetSpan(row, start, length, buffer);
00273 
00274     for (i = 0; i < length; i++)
00275         dst[i] = ColourToRGBA(buffer[i]);
00276 
00277     delete[] buffer;
00278 }
00279 
00280 Void Image::SetByteSpan(Int row, Int start, Int length, 
00281                         const Byte *src, ImgChannel channel)
00282 {
00283     Int     i;
00284     Colour  *buffer = new Colour[length];
00285 
00286     for (i = 0; i < length; i++)
00287         buffer[i] = ByteToColour(src[i]);
00288 
00289     SetSpan(row, start, length, buffer);
00290 
00291     delete[] buffer;
00292 }
00293 
00294 Void Image::GetByteSpan(Int row, Int start, Int length, 
00295                         Byte *dst, ImgChannel channel) const
00296 {
00297     Int     i;
00298     Colour  *buffer = new Colour[length];
00299 
00300     GetSpan(row, start, length, buffer);
00301 
00302     for (i = 0; i < length; i++)
00303         dst[i] = ColourToByte(buffer[i]);
00304 
00305     delete[] buffer;
00306 }
00307 
00308 
00309 // --- File methods -----------------------------------------------------------
00310 
00311 Char *tImageFormats[] = 
00312 {
00313     "ppm",      "PPM image format",
00314 #ifdef GCL_TIFF
00315     "tif",      "Adobe TIFF format",
00316 #endif
00317 #ifdef GCL_JPEG
00318     "jpg",      "JPEG format",
00319 #endif
00320 #ifdef GCL_GIF
00321     "gif",      "GIF format (read only)",
00322 #endif
00323     0
00324 };
00325 
00326 Void Image::PrintSupportedFormats(ostream &s)
00327 {
00328     Char    **p = tImageFormats;
00329     
00330     s << "Supported image file extensions: " << endl;
00331 
00332     while (*p)
00333     {
00334         s << String().Printf("%-5s %s\n", *p, *(p + 1));
00335         p += 2;
00336     }
00337 }
00338 
00339 Int Image::Save(FileName &filename)
00340 {
00341     if (filename.GetExtension() == "ppm")
00342         return(SavePPM(filename.GetPath()));
00343 #ifdef GCL_TIFF
00344     else if (filename.GetExtension() == "tiff" || filename.GetExtension() == "tif")
00345         return(SaveTIFF(filename.GetPath()));
00346 #endif
00347 #ifdef GCL_JPEG
00348     else if (filename.GetExtension() == "jpg")
00349         return(SaveJPEG(filename.GetPath()));
00350 #endif
00351     else
00352     {
00353 #ifdef GCL_TIFF
00354         if (filename.GetExtension() != "")
00355             cerr << "Unknown image file extension:"
00356                  << " saving in TIFF format" << endl;
00357         filename.SetExtension("tif");
00358         return(SaveTIFF(filename.GetPath()));
00359 #else
00360         if (filename.GetExtension() != "")
00361             cerr << "Unknown image file extension:"
00362                  << " saving in PPM format" << endl;
00363         filename.SetExtension("ppm");
00364         return(SavePPM(filename.GetPath()));
00365 #endif      
00366     }
00367 }
00368 
00369 static StrConst kImageExtensions[] =
00370 {
00371     "ppm",
00372     "pgm",
00373 #ifdef GCL_TIFF
00374     "tif",
00375     "tiff",
00376 #endif
00377 #ifdef GCL_JPEG
00378     "jpg",
00379 #endif
00380 #ifdef GCL_GIF
00381     "gif",
00382 #endif
00383     0
00384 };
00385 
00386 Int Image::Load(FileName &filename)
00387 {
00388     Int     result = filename.FindFileExtension(kImageExtensions);
00389 
00390     if (result == kBadExtension)
00391         cerr << "error: unknown image extension '" << filename.GetExtension()
00392              << "'" << endl;
00393     else if (result == kFileNotFound)
00394         cerr << "error: can't find image file " << filename.GetPath() << endl;
00395 
00396     if (result < 0)
00397         return(result);
00398 
00399     filename.DecompressSetup();
00400     if (result < 2)
00401         return(LoadPPM(filename.GetPath()));
00402 #ifdef GCL_TIFF
00403     else if (filename.GetExtension() == "tiff" || filename.GetExtension() == "tif")
00404         return(LoadTIFF(filename.GetPath()));
00405 #endif
00406 #ifdef GCL_JPEG
00407     else if (filename.GetExtension() == "jpg")
00408         return(LoadJPEG(filename.GetPath()));
00409 #endif
00410 #ifdef GCL_GIF
00411     else if (filename.GetExtension() == "gif")
00412         return(LoadGIF(filename.GetPath()));
00413 #endif
00414     filename.DecompressCleanup();
00415 
00416     _Error("Unhandled extension");
00417 
00418     return(-1);
00419 }
00420 
00421 
00422 // --- PPM read/write ---------------------------------------------------------
00423 
00424 
00425 Int Image::SavePPM(const Char *filename)
00426 {
00427     int         i, j;
00428     FILE        *ppm;
00429     RGBAPixel   *p, *buffer = new RGBAPixel[width];
00430     
00431     if (!buffer)
00432         return(-1);
00433     ppm = fopen(filename, "w");
00434     if (!ppm)
00435         return(-1);
00436     
00437     fprintf(ppm, "P6\n%u %u\n255\n", width, height);
00438 
00439     for (j = height - 1; j >= 0; j--)
00440     {
00441         GetRGBASpan(j, 0, width, buffer);
00442         p = buffer;
00443         for (i = 0; i < width; i++, p++)
00444         {
00445             fputc(p->ch[rgba_R], ppm);
00446             fputc(p->ch[rgba_G], ppm);
00447             fputc(p->ch[rgba_B], ppm);
00448         }
00449     }
00450 
00451     delete[] buffer;
00452     return(fclose(ppm));
00453 }
00454 
00455 static Int ppmReadInt(FILE *ppm)
00456 {
00457     Int result, c;
00458 
00459     // chomp space & comments
00460     c = fgetc(ppm);
00461 
00462     while(isspace(c) || c == '#')
00463     {
00464         if (c == '#')
00465             do              
00466                 c = fgetc(ppm);
00467             while (c != '\n' && c != '\r' && c != EOF);
00468         
00469         c = fgetc(ppm);
00470     }
00471 
00472     ungetc(c, ppm);
00473     fscanf(ppm, "%d", &result);
00474 
00475     return(result); 
00476 }
00477 
00478 Int Image::LoadPPM(const Char *filename)
00479 {
00480     Int         i, j;
00481     Int         x, y, level;
00482     Char        p1, p2;
00483     Bool        isMono;
00484     FILE        *ppm;
00485     RGBAPixel   *p, *buffer;
00486     Byte        *mp, *mBuffer;
00487     
00488     ppm = fopen(filename, "r");
00489     if (!ppm)
00490         return(-1);
00491 
00492     p1 = fgetc(ppm);
00493     p2 = fgetc(ppm);
00494 
00495     if (p1 != 'P' || p2 <= '1' || p2 > '6')
00496     {
00497         _Warning("(LoadPPM) not a PPM file");
00498         return(-1);
00499     }
00500 
00501     if (p2 < '2' || p2 == '4' || p2 > '6')
00502     {
00503         _Warning("(LoadPPM) Only handles PGM and PPM files");
00504         return(-1);
00505     }
00506 
00507     isMono = (p2 == '2' || p2 == '5');
00508     
00509     x = ppmReadInt(ppm);
00510     y = ppmReadInt(ppm);
00511     level = ppmReadInt(ppm);
00512 
00513     if (level != 255)
00514         _Warning("(LoadPPM) Ignoring scaling factor.");
00515     
00516     SetSize(x, y);
00517 
00518     if (fgetc(ppm) != '\n')
00519     {
00520         _Warning("(LoadPPM) Corrupt PPM file");
00521         return(-1);
00522     }
00523 
00524     if (isMono)
00525         mBuffer = new Byte[width];
00526     else
00527         buffer = new RGBAPixel[width];
00528 
00529     for (j = height - 1; j >= 0; j--)
00530     {
00531         if (p2 == '2')
00532             for (i = 0, mp = mBuffer; i < width; i++, mp++)
00533             {
00534                 Int     b;
00535 
00536                 fscanf(ppm, "%d", &b);
00537                 *mp = b;
00538             }
00539         else if (p2 == '3')
00540             for (i = 0, p = buffer; i < width; i++, p++)
00541             {
00542                 Int     b;
00543                 fscanf(ppm, "%d", &b);
00544                 p->ch[rgba_R] = b;
00545                 fscanf(ppm, "%d", &b);
00546                 p->ch[rgba_G] = b;
00547                 fscanf(ppm, "%d", &b);
00548                 p->ch[rgba_B] = b;
00549                 p->ch[rgba_A] = 255;
00550             }
00551         else if (p2 == '5')
00552             fread(mBuffer, 1, width, ppm);
00553         else if (p2 == '6')
00554             for (i = 0, p = buffer; i < width; i++, p++)
00555             {
00556                 // UUU #ifdef endianess here sometime
00557                 p->ch[rgba_R] = fgetc(ppm);
00558                 p->ch[rgba_G] = fgetc(ppm);
00559                 p->ch[rgba_B] = fgetc(ppm);
00560                 p->ch[rgba_A] = 255;
00561             }
00562 
00563         if (isMono)
00564             SetByteSpan(j, 0, width, mBuffer);
00565         else
00566             SetRGBASpan(j, 0, width, buffer);
00567     }
00568 
00569     if (isMono)
00570         delete[] mBuffer;
00571     else
00572         delete[] buffer;
00573 
00574     return(fclose(ppm));
00575 }
00576 
00577 
00578 // --- TIFF read/write --------------------------------------------------------
00579 
00580 
00581 #ifdef GCL_TIFF
00582 
00583 #include "tiffio.h"
00584 
00585 Int Image::SaveTIFF(const Char *filename)
00586 {
00587     TIFF    *tif;
00588     UInt32  samples_per_pixel = 3;
00589     UInt32  w = Width();
00590     UInt32  h = Height();
00591     UInt32  scanline_size = samples_per_pixel * w;
00592     UInt32  i, k;
00593     Int     y;
00594     Char    *scanline_buf;
00595     RGBAPixel *rgba_buf;
00596 
00597     tif = TIFFOpen(filename, "w");
00598     if (!tif)
00599         return(-1);
00600 
00601     TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, w);
00602     TIFFSetField(tif, TIFFTAG_IMAGELENGTH, h);
00603 
00604     /* These are the charateristics of our Pic data */
00605     TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_LEFTTOP);
00606     TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, samples_per_pixel);
00607     TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
00608     TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
00609     TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
00610 #ifdef GCL_PATENTS_SUCK
00611     // use PKZIP compression to escape the pitiful unisys nonsense.
00612     // currently, RH 6.2's tiff libs print a pissy little message
00613     // LZW and don't use it, but they haven't enabled support
00614     // for deflate compression. I suppose that would have just
00615     // been too bright of them. If you want compressed images,
00616     // you'll have to rebuild with either LZW reenabled, or deflate
00617     // enabled.
00618     TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE);    
00619 #else
00620     TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
00621 #endif
00622     
00623     if( TIFFScanlineSize(tif) != scanline_size )
00624     {
00625         fprintf(stderr,
00626             "TIFF: Mismatch with library's expected scanline size!\n");
00627         return(-1);
00628     }
00629     
00630     TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, 0));
00631 
00632     scanline_buf = new Char[scanline_size];
00633     rgba_buf = new RGBAPixel[scanline_size];
00634 
00635     if (!scanline_buf)
00636     {
00637         fprintf(stderr, "TIFF: Can't allocate scanline buffer!\n");
00638         return(-1);
00639     }
00640     
00641     for (y = h - 1; y >= 0; y--)
00642     {
00643         GetRGBASpan(y, 0, w, rgba_buf);
00644         k = 0;
00645         for (i = 0; i < w; i++)
00646         {
00647             scanline_buf[k++] = rgba_buf[i].ch[rgba_R];
00648             scanline_buf[k++] = rgba_buf[i].ch[rgba_G];
00649             scanline_buf[k++] = rgba_buf[i].ch[rgba_B];
00650         }
00651         
00652         TIFFWriteScanline(tif, scanline_buf, h - y - 1, 0);
00653         /* note that TIFFWriteScanline modifies the buffer you pass it */
00654     }
00655 
00656     delete[] scanline_buf;
00657     delete[] rgba_buf;
00658     TIFFClose(tif);
00659 
00660     return(0);
00661 }
00662 
00663 Int Image::LoadTIFF(const Char *filename)
00664 {
00665     TIFF            *tif;
00666     TIFFRGBAImage   img;
00667     Int             result = -1;
00668     Char            emsg[1024];
00669     
00670     tif = TIFFOpen(filename, "r");
00671     if (!tif)
00672     {
00673         _Warning("(LoadTIFF) Couldn't find file.");
00674         return(-1);
00675     }
00676 
00677     if (TIFFRGBAImageBegin(&img, tif, 0, emsg)) 
00678     {
00679         SetSize(img.width, img.height);
00680 
00681 #ifdef GCL_BIG_END
00682         // TIFF unpacks data in AGBR format, which is endian dependent.
00683         // If we're on big-end machines, it matches with our format,
00684         // and we can write the data straight in, otherwise we have to
00685         // convert.
00686         if (Tag() == imgRGBATag)
00687             TIFFRGBAImageGet(&img, ((RGBAImage*) this)->Data(), 
00688                              img.width, img.height); 
00689         else
00690         {
00691 #endif
00692             Int     npixels = img.width * img.height;
00693             UInt32  *raster = 
00694                 (UInt32*) _TIFFmalloc(npixels * sizeof (UInt32));
00695 
00696             // should use TIFF put methods here, but they're too poorly
00697             // documented to waste time on just at the mo'
00698             if (raster) 
00699             {
00700                 if (TIFFRGBAImageGet(&img, (uint32*) raster, img.width, img.height)) 
00701                 {
00702                     Int         i, j;
00703                     RGBAPixel   *rgbaBuf = new RGBAPixel[img.width];
00704 
00705                     if (rgbaBuf)
00706                         for (i = 0; i < img.height; i++)
00707                         {
00708                             for (j = 0; j < img.width; j++)
00709                             {
00710                                 UInt32  pixel = raster[i * img.width + j];
00711 
00712                                 rgbaBuf[j].ch[rgba_R] = TIFFGetR(pixel);
00713                                 rgbaBuf[j].ch[rgba_G] = TIFFGetG(pixel);
00714                                 rgbaBuf[j].ch[rgba_B] = TIFFGetB(pixel);
00715                                 rgbaBuf[j].ch[rgba_A] = TIFFGetA(pixel);
00716                             }
00717                             SetRGBASpan(i, 0, img.width, rgbaBuf);
00718                         }
00719 
00720                     delete[] rgbaBuf;
00721                 }
00722                 else
00723                 {
00724                     _Warning("(LoadTIFF) TIFFRGBAImageGet failed");
00725                     return(-1);
00726                 }
00727                 _TIFFfree(raster);
00728             }
00729             else
00730             {
00731                 _Warning("(LoadTIFF) couldn't allocate raster data");
00732                 return(-1);
00733             }
00734 
00735 #ifdef GCL_BIG_END
00736         }
00737 #endif
00738 
00739         TIFFRGBAImageEnd(&img);
00740         result = 0;
00741     } 
00742     else
00743         TIFFError("(LoadTIFF)", emsg);
00744 
00745 
00746     TIFFClose(tif);
00747 
00748     return(result);
00749 }
00750 
00751 #ifdef UNFINISHED
00752 
00753 // code for ward's clever scaling scheme
00754 
00755 To a standard TIFF writer, one needs to add the following code fragment 
00756 to the initialization routine to set up for sending XYZ data:
00757 
00758 Int Image::SaveTIFF_LogLUV(const Char *filename, Float stonits)
00759 {
00760     TIFF    *tif;
00761     UInt32  samples_per_pixel = 3;
00762     UInt32  w = Width();
00763     UInt32  h = Height();
00764     UInt32  scanline_size = samples_per_pixel * w;
00765     UInt32  y, i, k;
00766     Char    *scanline_buf;
00767     RGBAPixel *rgba_buf;
00768 
00769     tif = TIFFOpen(filename, "w");
00770     if (!tif)
00771         return(-1);
00772 
00773     TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, w);
00774     TIFFSetField(tif, TIFFTAG_IMAGELENGTH, h);
00775 
00776     /* These are the charateristics of our Pic data */
00777     TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_LEFTTOP);
00778     TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, samples_per_pixel);
00779     TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
00780 //    TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
00781 //    TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
00782 //    TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
00783 //    TIFFSetField(tif, TIFFTAG_PREDICTOR, 2);
00784     
00785     // set up for LUV output...
00786     TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_SGILOG);
00787     TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_LOGLUV);
00788     TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
00789     TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_FLOAT);
00790     TIFFSetField(tif, TIFFTAG_STONITS, stonits);
00791 
00792     if( TIFFScanlineSize(tif) != scanline_size )
00793     {
00794         _Warning("TIFF: Mismatch with library's expected scanline size!\n");
00795         return(-1);
00796     }
00797     
00798     TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, 0));
00799 
00800     scanline_buf = new Char[scanline_size];
00801     rgba_buf = new RGBAPixel[scanline_size];
00802 
00803     if (!scanline_buf)
00804     {
00805         Warning("TIFF: Can't allocate scanline buffer!\n");
00806         return(-1);
00807     }
00808     
00809     for(y = h - 1; y >= 0; y--)
00810     {
00811         GetRGBASpan(y, 0, w, rgba_buf);
00812         k = 0;
00813         for (i = 0; i < w; i++)
00814         {
00815             scanline_buf[k++] = rgba_buf[i].ch[rgba_R];
00816             scanline_buf[k++] = rgba_buf[i].ch[rgba_G];
00817             scanline_buf[k++] = rgba_buf[i].ch[rgba_B];
00818         }
00819         
00820         TIFFWriteScanline(tif, scanline_buf, y, 0);
00821         /* note that TIFFWriteScanline modifies the buffer you pass it */
00822     }
00823     delete[] scanline_buf;
00824     delete[] rgba_buf;
00825     TIFFClose(tif);
00826     return(0);
00827 }
00828 
00829 #endif
00830 #endif
00831 
00832 
00833 // --- GIF read/write --------------------------------------------------------
00834 
00835 #ifdef GCL_GIF
00836 
00837 // Bog off, UNISYS
00838 
00839 extern "C"
00840 {
00841 #include "gif_lib.h"
00842 }
00843 
00844 // why on earth isn't this handled by DGifSlurp? 
00845 // and why does that code assume char is unsigned? 
00846 static Int tInterlacedOffset[] = { 0, 4, 2, 1 };
00847 static Int tInterlacedJump[] = { 8, 8, 4, 2 };
00848 
00849 Int Image::SaveGIF(const Char *filename)
00850 {
00851     return(-1);
00852 }
00853 
00854 Int Image::LoadGIF(const Char *filename)
00855 {
00856     GifFileType     *gifFile;
00857     SavedImage      *theGIFImg;
00858     ColorMapObject  *clrMap;
00859     RGBAPixel       *buffer;
00860     Int             i, j, result = -1;
00861     Int             pass, destRow, destStep;
00862     
00863     gifFile = DGifOpenFileName(filename);   
00864     if (gifFile)
00865     {
00866         if (DGifSlurp(gifFile) == GIF_OK)
00867         {
00868             buffer = new RGBAPixel[gifFile->SWidth];
00869 
00870             theGIFImg = gifFile->SavedImages;   // first image
00871             
00872             SetSize(theGIFImg->ImageDesc.Width, theGIFImg->ImageDesc.Height);
00873 
00874             if (theGIFImg->ImageDesc.ColorMap)
00875                 clrMap = theGIFImg->ImageDesc.ColorMap;
00876             else if (gifFile->SColorMap)
00877                 clrMap = gifFile->SColorMap;
00878             else
00879             {
00880                 _Warning("GIF file contains no colormap!");
00881                 return(-1);
00882             }
00883             
00884             if (theGIFImg->ImageDesc.Interlace)
00885             {
00886                 destRow = tInterlacedOffset[0];
00887                 destStep = tInterlacedJump[0];
00888                 pass = 0;
00889             }
00890             else
00891             {
00892                 destRow = 0;
00893                 destStep = 1;
00894             }
00895                 
00896             for (i = 0; i < theGIFImg->ImageDesc.Height; i++)
00897             {
00898                 Byte *sp = (Byte*) theGIFImg->RasterBits + i * theGIFImg->ImageDesc.Width;
00899 
00900                 for (j = 0; j < theGIFImg->ImageDesc.Width; j++)
00901                 {
00902                     Byte idx = *sp++;
00903 
00904                     buffer[j].ch[rgba_R] = clrMap->Colors[idx].Red;
00905                     buffer[j].ch[rgba_G] = clrMap->Colors[idx].Green;
00906                     buffer[j].ch[rgba_B] = clrMap->Colors[idx].Blue;
00907                     buffer[j].ch[rgba_A] = 255;
00908                 }
00909                 
00910                 SetRGBASpan(height - 1 - destRow, 0, theGIFImg->ImageDesc.Width, buffer);
00911                 destRow += destStep;
00912                 if (destRow >= height && theGIFImg->ImageDesc.Interlace)
00913                 {
00914                     pass++;
00915                     Assert(pass < 4, "Too many passes in GIF file");
00916                     destRow = tInterlacedOffset[pass];
00917                     destStep = tInterlacedJump[pass];
00918                 }
00919             }
00920             
00921             delete[] buffer;
00922             result = 0;
00923         }
00924         else
00925             PrintGifError();
00926 
00927         if (DGifCloseFile(gifFile) != GIF_OK)
00928             PrintGifError();
00929     }
00930     else
00931         PrintGifError();
00932 
00933     return(result);
00934 }
00935 
00936 #endif
00937 
00938 
00939 // --- JPEG read/write --------------------------------------------------------
00940 
00941 #ifdef GCL_JPEG
00942 
00943 extern "C"
00944 {
00945 #include "jpeglib.h"
00946 }
00947 
00948 Int Image::SaveJPEG(const Char *filename)
00949 {
00950     FILE                        *outfile;
00951     JSAMPROW                    rowPtr[1];
00952     struct jpeg_compress_struct compressObj;
00953     struct jpeg_error_mgr       jerr;
00954     JSAMPLE                     *scanlineBuf, *p;
00955     Int                         i, j;
00956     
00957     compressObj.err = jpeg_std_error(&jerr);
00958     jpeg_create_compress(&compressObj);
00959 
00960     //  Set up file for output... 
00961 
00962     if ((outfile = fopen(filename, "wb")) == NULL)
00963     {
00964         _Warning("(Image::SaveJPEG) can't open for writing: " + StrConst(filename));
00965         return(-1);
00966     }
00967     
00968     jpeg_stdio_dest(&compressObj, outfile);
00969 
00970     compressObj.image_width = width;
00971     compressObj.image_height = height;
00972     compressObj.input_components = 3;
00973     compressObj.in_color_space = JCS_RGB;
00974 
00975     jpeg_set_defaults(&compressObj);
00976     jpeg_set_quality(&compressObj, sJPEGQuality, TRUE);
00977 
00978     // Set up scanlines 
00979     
00980     scanlineBuf = new JSAMPLE[width * 3];
00981     if (!scanlineBuf)
00982         return(-1);
00983     rowPtr[0] = scanlineBuf;
00984     
00985     // Compress & save
00986 
00987     jpeg_start_compress(&compressObj, TRUE);
00988 
00989     for (i = height - 1; i >= 0; i--)
00990     {
00991         Colour  c;
00992 
00993         p = scanlineBuf;
00994         for (j = 0; j < width; j++)
00995         {
00996             c = GetPixel(j, i);
00997             *p++ = Byte(c[0] * 255.0);
00998             *p++ = Byte(c[1] * 255.0);
00999             *p++ = Byte(c[2] * 255.0);
01000         }
01001 
01002         jpeg_write_scanlines(&compressObj, rowPtr, 1);
01003     }
01004 
01005     jpeg_finish_compress(&compressObj);
01006     fclose(outfile);
01007     delete[] scanlineBuf;
01008 }
01009 
01010 Int Image::LoadJPEG(const Char *filename)
01011 {
01012     struct jpeg_decompress_struct   cinfo;
01013     struct jpeg_error_mgr           jerr;
01014     JSAMPROW                        buffer;
01015     FILE                            *file;
01016     RGBAPixel                       *rgba_buf;
01017     Int                             i, j, k, err = -1;
01018 
01019     cinfo.err = jpeg_std_error(&jerr);
01020     jpeg_create_decompress(&cinfo);
01021 
01022     file = fopen(filename, "rb");
01023     if (!file) 
01024     {
01025         fprintf(stderr, "JPEG: could not open file \"%s\"\n", filename);
01026         return(err);
01027     }
01028 
01029     jpeg_stdio_src(&cinfo, file);
01030     jpeg_read_header(&cinfo, TRUE);
01031 
01032     // decompress options
01033     cinfo.out_color_space = JCS_RGB;
01034     cinfo.quantize_colors = FALSE;
01035     cinfo.do_fancy_upsampling = FALSE;
01036     cinfo.do_block_smoothing = FALSE;
01037 
01038     jpeg_start_decompress(&cinfo);
01039 
01040     SetSize(cinfo.output_width, cinfo.output_height);
01041 
01042     // JSAMPLE better be a byte.
01043     Assert(sizeof(JSAMPLE) == 1, "JSAMPLE is not a byte");
01044     Assert(cinfo.output_components == 3, "JCS_RGB request failed");
01045     buffer = (JSAMPROW) new Byte[cinfo.output_width * cinfo.output_components];
01046     rgba_buf = new RGBAPixel[cinfo.output_width];
01047 
01048     if (!buffer || !rgba_buf) 
01049     {
01050         delete[] buffer; delete[] rgba_buf;
01051         fprintf(stderr, "JPEG: out of memory\n");
01052         goto bye;
01053     }
01054     
01055     k = cinfo.output_height;
01056 
01057     while (cinfo.output_scanline < cinfo.output_height) 
01058     {
01059         jpeg_read_scanlines(&cinfo, &buffer, 1);
01060 
01061         for (i = 0, j = 0; i < cinfo.output_width; i++) 
01062         {
01063             rgba_buf[i].ch[rgba_R] = buffer[j++];
01064             rgba_buf[i].ch[rgba_G] = buffer[j++];
01065             rgba_buf[i].ch[rgba_B] = buffer[j++];           
01066             rgba_buf[i].ch[rgba_A] = 255;           
01067         }
01068         SetRGBASpan(--k, 0, cinfo.output_width, rgba_buf);
01069     }
01070 
01071     jpeg_finish_decompress(&cinfo);
01072     err = 0;
01073     delete[] buffer; 
01074     delete[] rgba_buf;
01075 
01076 bye:
01077     jpeg_destroy_decompress(&cinfo);
01078 
01079     fclose(file);
01080     return(err);
01081 }
01082 
01083 #endif
01084 
01085 
01086 // --- RGBAImage methods ------------------------------------------------------
01087 
01088 Void RGBAImage::SetSize(Int width, Int height)
01089 {
01090     delete[] data;
01091     data = new RGBAPixel[width * height];
01092     SELF.width = width;
01093     SELF.height = height;
01094 }
01095 
01096 Void RGBAImage::Clear(const Colour &c)
01097 {
01098     RGBAPixel   *p = data, bc = ColourToRGBA(c);
01099     Int         i;
01100 
01101     for (i = 0; i < width * height; i++, p++)
01102         *p = bc;
01103 }
01104 
01105 Void RGBAImage::SetPixel(Int x, Int y, const Colour &c)
01106 {
01107     Assert(x >= 0 && y >= 0 && x < width && y < height,
01108            "illegal pixel access.");
01109     data[x + y * width] = ColourToRGBA(c);
01110 }
01111 
01112 Colour RGBAImage::GetPixel(Int x, Int y) const
01113 {
01114     Assert(x >= 0 && y >= 0 && x < width && y < height,
01115            "illegal pixel access.");
01116     return(RGBAToColour(data[x + y * width]));
01117 }
01118 
01119 Void RGBAImage::SetSpan(Int row, Int start, Int length, const Colour *src)
01120 {
01121     Assert(row >= 0 && row < height && start >= 0 && start + length <= width,
01122            "(RGBAImage::SetSpan) illegal span access.");
01123     Int             i;
01124     RGBAPixel       *p = data + row * width + start;
01125     const Colour    *cp = src;
01126     
01127     for (i = 0; i < length; i++, p++, cp++)
01128         *p = ColourToRGBA(*cp);
01129 }
01130 
01131 Void RGBAImage::GetSpan(Int row, Int start, Int length, Colour *dst) const
01132 {
01133     Assert(row >= 0 && row < height && start >= 0 && start + length <= width,
01134            "(RGBAImage::GetSpan) illegal span access.");
01135     Int         i;
01136     RGBAPixel   *p = data + row * width + start;
01137     Colour      *cp = dst;
01138     
01139     for (i = 0; i < length; i++, p++, cp++)
01140         *cp = RGBAToColour(*p);
01141 }
01142 
01143 Void RGBAImage::SetRGBASpan(Int row, Int start, Int length, 
01144                             const RGBAPixel *src) 
01145 {
01146     Assert(row >= 0 && row < height && start >= 0 && start + length <= width,
01147            "(RGBAImage::SetRGBASpan) illegal span access.");
01148 
01149     memcpy(data + row * width + start, src, length * sizeof(RGBAPixel));
01150 }
01151 
01152 Void RGBAImage::GetRGBASpan(Int row, Int start, Int length,
01153                             RGBAPixel *dst) const
01154 {
01155     Assert(row >= 0 && row < height && start >= 0 && start + length <= width,
01156            "(RGBAImage::GetRGBASpan) illegal span access.");
01157 
01158     memcpy(dst, data + row * width + start, length * sizeof(RGBAPixel));
01159 }
01160 
01161 
01162 // --- ByteImage methods ------------------------------------------------------
01163 
01164 Void ByteImage::SetSize(Int width, Int height)
01165 {
01166     delete[] data;
01167     data = new Byte[width * height];
01168     SELF.width = width;
01169     SELF.height = height;
01170 }
01171 
01172 Void ByteImage::Clear(const Colour &c)
01173 {
01174     Byte    *p = data, bc = ColourToByte(c);
01175     Int         i;
01176 
01177     for (i = 0; i < width * height; i++, p++)
01178         *p = bc;
01179 }
01180 
01181 Void ByteImage::SetPixel(Int x, Int y, const Colour &c)
01182 {
01183     Assert(x >= 0 && y >= 0 && x < width && y < height,
01184            "illegal pixel access.");
01185     data[x + y * width] = ColourToByte(c);
01186 }
01187 
01188 Colour ByteImage::GetPixel(Int x, Int y) const
01189 {
01190     Assert(x >= 0 && y >= 0 && x < width && y < height, 
01191            "illegal pixel access.");
01192     return(ByteToColour(data[x + y * width]));
01193 }
01194 
01195 Void ByteImage::SetRealPixel(Int x, Int y, ClrReal r, ImgChannel ch)
01196 {
01197     Assert(x >= 0 && y >= 0 && x < width && y < height, 
01198            "illegal pixel access.");
01199     if (ch <= chBlue)
01200         data[x + y * width] = (Byte) (r * 255.0);
01201 }
01202 
01203 
01204 ClrReal ByteImage::GetRealPixel(Int x, Int y, ImgChannel ch) const
01205 {
01206     Assert(x >= 0 && y >= 0 && x < width && y < height, 
01207            "illegal pixel access.");
01208 
01209     if (ch <= chBlue)
01210         return(data[x + y * width] / 255.0);
01211     else
01212         return(0.0);
01213 }
01214 
01215 Void ByteImage::SetSpan(Int row, Int start, Int length, const Colour *src)
01216 {
01217     Assert(row >= 0 && row < height && start >= 0 && start + length <= width,
01218            "(ByteImage::SetSpan) illegal span access.");
01219     Int             i;
01220     Byte            *p = data + row * width + start;
01221     const Colour    *cp = src;
01222     
01223     for (i = 0; i < length; i++, p++, cp++)
01224         *p = ColourToByte(*cp);
01225 }
01226 
01227 Void ByteImage::GetSpan(Int row, Int start, Int length, Colour *dst) const
01228 {
01229     Assert(row >= 0 && row < height && start >= 0 && start + length <= width,
01230            "(ByteImage::GetSpan) illegal span access.");
01231     Int         i;
01232     Byte        *p = data + row * width + start;
01233     Colour      *cp = dst;
01234     
01235     for (i = 0; i < length; i++, p++, cp++)
01236         *cp = ByteToColour(*p);
01237 }
01238 
01239 Void ByteImage::SetByteSpan(Int row, Int start, Int length, 
01240                             const Byte *src, ImgChannel channel) 
01241 {
01242     Assert(row >= 0 && row < height && start >= 0 && start + length <= width,
01243            "(ByteImage::SetByteSpan) illegal span access.");
01244 
01245     memcpy(data + row * width + start, src, length);
01246 }
01247 
01248 Void ByteImage::GetByteSpan(Int row, Int start, Int length,
01249                             Byte *dst, ImgChannel channel) const
01250 {
01251     Assert(row >= 0 && row < height && start >= 0 && start + length <= width,
01252            "(ByteImage::GetByteSpan) illegal span access.");
01253 
01254     memcpy(dst, data + row * width + start, length);
01255 }
01256 
01257 
01258 // --- RGBEImage methods ------------------------------------------------------
01259 
01260 Void RGBEImage::SetSize(Int width, Int height)
01261 {
01262     delete[] data;
01263     data = new RGBEPixel[width * height];
01264     SELF.width = width;
01265     SELF.height = height;
01266 }
01267 
01268 Void RGBEImage::Clear(const Colour &c)
01269 {
01270     RGBEPixel   *p = data, bc = ColourToRGBE(c);
01271     Int         i;
01272 
01273     for (i = 0; i < width * height; i++, p++)
01274         *p = bc;
01275 }
01276 
01277 Void RGBEImage::SetPixel(Int x, Int y, const Colour &c)
01278 {
01279     Assert(x >= 0 && y >= 0 && x < width && y < height,
01280            "illegal pixel access.");
01281     data[x + y * width] = ColourToRGBE(c);
01282 }
01283 
01284 Colour RGBEImage::GetPixel(Int x, Int y) const
01285 {
01286     Assert(x >= 0 && y >= 0 && x < width && y < height,
01287            "illegal pixel access.");
01288     return(RGBEToColour(data[x + y * width]));
01289 }
01290 
01291 Void RGBEImage::SetSpan(Int row, Int start, Int length, const Colour *src)
01292 {
01293     Assert(row >= 0 && row < height && start >= 0 && start + length <= width,
01294            "(RGBEImage::SetSpan) illegal span access.");
01295     Int             i;
01296     RGBEPixel       *p = data + row * width + start;
01297     const Colour    *cp = src;
01298     
01299     for (i = 0; i < length; i++, p++, cp++)
01300         *p = ColourToRGBE(*cp);
01301 }
01302 
01303 Void RGBEImage::GetSpan(Int row, Int start, Int length, Colour *dst) const
01304 {
01305     Assert(row >= 0 && row < height && start >= 0 && start + length <= width,
01306            "(RGBEImage::GetSpan) illegal span access.");
01307     Int         i;
01308     RGBEPixel   *p = data + row * width + start;
01309     Colour      *cp = dst;
01310     
01311     for (i = 0; i < length; i++, p++, cp++)
01312         *cp = RGBEToColour(*p);
01313 }
01314 
01315 const Int kRGBE_Excess = 128;
01316 
01317 Colour RGBEToColour(RGBEPixel rgbe)
01318 {
01319     Colour  result;
01320     Double  f;
01321     
01322     if (rgbe.ch[3] == 0)
01323         return(cBlack);
01324 
01325     f = ldexp(1.0, (Int) rgbe.ch[3] - (kRGBE_Excess + 8));
01326 
01327     result[0] = f * (rgbe.ch[0] + 0.5);
01328     result[1] = f * (rgbe.ch[1] + 0.5);
01329     result[2] = f * (rgbe.ch[2] + 0.5);
01330 
01331     return(result); 
01332 }
01333 
01334 RGBEPixel ColourToRGBE(const Colour &c)
01335 {
01336     RGBEPixel   result;
01337     Int         e;
01338     Double      d;
01339     
01340     d = MaxCmpt(c);
01341     if (d <= 1e-32)
01342     {
01343         *((UInt32*) result.ch) = 0;
01344     }
01345     else
01346     {
01347         d = frexp(d, &e) * 256.0 / d;
01348         
01349         result.ch[0] = (Byte) (c[0] * d);
01350         result.ch[1] = (Byte) (c[1] * d);
01351         result.ch[2] = (Byte) (c[2] * d);
01352         result.ch[3] = e + kRGBE_Excess;
01353     }
01354     
01355     return(result); 
01356 }
01357 
01358 RGBEPixel RGBEMult(RGBEPixel rgbe, Double s)
01359 {
01360     Colour      temp;
01361     Double      d, f;
01362     Int         e;
01363     RGBEPixel   result;
01364     
01365     *((UInt32*) result.ch) = 0;
01366 
01367     if (rgbe.ch[3] == 0)
01368         return(result);
01369 
01370     f = ldexp(1.0, (Int) rgbe.ch[3] - (kRGBE_Excess + 8));
01371 
01372     temp[0] = f * (rgbe.ch[0] + 0.5);
01373     temp[1] = f * (rgbe.ch[1] + 0.5);
01374     temp[2] = f * (rgbe.ch[2] + 0.5);
01375 
01376     d = MaxCmpt(temp);
01377     if (d <= 1e-32)
01378         return(result);
01379     else
01380     {
01381         d = frexp(d, &e) * 256.0 / d;
01382         
01383         result.ch[0] = (Byte) (temp[0] * d);
01384         result.ch[1] = (Byte) (temp[1] * d);
01385         result.ch[2] = (Byte) (temp[2] * d);
01386         result.ch[3] = e + kRGBE_Excess;
01387     }
01388 
01389     return(result); 
01390 }
01391 
01392 
01393 // --- ChannelImage methods ---------------------------------------------------
01394 
01395 #ifdef UNFINISHED
01396 
01397 ChannelImage::ChannelImage() : tag(imgChannelTag) {}
01398 {
01399 }
01400 #endif
01401 
01402 
01403 Int RGBEImage::SavePIC(const Char *filename)
01404 {
01405     Int         i, j;
01406     FILE        *pic;
01407     RGBEPixel   *p, *buffer = new RGBEPixel[width];
01408 
01409     if (!buffer)
01410         return(-1);
01411     pic = fopen(filename, "w");
01412     if (!pic)
01413         return(-1);
01414     
01415     fprintf(pic, "#?RADIANCE\n");
01416     fprintf(pic, "gcl_out\n");
01417     fprintf(pic, "FORMAT=32-bit_rle_rgbe\n");
01418     fprintf(pic, "\n");
01419     fprintf(pic, "-Y %d +X %d\n", width, height);
01420 
01421     for (j = height - 1; j >= 0; j--)
01422     {
01423         p = data + j * width;
01424         // convert to radiance
01425         for (i = 0; i < width; i++)
01426             buffer[i] = RGBEMult(p[i], 1.0 / 179.0);
01427         fwrite(buffer, sizeof(RGBEPixel), width, pic);
01428     }
01429 
01430     delete[] buffer;
01431     
01432     return(fclose(pic));
01433 }
01434 
01435 Int RGBEImage::LoadPIC(const Char *filename)
01436 {
01437     Int         i, j;
01438     Int         x, y, level;
01439     FILE        *pic;
01440     RGBEPixel   *p, *buffer;
01441     
01442     pic = fopen(filename, "r");
01443     if (!pic)
01444         return(-1);
01445 
01446     if (fscanf(pic, 
01447             "#?RADIANCE\n"
01448             "gcl_out\n"
01449             "FORMAT=32-bit_rle_rgbe\n\n"
01450             "-Y %d +X %d\n", &x, &y) != 2)
01451     {
01452         _Warning("Couldn't read pic file: bad format/not gcl_out\n");
01453         fclose(pic);
01454         return(-1);
01455     }
01456 
01457     SetSize(x, y);
01458 
01459     for (j = height - 1; j >= 0; j--)
01460     {
01461         p = data + j * width;
01462         fread(p, sizeof(RGBEPixel), width, pic);
01463     }
01464     
01465     return(fclose(pic));
01466 }

Generated at Sat Aug 5 00:17:00 2000 for Graphics Class Library by doxygen 1.1.0 written by Dimitri van Heesch, © 1997-2000