- Main Page
- Data Structures
- Files

- File List

# E:/DevIL/src-IL/src/il_jp2.c

    00001 //-----------------------------------------------------------------------------
    00002 //
    00003 // ImageLib Sources
    00004 // Copyright (C) 2000-2009 by Denton Woods
    00005 // Last modified: 01/15/2009
    00006 //
    00007 // Filename: src-IL/src/il_jp2.c
    00008 //
    00009 // Description: Jpeg-2000 (.jp2) functions
    00010 //
    00011 //-----------------------------------------------------------------------------
    00012
    00013
    00014 #include "il_internal.h"
    00015 #ifndef IL_NO_JP2
    00016 #include <jasper/jasper.h>
    00017 #include "il_jp2.h"
    00018
    00019 #if defined(_WIN32) && defined(IL_USE_PRAGMA_LIBS)
    00020         #if defined(_MSC_VER) || defined(__BORLANDC__)
    00021                 #ifndef _DEBUG
    00022                         #pragma comment(lib, "libjasper.lib")
    00023                 #else
    00024                         #pragma comment(lib, "libjasper-d.lib")
    00025                 #endif
    00026         #endif
    00027 #endif
    00028
    00029 ILboolean iIsValidJp2(void);
    00030
    00031 ILboolean JasperInit = IL_FALSE;
    00032
    00033
    00035 ILboolean ilIsValidJp2(ILconst_string FileName)
    00036 {
    00037         ILHANDLE        Jp2File;
    00038         ILboolean       bJp2 = IL_FALSE;
    00039
    00040         if (!iCheckExtension(FileName, IL_TEXT("jp2"))) {
    00041                 ilSetError(IL_INVALID_EXTENSION);
    00042                 return bJp2;
    00043         }
    00044
    00045         Jp2File = iopenr(FileName);
    00046         if (Jp2File == NULL) {
    00047                 ilSetError(IL_COULD_NOT_OPEN_FILE);
    00048                 return bJp2;
    00049         }
    00050
    00051         bJp2 = ilIsValidJp2F(Jp2File);
    00052         icloser(Jp2File);
    00053
    00054         return bJp2;
    00055 }
    00056
    00057
    00059 ILboolean ilIsValidJp2F(ILHANDLE File)
    00060 {
    00061         ILuint          FirstPos;
    00062         ILboolean       bRet;
    00063
    00064         iSetInputFile(File);
    00065         FirstPos = itell();
    00066         bRet = iIsValidJp2();
    00067         iseek(FirstPos, IL_SEEK_SET);
    00068
    00069         return bRet;
    00070 }
    00071
    00072
    00074 ILboolean ilIsValidJp2L(const void *Lump, ILuint Size)
    00075 {
    00076         iSetInputLump(Lump, Size);
    00077         return iIsValidJp2();
    00078 }
    00079
    00080
    00081 // Internal function to get the header and check it.
    00082 ILboolean iIsValidJp2(void)
    00083 {
    00084         ILubyte Signature[4];
    00085
    00086         iseek(4, IL_SEEK_CUR);  // Skip the 4 bytes that tell the size of the signature box.
    00087         if (iread(Signature, 1, 4) != 4) {
    00088                 iseek(-4, IL_SEEK_CUR);
    00089                 return IL_FALSE;  // File read error
    00090         }
    00091
    00092         iseek(-8, IL_SEEK_CUR);  // Restore to previous state
    00093
    00094         // Signature is 'jP\040\040' by the specs (or 0x6A502020).
    00095         //  http://www.jpeg.org/public/fcd15444-6.pdf
    00096         if (Signature[0] != 0x6A || Signature[1] != 0x50 ||
    00097                 Signature[2] != 0x20 || Signature[3] != 0x20)
    00098                 return IL_FALSE;
    00099
    00100         return IL_TRUE;
    00101 }
    00102
    00103
    00105 ILboolean ilLoadJp2(ILconst_string FileName)
    00106 {
    00107         ILHANDLE        Jp2File;
    00108         ILboolean       bRet;
    00109
    00110         Jp2File = iopenr(FileName);
    00111         if (Jp2File == NULL) {
    00112                 ilSetError(IL_COULD_NOT_OPEN_FILE);
    00113                 return IL_FALSE;
    00114         }
    00115
    00116         bRet = ilLoadJp2F(Jp2File);
    00117         icloser(Jp2File);
    00118
    00119         return bRet;
    00120 }
    00121
    00122
    00124 ILboolean ilLoadJp2F(ILHANDLE File)
    00125 {
    00126         ILuint                  FirstPos;
    00127         ILboolean               bRet;
    00128         jas_stream_t    *Stream;
    00129
    00130         iSetInputFile(File);
    00131         FirstPos = itell();
    00132
    00133         if (!JasperInit) {
    00134                 if (jas_init()) {
    00135                         ilSetError(IL_LIB_JP2_ERROR);
    00136                         return IL_FALSE;
    00137                 }
    00138                 JasperInit = IL_TRUE;
    00139         }
    00140         Stream = iJp2ReadStream();
    00141         if (!Stream)
    00142         {
    00143                 ilSetError(IL_COULD_NOT_OPEN_FILE);
    00144                 return IL_FALSE;
    00145         }
    00146
    00147         bRet = iLoadJp2Internal(Stream, NULL);
    00148         // Close the input stream.
    00149         jas_stream_close(Stream);
    00150
    00151         iseek(FirstPos, IL_SEEK_SET);
    00152
    00153         return bRet;
    00154 }
    00155
    00156
    00158 ILboolean ilLoadJp2L(const void *Lump, ILuint Size)
    00159 {
    00160         return ilLoadJp2LInternal(Lump, Size, NULL);
    00161 }
    00162
    00163
    00165 ILboolean ilLoadJp2LInternal(const void *Lump, ILuint Size, ILimage *Image)
    00166 {
    00167         ILboolean               bRet;
    00168         jas_stream_t    *Stream;
    00169
    00170         if (!JasperInit) {
    00171                 if (jas_init()) {
    00172                         ilSetError(IL_LIB_JP2_ERROR);
    00173                         return IL_FALSE;
    00174                 }
    00175                 JasperInit = IL_TRUE;
    00176         }
    00177         Stream = jas_stream_memopen((char*)Lump, Size);
    00178         if (!Stream)
    00179         {
    00180                 ilSetError(IL_COULD_NOT_OPEN_FILE);
    00181                 return IL_FALSE;
    00182         }
    00183
    00184         bRet = iLoadJp2Internal(Stream, Image);
    00185         // Close the input stream.
    00186         jas_stream_close(Stream);
    00187
    00188         return bRet;
    00189 }
    00190
    00191
    00192 // Internal function used to load the Jpeg2000 stream.
    00193 ILboolean iLoadJp2Internal(jas_stream_t *Stream, ILimage *Image)
    00194 {
    00195         jas_image_t             *Jp2Image = NULL;
    00196         jas_matrix_t    *origdata;
    00197         ILuint                  x, y, c, Error;
    00198         ILimage                 *TempImage;
    00199
    00200         // Decode image
    00201         Jp2Image = jas_image_decode(Stream, -1, 0);
    00202         if (!Jp2Image)
    00203         {
    00204                 ilSetError(IL_ILLEGAL_FILE_VALUE);
    00205                 jas_stream_close(Stream);
    00206                 return IL_FALSE;
    00207         }
    00208
    00209         // JasPer likes to buffer a lot, so it may try buffering past the end
    00210         //  of the file.  iread naturally sets IL_FILE_READ_ERROR if it tries
    00211         //  reading past the end of the file, but this actually is not an error.
    00212         Error = ilGetError();
    00213         // Put the error back if it is not IL_FILE_READ_ERROR.
    00214         if (Error != IL_FILE_READ_ERROR)
    00215                 ilSetError(Error);
    00216
    00217
    00218         // We're not supporting anything other than 8 bits/component yet.
    00219         if (jas_image_cmptprec(Jp2Image, 0) != 8)
    00220         {
    00221                 jas_image_destroy(Jp2Image);
    00222                 ilSetError(IL_ILLEGAL_FILE_VALUE);
    00223                 return IL_FALSE;
    00224         }
    00225
    00226         switch (jas_image_numcmpts(Jp2Image))
    00227         {
    00228                 //@TODO: Can we do alpha data?  jas_image_cmpttype always returns 0 for this case.
    00229                 case 1:  // Assuming this is luminance data.
    00230                         if (Image == NULL) {
    00231                                 ilTexImage(jas_image_width(Jp2Image), jas_image_height(Jp2Image), 1, 1, IL_LUMINANCE, IL_UNSIGNED_BYTE, NULL);
    00232                                 TempImage = iCurImage;
    00233                         }
    00234                         else {
    00235                                 ifree(Image->Data);  // @TODO: Not really the most efficient way to do this...
    00236                                 ilInitImage(Image, jas_image_width(Jp2Image), jas_image_height(Jp2Image), 1, 1, IL_LUMINANCE, IL_UNSIGNED_BYTE, NULL);
    00237                                 TempImage = Image;
    00238                         }
    00239                         break;
    00240
    00241                 case 2:  // Assuming this is luminance-alpha data.
    00242                         if (Image == NULL) {
    00243                                 ilTexImage(jas_image_width(Jp2Image), jas_image_height(Jp2Image), 1, 2, IL_LUMINANCE_ALPHA, IL_UNSIGNED_BYTE, NULL);
    00244                                 TempImage = iCurImage;
    00245                         }
    00246                         else {
    00247                                 ifree(Image->Data);  // @TODO: Not really the most efficient way to do this...
    00248                                 ilInitImage(Image, jas_image_width(Jp2Image), jas_image_height(Jp2Image), 1, 2, IL_LUMINANCE_ALPHA, IL_UNSIGNED_BYTE, NULL);
    00249                                 TempImage = Image;
    00250                         }
    00251                         break;
    00252
    00253                 case 3:
    00254                         if (Image == NULL) {
    00255                                 ilTexImage(jas_image_width(Jp2Image), jas_image_height(Jp2Image), 1, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL);
    00256                                 TempImage = iCurImage;
    00257                         }
    00258                         else {
    00259                                 ifree(Image->Data);  // @TODO: Not really the most efficient way to do this...
    00260                                 ilInitImage(Image, jas_image_width(Jp2Image), jas_image_height(Jp2Image), 1, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL);
    00261                                 TempImage = Image;
    00262                         }
    00263                         break;
    00264                 case 4:
    00265                         if (Image == NULL) {
    00266                                 ilTexImage(jas_image_width(Jp2Image), jas_image_height(Jp2Image), 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL);
    00267                                 TempImage = iCurImage;
    00268                         }
    00269                         else {
    00270                                 ifree(Image->Data);  // @TODO: Not really the most efficient way to do this...
    00271                                 ilInitImage(Image, jas_image_width(Jp2Image), jas_image_height(Jp2Image), 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL);
    00272                                 TempImage = Image;
    00273                         }
    00274                         break;
    00275                 default:
    00276                         jas_image_destroy(Jp2Image);
    00277                         ilSetError(IL_ILLEGAL_FILE_VALUE);
    00278                         return IL_FALSE;
    00279         }
    00280         TempImage->Origin = IL_ORIGIN_UPPER_LEFT;
    00281
    00282         // JasPer stores the data channels separately.
    00283         //  I am assuming RGBA format.  Is it possible for other formats to be included?
    00284         for (c = 0; c < TempImage->Bpp; c++)
    00285         {
    00286                 origdata = jas_matrix_create(TempImage->Height, TempImage->Width);
    00287                 if (!origdata)
    00288                 {
    00289                         ilSetError(IL_LIB_JP2_ERROR);
    00290                         return IL_FALSE;  // @TODO: Error
    00291                 }
    00292                 // Have to convert data into an intermediate matrix format.
    00293                 if (jas_image_readcmpt(Jp2Image, c, 0, 0, TempImage->Width, TempImage->Height, origdata))
    00294                 {
    00295                         return IL_FALSE;
    00296                 }
    00297
    00298                 for (y = 0; y < TempImage->Height; y++)
    00299                 {
    00300                         for (x = 0; x < TempImage->Width; x++)
    00301                         {
    00302                                 TempImage->Data[y * TempImage->Width * TempImage->Bpp + x * TempImage->Bpp + c] = origdata->data_[y * origdata->numcols_ + x];
    00303                         }
    00304                 }
    00305
    00306                 jas_matrix_destroy(origdata);
    00307         }
    00308
    00309         jas_image_destroy(Jp2Image);
    00310
    00311         ilFixImage();
    00312
    00313         return IL_TRUE;
    00314 }
    00315
    00316
    00317
    00318 static int iJp2_file_read(jas_stream_obj_t *obj, char *buf, int cnt)
    00319 {
    00320         obj;
    00321         return iread(buf, 1, cnt);
    00322 }
    00323
    00324 static int iJp2_file_write(jas_stream_obj_t *obj, char *buf, int cnt)
    00325 {
    00326         obj;
    00327         return iwrite(buf, 1, cnt);
    00328 }
    00329
    00330 static long iJp2_file_seek(jas_stream_obj_t *obj, long offset, int origin)
    00331 {
    00332         obj;
    00333
    00334         // We could just pass origin to iseek, but this is probably more portable.
    00335         switch (origin)
    00336         {
    00337                 case SEEK_SET:
    00338                         return iseek(offset, IL_SEEK_SET);
    00339                 case SEEK_CUR:
    00340                         return iseek(offset, IL_SEEK_CUR);
    00341                 case SEEK_END:
    00342                         return iseek(offset, IL_SEEK_END);
    00343         }
    00344         return 0;  // Failed
    00345 }
    00346
    00347 static int iJp2_file_close(jas_stream_obj_t *obj)
    00348 {
    00349         obj;
    00350         return 0;  // We choose when we want to close the file.
    00351 }
    00352
    00353 static jas_stream_ops_t jas_stream_devilops = {
    00354         iJp2_file_read,
    00355         iJp2_file_write,
    00356         iJp2_file_seek,
    00357         iJp2_file_close
    00358 };
    00359
    00360 static jas_stream_t *jas_stream_create(void);
    00361 static void jas_stream_destroy(jas_stream_t *stream);
    00362 static void jas_stream_initbuf(jas_stream_t *stream, int bufmode, char *buf, int bufsize);
    00363
    00364
    00365 // Modified version of jas_stream_fopen and jas_stream_memopen from jas_stream.c of JasPer
    00366 //  so that we can use our own file routines.
    00367 jas_stream_t *iJp2ReadStream()
    00368 {
    00369         jas_stream_t *stream;
    00370         jas_stream_memobj_t *obj;
    00371
    00372         if (!(stream = jas_stream_create())) {
    00373                 return 0;
    00374         }
    00375
    00376         /* A stream associated with a memory buffer is always opened
    00377         for both reading and writing in binary mode. */
    00378         stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_BINARY;
    00379
    00380         /* We use buffering whether it is from memory or a file. */
    00381         jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
    00382
    00383         /* Select the operations for a memory stream. */
    00384         stream->ops_ = &jas_stream_devilops;
    00385
    00386         /* Allocate memory for the underlying memory stream object. */
    00387         if (!(obj = jas_malloc(sizeof(jas_stream_memobj_t)))) {
    00388                 jas_stream_destroy(stream);
    00389                 return 0;
    00390         }
    00391         stream->obj_ = (void *) obj;
    00392
    00393         /* Initialize a few important members of the memory stream object. */
    00394         obj->myalloc_ = 0;
    00395         obj->buf_ = 0;
    00396
    00397         // Shouldn't need any of this.
    00398
    00400         //is allocated internally and automatically grown as needed. */
    00401         //if (bufsize <= 0) {
    00402         //      obj->bufsize_ = 1024;
    00403         //      obj->growable_ = 1;
    00404         //} else {
    00405         //      obj->bufsize_ = bufsize;
    00406         //      obj->growable_ = 0;
    00407         //}
    00408         //if (buf) {
    00409         //      obj->buf_ = (unsigned char *) buf;
    00410         //} else {
    00411         //      obj->buf_ = jas_malloc(obj->bufsize_ * sizeof(char));
    00412         //      obj->myalloc_ = 1;
    00413         //}
    00414         //if (!obj->buf_) {
    00415         //      jas_stream_close(stream);
    00416         //      return 0;
    00417         //}
    00418
    00419         //if (bufsize > 0 && buf) {
    00420         //      /* If a buffer was supplied by the caller and its length is positive,
    00421         //        make the associated buffer data appear in the stream initially. */
    00422         //      obj->len_ = bufsize;
    00423         //} else {
    00424         //      /* The stream is initially empty. */
    00425         //      obj->len_ = 0;
    00426         //}
    00427         //obj->pos_ = 0;
    00428
    00429         return stream;
    00430 }
    00431
    00432
    00433 // The following functions are taken directly from jas_stream.c of JasPer,
    00434 //  since they are designed to be used within JasPer only.
    00435
    00436 static void jas_stream_initbuf(jas_stream_t *stream, int bufmode, char *buf,
    00437   int bufsize)
    00438 {
    00439         /* If this function is being called, the buffer should not have been
    00440           initialized yet. */
    00441         assert(!stream->bufbase_);
    00442
    00443         if (bufmode != JAS_STREAM_UNBUF) {
    00444                 /* The full- or line-buffered mode is being employed. */
    00445                 if (!buf) {
    00446                         /* The caller has not specified a buffer to employ, so allocate
    00447                           one. */
    00448                         if ((stream->bufbase_ = jas_malloc(JAS_STREAM_BUFSIZE +
    00449                           JAS_STREAM_MAXPUTBACK))) {
    00450                                 stream->bufmode_ |= JAS_STREAM_FREEBUF;
    00451                                 stream->bufsize_ = JAS_STREAM_BUFSIZE;
    00452                         } else {
    00453                                 /* The buffer allocation has failed.  Resort to unbuffered
    00454                                   operation. */
    00455                                 stream->bufbase_ = stream->tinybuf_;
    00456                                 stream->bufsize_ = 1;
    00457                         }
    00458                 } else {
    00459                         /* The caller has specified a buffer to employ. */
    00460                         /* The buffer must be large enough to accommodate maximum
    00461                           putback. */
    00462                         assert(bufsize > JAS_STREAM_MAXPUTBACK);
    00463                         stream->bufbase_ = JAS_CAST(uchar *, buf);
    00464                         stream->bufsize_ = bufsize - JAS_STREAM_MAXPUTBACK;
    00465                 }
    00466         } else {
    00467                 /* The unbuffered mode is being employed. */
    00468                 /* A buffer should not have been supplied by the caller. */
    00469                 assert(!buf);
    00470                 /* Use a trivial one-character buffer. */
    00471                 stream->bufbase_ = stream->tinybuf_;
    00472                 stream->bufsize_ = 1;
    00473         }
    00474         stream->bufstart_ = &stream->bufbase_[JAS_STREAM_MAXPUTBACK];
    00475         stream->ptr_ = stream->bufstart_;
    00476         stream->cnt_ = 0;
    00477         stream->bufmode_ |= bufmode & JAS_STREAM_BUFMODEMASK;
    00478 }
    00479
    00480 static jas_stream_t *jas_stream_create()
    00481 {
    00482         jas_stream_t *stream;
    00483
    00484         if (!(stream = jas_malloc(sizeof(jas_stream_t)))) {
    00485                 return 0;
    00486         }
    00487         stream->openmode_ = 0;
    00488         stream->bufmode_ = 0;
    00489         stream->flags_ = 0;
    00490         stream->bufbase_ = 0;
    00491         stream->bufstart_ = 0;
    00492         stream->bufsize_ = 0;
    00493         stream->ptr_ = 0;
    00494         stream->cnt_ = 0;
    00495         stream->ops_ = 0;
    00496         stream->obj_ = 0;
    00497         stream->rwcnt_ = 0;
    00498         stream->rwlimit_ = -1;
    00499
    00500         return stream;
    00501 }
    00502
    00503 static void jas_stream_destroy(jas_stream_t *stream)
    00504 {
    00505         /* If the memory for the buffer was allocated with malloc, free
    00506         this memory. */
    00507         if ((stream->bufmode_ & JAS_STREAM_FREEBUF) && stream->bufbase_) {
    00508                 jas_free(stream->bufbase_);
    00509                 stream->bufbase_ = 0;
    00510         }
    00511         jas_free(stream);
    00512 }
    00513
    00514
    00515
    00516
    00517 jas_stream_t *iJp2WriteStream()
    00518 {
    00519         jas_stream_t *stream;
    00520         jas_stream_memobj_t *obj;
    00521
    00522         if (!(stream = jas_stream_create())) {
    00523                 return 0;
    00524         }
    00525
    00526         /* A stream associated with a memory buffer is always opened
    00527         for both reading and writing in binary mode. */
    00528         stream->openmode_ = JAS_STREAM_WRITE | JAS_STREAM_BINARY;
    00529
    00530         /* We use buffering whether it is from memory or a file. */
    00531         jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
    00532
    00533         /* Select the operations for a memory stream. */
    00534         stream->ops_ = &jas_stream_devilops;
    00535
    00536         /* Allocate memory for the underlying memory stream object. */
    00537         if (!(obj = jas_malloc(sizeof(jas_stream_memobj_t)))) {
    00538                 jas_stream_destroy(stream);
    00539                 return 0;
    00540         }
    00541         stream->obj_ = (void *) obj;
    00542
    00543         /* Initialize a few important members of the memory stream object. */
    00544         obj->myalloc_ = 0;
    00545         obj->buf_ = 0;
    00546
    00547         return stream;
    00548 }
    00549
    00550
    00551
    00553 ILboolean ilSaveJp2(const ILstring FileName)
    00554 {
    00555         ILHANDLE        Jp2File;
    00556         ILuint          Jp2Size;
    00557
    00558         if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
    00559                 if (iFileExists(FileName)) {
    00560                         ilSetError(IL_FILE_ALREADY_EXISTS);
    00561                         return IL_FALSE;
    00562                 }
    00563         }
    00564
    00565         Jp2File = iopenw(FileName);
    00566         if (Jp2File == NULL) {
    00567                 ilSetError(IL_COULD_NOT_OPEN_FILE);
    00568                 return IL_FALSE;
    00569         }
    00570
    00571         Jp2Size = ilSaveJp2F(Jp2File);
    00572         iclosew(Jp2File);
    00573
    00574         if (Jp2Size == 0)
    00575                 return IL_FALSE;
    00576         return IL_TRUE;
    00577 }
    00578
    00579
    00581 ILuint ilSaveJp2F(ILHANDLE File)
    00582 {
    00583         ILuint Pos;
    00584         iSetOutputFile(File);
    00585         Pos = itellw();
    00586         if (iSaveJp2Internal() == IL_FALSE)
    00587                 return 0;  // Error occurred
    00588         return itellw() - Pos;  // Return the number of bytes written.
    00589 }
    00590
    00591
    00593 ILuint ilSaveJp2L(void *Lump, ILuint Size)
    00594 {
    00595         ILuint Pos = itellw();
    00596         iSetOutputLump(Lump, Size);
    00597         if (iSaveJp2Internal() == IL_FALSE)
    00598                 return 0;  // Error occurred
    00599         return itellw() - Pos;  // Return the number of bytes written.
    00600 }
    00601
    00602
    00603
    00604 // Function from OpenSceneGraph (originally called getdata in their sources):
    00605 //  http://openscenegraph.sourcearchive.com/documentation/2.2.0/ReaderWriterJP2_8cpp-source.html
    00606 ILint Jp2ConvertData(jas_stream_t *in, jas_image_t *image)
    00607 {
    00608         int ret;
    00609         int numcmpts;
    00610         int cmptno;
    00611         jas_matrix_t *data[4];
    00612         int x;
    00613         int y;
    00614         int width, height;
    00615
    00616         width = jas_image_cmptwidth(image, 0);
    00617         height = jas_image_cmptheight(image, 0);
    00618         numcmpts = jas_image_numcmpts(image);
    00619
    00620         ret = -1;
    00621
    00622         data[0] = 0;
    00623         data[1] = 0;
    00624         data[2] = 0;
    00625         data[3] = 0;
    00626         for (cmptno = 0; cmptno < numcmpts; ++cmptno) {
    00627                 if (!(data[cmptno] = jas_matrix_create(1, width))) {
    00628                         goto done;
    00629                 }
    00630         }
    00631
    00632         for (y = height - 1; y >= 0; --y)
    00633         //        for (y = 0; y < height; ++y)
    00634         {
    00635                 for (x = 0; x < width; ++x)
    00636                 {
    00637                         for (cmptno = 0; cmptno < numcmpts; ++cmptno)
    00638                         {
    00639                                 // The sample data is unsigned.
    00640                                 int c;
    00641                                 if ((c = jas_stream_getc(in)) == EOF) {
    00642                                         return -1;
    00643                                 }
    00644                                 jas_matrix_set(data[cmptno], 0, x, c);
    00645                         }
    00646                 }
    00647                 for (cmptno = 0; cmptno < numcmpts; ++cmptno) {
    00648                         if (jas_image_writecmpt(image, cmptno, 0, y, width, 1,
    00649                                 data[cmptno])) {
    00650                                 goto done;
    00651                         }
    00652                 }
    00653         }
    00654
    00655         jas_stream_flush(in);
    00656         ret = 0;
    00657
    00658 done:
    00659         for (cmptno = 0; cmptno < numcmpts; ++cmptno) {
    00660                 if (data[cmptno]) {
    00661                         jas_matrix_destroy(data[cmptno]);
    00662                 }
    00663         }
    00664
    00665         return ret;
    00666 }
    00667
    00668
    00669 // Internal function used to save the Jp2.
    00670 // Since the JasPer documentation is extremely incomplete, I had to look at how OpenSceneGraph uses it:
    00671 //  http://openscenegraph.sourcearchive.com/documentation/2.2.0/ReaderWriterJP2_8cpp-source.html
    00672
    00673 //@TODO: Do we need to worry about images with depths > 1?
    00674 ILboolean iSaveJp2Internal()
    00675 {
    00676         jas_image_t *Jp2Image;
    00677         jas_image_cmptparm_t cmptparm[4];
    00678         jas_stream_t *Mem, *Stream;
    00679         ILuint  NumChans, i;
    00680         ILenum  NewFormat, NewType = IL_UNSIGNED_BYTE;
    00681         ILimage *TempImage = iCurImage;
    00682
    00683         if (!JasperInit) {
    00684                 if (jas_init()) {
    00685                         ilSetError(IL_LIB_JP2_ERROR);
    00686                         return IL_FALSE;
    00687                 }
    00688                 JasperInit = IL_TRUE;
    00689         }
    00690
    00691         if (iCurImage->Type != IL_UNSIGNED_BYTE) {  //@TODO: Support greater than 1 bpc.
    00692                 NewType = IL_UNSIGNED_BYTE;
    00693         }
    00694         //@TODO: Do luminance/luminance-alpha/alpha separately.
    00695         switch (iCurImage->Format)
    00696         {
    00697                 case IL_LUMINANCE:
    00698                         NewFormat = IL_LUMINANCE;
    00699                         NumChans = 1;
    00700                         break;
    00701                 case IL_ALPHA:
    00702                         NewFormat = IL_ALPHA;
    00703                         NumChans = 1;
    00704                         break;
    00705                 case IL_LUMINANCE_ALPHA:
    00706                         NewFormat = IL_LUMINANCE_ALPHA;
    00707                         NumChans = 2;
    00708                         break;
    00709                 case IL_COLOUR_INDEX:  // Assuming the color palette does not have an alpha value.
    00710                                                                 //@TODO: Check for this in the future.
    00711                 case IL_RGB:
    00712                 case IL_BGR:
    00713                         NewFormat = IL_RGB;
    00714                         NumChans = 3;
    00715                         break;
    00716                 case IL_RGBA:
    00717                 case IL_BGRA:
    00718                         NewFormat = IL_RGBA;
    00719                         NumChans = 4;
    00720                         break;
    00721         }
    00722
    00723         if (NewType != iCurImage->Type || NewFormat != iCurImage->Format) {
    00724                 TempImage = iConvertImage(iCurImage, NewFormat, NewType);
    00725                 if (TempImage == NULL)
    00726                         return IL_FALSE;
    00727         }
    00728
    00729         // The origin is always in the lower left corner.  Flip the buffer if it is not.
    00730         if (TempImage->Origin == IL_ORIGIN_UPPER_LEFT)
    00731                 iFlipBuffer(TempImage->Data, TempImage->Depth, TempImage->Bps, TempImage->Height);
    00732
    00733         // Have to tell JasPer about each channel.  In our case, they all have the same information.
    00734         for (i = 0; i < NumChans; i++) {
    00735                 cmptparm[i].width = iCurImage->Width;
    00736                 cmptparm[i].height = iCurImage->Height;
    00737                 cmptparm[i].hstep = 1;
    00738                 cmptparm[i].vstep = 1;
    00739                 cmptparm[i].tlx = 0;
    00740                 cmptparm[i].tly = 0;
    00741                 cmptparm[i].prec = 8;
    00742                 cmptparm[i].sgnd = 0;  // Unsigned data
    00743         }
    00744
    00745         // Using the unknown color space, since we have not determined the space yet.
    00746         //  This is done in the following switch statement.
    00747         Jp2Image = jas_image_create(NumChans, cmptparm, JAS_CLRSPC_UNKNOWN);
    00748         if (Jp2Image == NULL) {
    00749                 ilSetError(IL_LIB_JP2_ERROR);
    00750                 return IL_FALSE;
    00751         }
    00752
    00753         switch (NumChans)
    00754         {
    00755                 case 1:
    00756                         jas_image_setclrspc(Jp2Image, JAS_CLRSPC_SGRAY);
    00757                         if (NewFormat == IL_LUMINANCE)
    00758                                 jas_image_setcmpttype(Jp2Image, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y));
    00759                         else // IL_ALPHA
    00760                                 jas_image_setcmpttype(Jp2Image, 0, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_OPACITY));
    00761                         break;
    00762                 case 2:
    00763                         jas_image_setclrspc(Jp2Image, JAS_CLRSPC_SGRAY);
    00764                         jas_image_setcmpttype(Jp2Image, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y));
    00765                         jas_image_setcmpttype(Jp2Image, 1, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_OPACITY));
    00766                         break;
    00767                 case 3:
    00768                         jas_image_setclrspc(Jp2Image, JAS_CLRSPC_SRGB);
    00769                         jas_image_setcmpttype(Jp2Image, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R));
    00770                         jas_image_setcmpttype(Jp2Image, 1, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G));
    00771                         jas_image_setcmpttype(Jp2Image, 2, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B));
    00772                         break;
    00773                 case 4:
    00774                         jas_image_setclrspc(Jp2Image, JAS_CLRSPC_SRGB);
    00775                         jas_image_setcmpttype(Jp2Image, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R));
    00776                         jas_image_setcmpttype(Jp2Image, 1, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G));
    00777                         jas_image_setcmpttype(Jp2Image, 2, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B));
    00778                         jas_image_setcmpttype(Jp2Image, 3, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_OPACITY));
    00779                         break;
    00780         }
    00781
    00782         Mem = jas_stream_memopen((char*)TempImage->Data, TempImage->SizeOfData);
    00783         if (Mem == NULL) {
    00784                 jas_image_destroy(Jp2Image);
    00785                 ilSetError(IL_LIB_JP2_ERROR);
    00786                 return IL_FALSE;
    00787         }
    00788         Stream = iJp2WriteStream();
    00789         if (Stream == NULL) {
    00790                 jas_stream_close(Mem);
    00791                 jas_image_destroy(Jp2Image);
    00792                 ilSetError(IL_LIB_JP2_ERROR);
    00793                 return IL_FALSE;
    00794         }
    00795
    00796         // Puts data in the format that JasPer wants it in.
    00797         Jp2ConvertData(Mem, Jp2Image);
    00798
    00799         // Does all of the encoding.
    00800         if (jas_image_encode(Jp2Image, Stream, jas_image_strtofmt("jp2"), NULL)) {  //@TODO: Do we want to use any options?
    00801                 jas_stream_close(Mem);
    00802                 jas_stream_close(Stream);
    00803                 jas_image_destroy(Jp2Image);
    00804                 ilSetError(IL_LIB_JP2_ERROR);
    00805                 return IL_FALSE;
    00806         }
    00807         jas_stream_flush(Stream);  // Do any final writing.
    00808
    00809         // Close the memory and output streams.
    00810         jas_stream_close(Mem);
    00811         jas_stream_close(Stream);
    00812         // Destroy the JasPer image.
    00813         jas_image_destroy(Jp2Image);
    00814
    00815         // Destroy our temporary image if we used one.
    00816         if (TempImage != iCurImage)
    00817                 ilCloseImage(TempImage);
    00818
    00819         return IL_TRUE;
    00820 }
    00821
    00822
    00823 #endif//IL_NO_JP2