1
//-----------------------------------------------------------------------------
4
// Copyright (C) 2000-2008 by Denton Woods
5
// Last modified: 08/24/2008
7
// Filename: src-IL/src/il_jp2.c
9
// Description: Jpeg-2000 (.jp2) functions
11
//-----------------------------------------------------------------------------
14
// @TODO: Look in jas_stream.c of JasPer and make own version of
15
// jas_stream_fopen that will return a jas_stream_t and
16
// work on file streams instead of just a filename.
18
#include "il_internal.h"
20
#include <jasper/jasper.h>
23
#if defined(_WIN32) && defined(IL_USE_PRAGMA_LIBS)
24
#if defined(_MSC_VER) || defined(__BORLANDC__)
26
#pragma comment(lib, "libjasper.lib")
28
#pragma comment(lib, "libjasper-d.lib")
34
//! Reads a Jpeg2000 file.
35
ILboolean ilLoadJp2(ILconst_string FileName)
40
Jp2File = iopenr(FileName);
41
if (Jp2File == NULL) {
42
ilSetError(IL_COULD_NOT_OPEN_FILE);
46
bRet = ilLoadJp2F(Jp2File);
53
//! Reads an already-opened Jpeg2000 file.
54
ILboolean ilLoadJp2F(ILHANDLE File)
65
ilSetError(IL_LIB_JP2_ERROR);
68
Stream = iJp2ReadStream();
71
ilSetError(IL_COULD_NOT_OPEN_FILE);
75
bRet = iLoadJp2Internal(Stream, NULL);
76
// Close the input stream.
77
jas_stream_close(Stream);
79
iseek(FirstPos, IL_SEEK_SET);
85
//! Reads from a memory "lump" that contains a Jpeg2000 stream.
86
ILboolean ilLoadJp2L(const void *Lump, ILuint Size)
88
return ilLoadJp2LInternal(Lump, Size, NULL);
92
//! This is separated so that it can be called for other file types, such as .icns.
93
ILboolean ilLoadJp2LInternal(const void *Lump, ILuint Size, ILimage *Image)
100
ilSetError(IL_LIB_JP2_ERROR);
103
Stream = jas_stream_memopen((char*)Lump, Size);
106
ilSetError(IL_COULD_NOT_OPEN_FILE);
110
bRet = iLoadJp2Internal(Stream, Image);
111
// Close the input stream.
112
jas_stream_close(Stream);
118
// Internal function used to load the Jpeg2000 stream.
119
ILboolean iLoadJp2Internal(jas_stream_t *Stream, ILimage *Image)
121
jas_image_t *Jp2Image = NULL;
122
jas_matrix_t *origdata;
127
Jp2Image = jas_image_decode(Stream, -1, 0);
130
ilSetError(IL_ILLEGAL_FILE_VALUE);
131
jas_stream_close(Stream);
135
// We're not supporting anything other than 8 bits/component yet.
136
if (jas_image_cmptprec(Jp2Image, 0) != 8)
138
jas_image_destroy(Jp2Image);
139
ilSetError(IL_ILLEGAL_FILE_VALUE);
143
switch (jas_image_numcmpts(Jp2Image))
147
ilTexImage(jas_image_width(Jp2Image), jas_image_height(Jp2Image), 1, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL);
148
TempImage = iCurImage;
151
ifree(Image->Data); // @TODO: Not really the most efficient way to do this...
152
ilInitImage(Image, jas_image_width(Jp2Image), jas_image_height(Jp2Image), 1, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL);
158
ilTexImage(jas_image_width(Jp2Image), jas_image_height(Jp2Image), 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL);
159
TempImage = iCurImage;
162
ifree(Image->Data); // @TODO: Not really the most efficient way to do this...
163
ilInitImage(Image, jas_image_width(Jp2Image), jas_image_height(Jp2Image), 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL);
168
jas_image_destroy(Jp2Image);
169
ilSetError(IL_ILLEGAL_FILE_VALUE);
172
TempImage->Origin = IL_ORIGIN_UPPER_LEFT;
174
// JasPer stores the data channels separately.
175
// I am assuming RGBA format. Is it possible for other formats to be included?
176
for (c = 0; c < TempImage->Bpp; c++)
178
origdata = jas_matrix_create(TempImage->Height, TempImage->Width);
181
ilSetError(IL_LIB_JP2_ERROR);
182
return IL_FALSE; // @TODO: Error
184
// Have to convert data into an intermediate matrix format.
185
if (jas_image_readcmpt(Jp2Image, c, 0, 0, TempImage->Width, TempImage->Height, origdata))
190
for (y = 0; y < TempImage->Height; y++)
192
for (x = 0; x < TempImage->Width; x++)
194
TempImage->Data[y * TempImage->Width * TempImage->Bpp + x * TempImage->Bpp + c] = origdata->data_[y * origdata->numcols_ + x];
198
jas_matrix_destroy(origdata);
201
jas_image_destroy(Jp2Image);
210
static int iJp2_file_read(jas_stream_obj_t *obj, char *buf, int cnt)
213
return iread(buf, 1, cnt);
216
static int iJp2_file_write(jas_stream_obj_t *obj, char *buf, int cnt)
219
return iwrite(buf, 1, cnt);
222
static long iJp2_file_seek(jas_stream_obj_t *obj, long offset, int origin)
226
// We could just pass origin to iseek, but this is probably more portable.
230
return iseek(offset, IL_SEEK_SET);
232
return iseek(offset, IL_SEEK_CUR);
234
return iseek(offset, IL_SEEK_END);
239
static int iJp2_file_close(jas_stream_obj_t *obj)
242
return 0; // We choose when we want to close the file.
245
static jas_stream_ops_t jas_stream_devilops = {
252
static jas_stream_t *jas_stream_create(void);
253
static void jas_stream_destroy(jas_stream_t *stream);
254
static void jas_stream_initbuf(jas_stream_t *stream, int bufmode, char *buf, int bufsize);
257
// Modified version of jas_stream_fopen and jas_stream_memopen from jas_stream.c of JasPer
258
// so that we can use our own file routines.
259
jas_stream_t *iJp2ReadStream()
261
jas_stream_t *stream;
262
jas_stream_memobj_t *obj;
264
if (!(stream = jas_stream_create())) {
268
/* A stream associated with a memory buffer is always opened
269
for both reading and writing in binary mode. */
270
stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_BINARY;
272
/* We use buffering whether it is from memory or a file. */
273
jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
275
/* Select the operations for a memory stream. */
276
stream->ops_ = &jas_stream_devilops;
278
/* Allocate memory for the underlying memory stream object. */
279
if (!(obj = jas_malloc(sizeof(jas_stream_memobj_t)))) {
280
jas_stream_destroy(stream);
283
stream->obj_ = (void *) obj;
285
/* Initialize a few important members of the memory stream object. */
289
// Shouldn't need any of this.
291
///* If the buffer size specified is nonpositive, then the buffer
292
//is allocated internally and automatically grown as needed. */
293
//if (bufsize <= 0) {
294
// obj->bufsize_ = 1024;
295
// obj->growable_ = 1;
297
// obj->bufsize_ = bufsize;
298
// obj->growable_ = 0;
301
// obj->buf_ = (unsigned char *) buf;
303
// obj->buf_ = jas_malloc(obj->bufsize_ * sizeof(char));
304
// obj->myalloc_ = 1;
307
// jas_stream_close(stream);
311
//if (bufsize > 0 && buf) {
312
// /* If a buffer was supplied by the caller and its length is positive,
313
// make the associated buffer data appear in the stream initially. */
314
// obj->len_ = bufsize;
316
// /* The stream is initially empty. */
325
// The following functions are taken directly from jas_stream.c of JasPer,
326
// since they are designed to be used within JasPer only.
328
static void jas_stream_initbuf(jas_stream_t *stream, int bufmode, char *buf,
331
/* If this function is being called, the buffer should not have been
333
assert(!stream->bufbase_);
335
if (bufmode != JAS_STREAM_UNBUF) {
336
/* The full- or line-buffered mode is being employed. */
338
/* The caller has not specified a buffer to employ, so allocate
340
if ((stream->bufbase_ = jas_malloc(JAS_STREAM_BUFSIZE +
341
JAS_STREAM_MAXPUTBACK))) {
342
stream->bufmode_ |= JAS_STREAM_FREEBUF;
343
stream->bufsize_ = JAS_STREAM_BUFSIZE;
345
/* The buffer allocation has failed. Resort to unbuffered
347
stream->bufbase_ = stream->tinybuf_;
348
stream->bufsize_ = 1;
351
/* The caller has specified a buffer to employ. */
352
/* The buffer must be large enough to accommodate maximum
354
assert(bufsize > JAS_STREAM_MAXPUTBACK);
355
stream->bufbase_ = JAS_CAST(uchar *, buf);
356
stream->bufsize_ = bufsize - JAS_STREAM_MAXPUTBACK;
359
/* The unbuffered mode is being employed. */
360
/* A buffer should not have been supplied by the caller. */
362
/* Use a trivial one-character buffer. */
363
stream->bufbase_ = stream->tinybuf_;
364
stream->bufsize_ = 1;
366
stream->bufstart_ = &stream->bufbase_[JAS_STREAM_MAXPUTBACK];
367
stream->ptr_ = stream->bufstart_;
369
stream->bufmode_ |= bufmode & JAS_STREAM_BUFMODEMASK;
372
static jas_stream_t *jas_stream_create()
374
jas_stream_t *stream;
376
if (!(stream = jas_malloc(sizeof(jas_stream_t)))) {
379
stream->openmode_ = 0;
380
stream->bufmode_ = 0;
382
stream->bufbase_ = 0;
383
stream->bufstart_ = 0;
384
stream->bufsize_ = 0;
390
stream->rwlimit_ = -1;
395
static void jas_stream_destroy(jas_stream_t *stream)
397
/* If the memory for the buffer was allocated with malloc, free
399
if ((stream->bufmode_ & JAS_STREAM_FREEBUF) && stream->bufbase_) {
400
jas_free(stream->bufbase_);
401
stream->bufbase_ = 0;