~ubuntu-branches/ubuntu/jaunty/ghostscript/jaunty-updates

« back to all changes in this revision

Viewing changes to base/sjpx_luratech.c

  • Committer: Bazaar Package Importer
  • Author(s): Till Kamppeter
  • Date: 2009-01-20 16:40:45 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20090120164045-lnfhi0n30o5lwhwa
Tags: 8.64.dfsg.1~svn9377-0ubuntu1
* New upstream release (SVN rev 9377)
   o Fixes many bugs concerning PDF rendering, to make the PDF printing
     workflow correctly working.
   o Fixes long-standing bugs in many drivers, like input paper tray and
     duplex options not working for the built-in PCL 4, 5, 5c, 5e, and
     6/XL drivers, PDF input not working for bjc600, bjc800, and cups
     output devices, several options not working and uninitialized
     memory with cups output device.
   o Merged nearly all patches of the Ubuntu and Debian packages upstream.
   o Fixes LP: #317810, LP: #314439, LP: #314018.
* debian/patches/03_libpaper_support.dpatch,
  debian/patches/11_gs-cjk_font_glyph_handling_fix.dpatch,
  debian/patches/12_gs-cjk_vertical_writing_metrics_fix.dpatch,
  debian/patches/13_gs-cjk_cjkps_examples.dpatch,
  debian/patches/20_bbox_segv_fix.dpatch,
  debian/patches/21_brother_7x0_gdi_fix.dpatch,
  debian/patches/22_epsn_margin_workaround.dpatch,
  debian/patches/24_gs_man_fix.dpatch,
  debian/patches/25_toolbin_insecure_tmp_usage_fix.dpatch,
  debian/patches/26_assorted_script_fixes.dpatch,
  debian/patches/29_gs_css_fix.dpatch,
  debian/patches/30_ps2pdf_man_improvement.dpatch,
  debian/patches/31_fix-gc-sigbus.dpatch,
  debian/patches/34_ftbfs-on-hurd-fix.dpatch,
  debian/patches/35_disable_libcairo.dpatch,
  debian/patches/38_pxl-duplex.dpatch,
  debian/patches/39_pxl-resolution.dpatch,
  debian/patches/42_gs-init-ps-delaybind-fix.dpatch,
  debian/patches/45_bjc600-bjc800-pdf-input.dpatch,
  debian/patches/48_cups-output-device-pdf-duplex-uninitialized-memory-fix.dpatch,
  debian/patches/50_lips4-floating-point-exception.dpatch,
  debian/patches/52_cups-device-logging.dpatch,
  debian/patches/55_pcl-input-slot-fix.dpatch,
  debian/patches/57_pxl-input-slot-fix.dpatch,
  debian/patches/60_pxl-cups-driver-pdf.dpatch,
  debian/patches/62_onebitcmyk-pdf.dpatch,
  debian/patches/65_too-big-temp-files-1.dpatch,
  debian/patches/67_too-big-temp-files-2.dpatch,
  debian/patches/70_take-into-account-data-in-stream-buffer-before-refill.dpatch:
  Removed, applied upstream.
* debian/patches/01_docdir_fix_for_debian.dpatch,
  debian/patches/02_gs_man_fix_debian.dpatch,
  debian/patches/01_docdir-fix-for-debian.dpatch,
  debian/patches/02_docdir-fix-for-debian.dpatch: Renamed patches to
  make merging with Debian easier.
* debian/patches/32_improve-handling-of-media-size-changes-from-gv.dpatch, 
  debian/patches/33_bad-params-to-xinitimage-on-large-bitmaps.dpatch:
  regenerated for new source directory structure.
* debian/rules: Corrected paths to remove cidfmap (it is in Resource/Init/
  in GS 8.64) and to install headers (source paths are psi/ and base/ now).
* debian/rules: Remove all fontmaps, as DeFoMa replaces them.
* debian/local/pdftoraster/pdftoraster.c,
  debian/local/pdftoraster/pdftoraster.convs, debian/rules: Removed
  added pdftoraster filter and use the one which comes with Ghostscript.
* debian/ghostscript.links: s/8.63/8.64/

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2001-2006 Artifex Software, Inc.
 
2
   All Rights Reserved.
 
3
 
 
4
   This software is provided AS-IS with no warranty, either express or
 
5
   implied.
 
6
 
 
7
   This software is distributed under license and may not be copied, modified
 
8
   or distributed except as expressly authorized under the terms of that
 
9
   license.  Refer to licensing information at http://www.artifex.com/
 
10
   or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
 
11
   San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
 
12
*/
 
13
 
 
14
/* $Id: sjpx_luratech.c 8816 2008-07-03 18:25:52Z giles $ */
 
15
/* JPXDecode filter implementation -- hooks in the Luratech JPEG2K CSDK */
 
16
 
 
17
#include "memory_.h"
 
18
#include "malloc_.h"
 
19
#include "gserrors.h"
 
20
#include "gserror.h"
 
21
#include "gdebug.h"
 
22
#include "strimpl.h"
 
23
#include "sjpx_luratech.h"
 
24
 
 
25
#include <lwf_jp2.h>
 
26
 
 
27
/* JPXDecode stream implementation using the Luratech library */
 
28
 
 
29
/* if linking against a SDK build that requires a separate license key,
 
30
   you can change the following undefs to defines and set them here. */
 
31
/***
 
32
#ifndef JP2_LICENSE_NUM_1
 
33
# undef JP2_LICENSE_NUM_1
 
34
#endif
 
35
#ifndef JP2_LICENSE_NUM_2
 
36
# undef JP2_LICENSE_NUM_2
 
37
#endif
 
38
***/
 
39
 
 
40
/* As with the /JBIG2Decode filter, we let the library do its
 
41
   memory management through malloc() etc. and rely on our release()
 
42
   proc being called to deallocate state.
 
43
*/
 
44
 
 
45
private_st_jpxd_state(); /* creates a gc object for our state,
 
46
                            defined in sjpx.h */
 
47
 
 
48
#define JPX_BUFFER_SIZE 1024
 
49
 
 
50
/** callback for the codec library */
 
51
 
 
52
/* memory allocation */
 
53
static void * JP2_Callback_Conv
 
54
s_jpx_alloc(long size, JP2_Callback_Param param)
 
55
{
 
56
    void *result = malloc(size);
 
57
 
 
58
    return result;
 
59
}
 
60
 
 
61
/* memory free */
 
62
static JP2_Error JP2_Callback_Conv
 
63
s_jpx_free(void *ptr, JP2_Callback_Param param)
 
64
{
 
65
    free(ptr);
 
66
 
 
67
    return cJP2_Error_OK;
 
68
}
 
69
 
 
70
/* pass any available input to the library */
 
71
static unsigned long JP2_Callback_Conv
 
72
s_jpxd_read_data(unsigned char *pucData,
 
73
                            unsigned long ulPos, unsigned long ulSize,
 
74
                            JP2_Callback_Param param)
 
75
{
 
76
    stream_jpxd_state *const state = (stream_jpxd_state *) param;
 
77
    unsigned long copy_bytes = min(ulSize, state->inbuf_fill - ulPos);
 
78
 
 
79
    memcpy(pucData, state->inbuf + ulPos, copy_bytes);
 
80
 
 
81
    return copy_bytes;
 
82
}
 
83
 
 
84
/* write decompressed data into our image buffer */
 
85
static JP2_Error JP2_Callback_Conv
 
86
s_jpxd_write_data(unsigned char * pucData,
 
87
                               short sComponent,
 
88
                               unsigned long ulRow,
 
89
                               unsigned long ulStart,
 
90
                               unsigned long ulNum,
 
91
                               JP2_Callback_Param param)
 
92
{
 
93
    stream_jpxd_state *const state = (stream_jpxd_state *) param;
 
94
    unsigned char *p;
 
95
    unsigned long i;
 
96
 
 
97
    /* check input */
 
98
    if (ulRow >= state->height) return cJP2_Error_Invalid_Height;
 
99
    if (ulStart + ulNum >= state->width) ulNum = state->width - ulStart;
 
100
 
 
101
    /* Here we just copy a byte at a time into an image buffer,
 
102
       interleaving with whatever data already exists. For multi-
 
103
       component images, it would be more efficient to save rows
 
104
       from each call in planar buffers and interleave a tile at
 
105
       a time into a stipe buffer for output */
 
106
 
 
107
    /* todo: handle non-8-bit samples, subsampled components,
 
108
        and Y'CrCb colorspace rotation */
 
109
 
 
110
    p = state->image + state->stride*ulRow + state->ncomp*ulStart;
 
111
    if (state->ncomp == 1)
 
112
        memcpy(p, pucData, ulNum);
 
113
    else for (i = 0; i < ulNum; i++) {
 
114
        p[sComponent] = pucData[i];
 
115
        p += state->ncomp;
 
116
    }
 
117
    return cJP2_Error_OK;
 
118
}
 
119
 
 
120
static int
 
121
s_jpxd_inbuf(stream_jpxd_state *state, stream_cursor_read * pr)
 
122
{
 
123
    long in_size = pr->limit - pr->ptr;
 
124
 
 
125
    /* allocate the input buffer if needed */
 
126
    if (state->inbuf == NULL) {
 
127
        state->inbuf = malloc(JPX_BUFFER_SIZE);
 
128
        if (state->inbuf == NULL) return gs_error_VMerror;
 
129
        state->inbuf_size = JPX_BUFFER_SIZE;
 
130
        state->inbuf_fill = 0;
 
131
    }
 
132
 
 
133
    /* grow the input buffer if needed */
 
134
    if (state->inbuf_size < state->inbuf_fill + in_size) {
 
135
        unsigned char *new;
 
136
        unsigned long new_size = state->inbuf_size;
 
137
 
 
138
        while (new_size < state->inbuf_fill + in_size)
 
139
            new_size = new_size << 1;
 
140
 
 
141
        if_debug1('s', "[s]jpxd growing input buffer to %lu bytes\n",
 
142
                new_size);
 
143
        new = realloc(state->inbuf, new_size);
 
144
        if (new == NULL) return gs_error_VMerror;
 
145
 
 
146
        state->inbuf = new;
 
147
        state->inbuf_size = new_size;
 
148
    }
 
149
 
 
150
    /* copy the available input into our buffer */
 
151
    /* note that the gs stream library uses offset-by-one
 
152
        indexing of its buffers while we use zero indexing */
 
153
    memcpy(state->inbuf + state->inbuf_fill, pr->ptr + 1, in_size);
 
154
    state->inbuf_fill += in_size;
 
155
    pr->ptr += in_size;
 
156
 
 
157
    return 0;
 
158
}
 
159
 
 
160
/* initialize the steam.
 
161
   this involves allocating the stream and image structures, and
 
162
   initializing the decoder.
 
163
 */
 
164
static int
 
165
s_jpxd_init(stream_state * ss)
 
166
{
 
167
    stream_jpxd_state *const state = (stream_jpxd_state *) ss;
 
168
 
 
169
    if (state->jpx_memory == NULL) {
 
170
      state->jpx_memory = ss->memory ?
 
171
                ss->memory->non_gc_memory :
 
172
                gs_lib_ctx_get_non_gc_memory_t();
 
173
    }
 
174
 
 
175
    state->handle = (JP2_Decomp_Handle)NULL;
 
176
 
 
177
    state->inbuf = NULL;
 
178
    state->inbuf_size = 0;
 
179
    state->inbuf_fill = 0;
 
180
 
 
181
    state->ncomp = 0;
 
182
    state->bpc = 0;
 
183
    state->width = 0;
 
184
    state->height = 0;
 
185
    state->stride = 0;
 
186
    state->image = NULL;
 
187
    state->offset = 0;
 
188
 
 
189
    return 0;
 
190
}
 
191
 
 
192
/* process a secton of the input and return any decoded data.
 
193
   see strimpl.h for return codes.
 
194
 */
 
195
static int
 
196
s_jpxd_process(stream_state * ss, stream_cursor_read * pr,
 
197
                 stream_cursor_write * pw, bool last)
 
198
{
 
199
    stream_jpxd_state *const state = (stream_jpxd_state *) ss;
 
200
    JP2_Error err;
 
201
    JP2_Property_Value result;
 
202
    long in_size = pr->limit - pr->ptr;
 
203
    long out_size = pw->limit - pw->ptr;
 
204
 
 
205
    if (in_size > 0) {
 
206
        /* buffer available data */
 
207
        s_jpxd_inbuf(state, pr);
 
208
    }
 
209
 
 
210
    if (last == 1) {
 
211
        /* we have all the data, decode and return */
 
212
 
 
213
        if (state->handle == (JP2_Decomp_Handle)NULL) {
 
214
            /* initialize decompressor */
 
215
            err = JP2_Decompress_Start(&state->handle,
 
216
                /* memory allocator callbacks */
 
217
                s_jpx_alloc, (JP2_Callback_Param)state,
 
218
                s_jpx_free,  (JP2_Callback_Param)state,
 
219
                /* our read callback */
 
220
                s_jpxd_read_data, (JP2_Callback_Param)state
 
221
            );
 
222
            if (err != cJP2_Error_OK) {
 
223
                dlprintf1("Luratech JP2 error %d starting decompression\n", (int)err);
 
224
                return ERRC;
 
225
            }
 
226
#if defined(JP2_LICENSE_NUM_1) && defined(JP2_LICENSE_NUM_2)
 
227
            /* set the license keys if appropriate */
 
228
            error = JP2_Decompress_SetLicense(state->handle,
 
229
                JP2_LICENSE_NUM_1, JP2_LICENSE_NUM_2);
 
230
            if (error != cJP2_Error_OK) {
 
231
                dlprintf1("Luratech JP2 error %d setting license\n", (int)err);
 
232
                return ERRC;
 
233
            }
 
234
#endif
 
235
            /* parse image parameters */
 
236
            err = JP2_Decompress_GetProp(state->handle,
 
237
                cJP2_Prop_Components, &result, -1, -1);
 
238
            if (err != cJP2_Error_OK) {
 
239
                dlprintf1("Luratech JP2 error %d decoding number of image components\n", (int)err);
 
240
                return ERRC;
 
241
            }
 
242
            state->ncomp = result;
 
243
 
 
244
            if_debug1('w', "[w]jpxd image has %d components\n", state->ncomp);
 
245
 
 
246
            {
 
247
                const char *cspace = "unknown";
 
248
                err = JP2_Decompress_GetProp(state->handle,
 
249
                        cJP2_Prop_Extern_Colorspace, &result, -1, -1);
 
250
                if (err != cJP2_Error_OK) {
 
251
                    dlprintf1("Luratech JP2 error %d decoding colorspace\n", (int)err);
 
252
                    return ERRC;
 
253
                }
 
254
                switch (result) {
 
255
                    case cJP2_Colorspace_Gray: cspace = "gray"; break;
 
256
                    case cJP2_Colorspace_RGBa: cspace = "sRGB"; break;
 
257
                    case cJP2_Colorspace_RGB_YCCa:
 
258
                        cspace = "sRGB YCrCb"; break;
 
259
                    case cJP2_Colorspace_CIE_LABa:
 
260
                        cspace = "CIE Lab"; break;
 
261
                    case cJP2_Colorspace_ICCa:
 
262
                        cspace = "ICC profile"; break;
 
263
                    case cJP2_Colorspace_Palette_Gray:
 
264
                        cspace = "indexed gray"; break;
 
265
                    case cJP2_Colorspace_Palette_RGBa:
 
266
                        cspace = "indexed sRGB"; break;
 
267
                    case cJP2_Colorspace_Palette_RGB_YCCa:
 
268
                        cspace = "indexed sRGB YCrCb"; break;
 
269
                    case cJP2_Colorspace_Palette_CIE_LABa:
 
270
                        cspace = "indexed CIE Lab"; break;
 
271
                    case cJP2_Colorspace_Palette_ICCa:
 
272
                        cspace = "indexed with ICC profile"; break;
 
273
                }
 
274
                if_debug1('w', "[w]jpxd image colorspace is %s\n", cspace);
 
275
            }
 
276
 
 
277
            /* the library doesn't return the overall image dimensions
 
278
               or depth, so we take the maximum of the component values */
 
279
            state->width = 0;
 
280
            state->height = 0;
 
281
            state->bpc = 0;
 
282
            {
 
283
                int comp;
 
284
                int width, height;
 
285
                int bits, is_signed;
 
286
                for (comp = 0; comp < state->ncomp; comp++) {
 
287
                    err= JP2_Decompress_GetProp(state->handle,
 
288
                        cJP2_Prop_Width, &result, -1, (short)comp);
 
289
                    if (err != cJP2_Error_OK) {
 
290
                        dlprintf2("Luratech JP2 error %d decoding "
 
291
                                "width for component %d\n", (int)err, comp);
 
292
                        return ERRC;
 
293
                    }
 
294
                    width = result;
 
295
                    err= JP2_Decompress_GetProp(state->handle,
 
296
                        cJP2_Prop_Height, &result, -1, (short)comp);
 
297
                    if (err != cJP2_Error_OK) {
 
298
                        dlprintf2("Luratech JP2 error %d decoding "
 
299
                                "height for component %d\n", (int)err, comp);
 
300
                        return ERRC;
 
301
                    }
 
302
                    height = result;
 
303
                    err= JP2_Decompress_GetProp(state->handle,
 
304
                        cJP2_Prop_Bits_Per_Sample, &result, -1, (short)comp);
 
305
                    if (err != cJP2_Error_OK) {
 
306
                        dlprintf2("Luratech JP2 error %d decoding "
 
307
                                "bits per sample for component %d\n", (int)err, comp);
 
308
                        return ERRC;
 
309
                    }
 
310
                    bits = result;
 
311
                    err= JP2_Decompress_GetProp(state->handle,
 
312
                        cJP2_Prop_Signed_Samples, &result, -1, (short)comp);
 
313
                    if (err != cJP2_Error_OK) {
 
314
                        dlprintf2("Luratech JP2 error %d decoding "
 
315
                                "signedness of component %d\n", (int)err, comp);
 
316
                        return ERRC;
 
317
                    }
 
318
                    is_signed = result;
 
319
                    if_debug5('w',
 
320
                        "[w]jpxd image component %d has %dx%d %s %d bit samples\n",
 
321
                        comp, width, height,
 
322
                        is_signed ? "signed" : "unsigned", bits);
 
323
 
 
324
                    /* update image maximums */
 
325
                    if (state->width < width) state->width = width;
 
326
                    if (state->height < height) state->height = height;
 
327
                    if (state->bpc < bits) state->bpc = bits;
 
328
                }
 
329
            }
 
330
            if_debug3('w', "[w]jpxd decoding image at %ldx%ld"
 
331
                " with %d bits per component\n",
 
332
                state->width, state->height, state->bpc);
 
333
 
 
334
        }
 
335
 
 
336
        if (state->handle != (JP2_Decomp_Handle)NULL &&
 
337
                state->image == NULL) {
 
338
 
 
339
            /* allocate our output buffer */
 
340
            state->stride = state->width*state->ncomp;
 
341
            state->image = malloc(state->stride*state->height);
 
342
            if (state->image == NULL) return ERRC;
 
343
 
 
344
            /* attach our output callback */
 
345
            err = JP2_Decompress_SetProp(state->handle,
 
346
                cJP2_Prop_Output_Parameter, (JP2_Property_Value)state);
 
347
            if (err != cJP2_Error_OK) {
 
348
                dlprintf1("Luratech JP2 error %d setting output parameter\n", (int)err);
 
349
                return ERRC;
 
350
            }
 
351
            err = JP2_Decompress_SetProp(state->handle,
 
352
                cJP2_Prop_Output_Function,
 
353
                (JP2_Property_Value)s_jpxd_write_data);
 
354
            if (err != cJP2_Error_OK) {
 
355
                dlprintf1("Luratech JP2 error %d setting output function\n", (int)err);
 
356
                return ERRC;
 
357
            }
 
358
 
 
359
            /* decompress the image */
 
360
            err = JP2_Decompress_Image(state->handle);
 
361
            if (err != cJP2_Error_OK) {
 
362
                dlprintf1("Luratech JP2 error %d decoding image data\n", (int)err);
 
363
                return ERRC; /* parsing error */
 
364
            }
 
365
        }
 
366
 
 
367
        /* copy out available data */
 
368
        if (state->image != NULL && out_size > 0) {
 
369
            /* copy some output data */
 
370
            long available = min(out_size,
 
371
                state->stride*state->height - state->offset);
 
372
            memcpy(pw->ptr + 1, state->image + state->offset, available);
 
373
            state->offset += available;
 
374
            pw->ptr += available;
 
375
            /* more output to deliver? */
 
376
            if (state->offset == state->stride*state->height) return 1;
 
377
        }
 
378
    }
 
379
 
 
380
    /* ask for more data */
 
381
    return 0;
 
382
}
 
383
 
 
384
/* stream release.
 
385
   free all our decoder state.
 
386
 */
 
387
static void
 
388
s_jpxd_release(stream_state *ss)
 
389
{
 
390
    stream_jpxd_state *const state = (stream_jpxd_state *) ss;
 
391
    JP2_Error err;
 
392
 
 
393
    if (state) {
 
394
        err = JP2_Decompress_End(state->handle);
 
395
        if (state->inbuf) free(state->inbuf);
 
396
        if (state->image) free(state->image);
 
397
    }
 
398
}
 
399
 
 
400
/* stream template */
 
401
const stream_template s_jpxd_template = {
 
402
    &st_jpxd_state,
 
403
    s_jpxd_init,
 
404
    s_jpxd_process,
 
405
    1024, 1024,   /* min in and out buffer sizes we can handle
 
406
                     should be ~32k,64k for efficiency? */
 
407
    s_jpxd_release
 
408
};
 
409
 
 
410
 
 
411
 
 
412
/*** encode support **/
 
413
 
 
414
/* we provide a C-only encode filter for generating JPX image data
 
415
   for embedding in PDF. */
 
416
 
 
417
/* create a gc object for our state, defined in sjpx_luratech.h */
 
418
private_st_jpxe_state();
 
419
 
 
420
/* callback for uncompressed data input */
 
421
static JP2_Error JP2_Callback_Conv
 
422
s_jpxe_read(unsigned char *buffer, short component,
 
423
                unsigned long row, unsigned long start,
 
424
                unsigned long num, JP2_Callback_Param param)
 
425
{
 
426
    stream_jpxe_state *state = (stream_jpxe_state *)param;
 
427
    unsigned long available, sentinel;
 
428
    unsigned char *p;
 
429
    int i;
 
430
 
 
431
    if (component < 0 || component >= state->components) {
 
432
        dlprintf2("Luratech JP2 requested image data for unknown component %d of %u\n",
 
433
                (int)component, state->components);
 
434
        return cJP2_Error_Invalid_Component_Index;
 
435
    }
 
436
 
 
437
    /* todo: handle subsampled components and bpc != 8 */
 
438
 
 
439
    /* clip to array bounds */
 
440
    sentinel = row*state->stride + (start + num)*state->components;
 
441
    available = min(sentinel, state->infill);
 
442
    num = min(num, available / state->components);
 
443
 
 
444
    p = state->inbuf + state->stride*row + state->components*start;
 
445
    if (state->components == 1)
 
446
        memcpy(buffer, p, num);
 
447
    else for (i = 0; i < num; i++) {
 
448
        buffer[i] = p[component];
 
449
        p += state->components;
 
450
    }
 
451
 
 
452
    if (available < sentinel) return cJP2_Error_Failure_Read;
 
453
    else return cJP2_Error_OK;
 
454
}
 
455
 
 
456
/* callback for compressed data output */
 
457
static JP2_Error JP2_Callback_Conv
 
458
s_jpxe_write(unsigned char *buffer,
 
459
                unsigned long pos, unsigned long size,
 
460
                JP2_Callback_Param param)
 
461
{
 
462
    stream_jpxe_state *state = (stream_jpxe_state *)param;
 
463
 
 
464
    /* verify state */
 
465
    if (state == NULL) return cJP2_Error_Invalid_Pointer;
 
466
 
 
467
    /* allocate the output buffer if necessary */
 
468
    if (state->outbuf == NULL) {
 
469
        state->outbuf = malloc(JPX_BUFFER_SIZE);
 
470
        if (state->outbuf == NULL) {
 
471
            dprintf("jpx encode: failed to allocate output buffer.\n");
 
472
            return cJP2_Error_Failure_Malloc;
 
473
        }
 
474
        state->outsize = JPX_BUFFER_SIZE;
 
475
    }
 
476
 
 
477
    /* grow the output buffer if necessary */
 
478
    while (pos+size > state->outsize) {
 
479
        unsigned char *new = realloc(state->outbuf, state->outsize*2);
 
480
        if (new == NULL) {
 
481
            dprintf1("jpx encode: failed to resize output buffer"
 
482
                " beyond %lu bytes.\n", state->outsize);
 
483
            return cJP2_Error_Failure_Malloc;
 
484
        }
 
485
        state->outbuf = new;
 
486
        state->outsize *= 2;
 
487
        if_debug1('s', "[s] jpxe output buffer resized to %lu bytes\n",
 
488
                state->outsize);
 
489
    }
 
490
 
 
491
    /* copy data into our buffer; we've assured there is enough room. */
 
492
    memcpy(state->outbuf + pos, buffer, size);
 
493
    /* update high water mark */
 
494
    if (state->outfill < pos + size) state->outfill = pos + size;
 
495
 
 
496
    return cJP2_Error_OK;
 
497
}
 
498
 
 
499
/* set defaults for user-configurable parameters */
 
500
static void
 
501
s_jpxe_set_defaults(stream_state *ss)
 
502
{
 
503
    stream_jpxe_state *state = (stream_jpxe_state *)ss;
 
504
 
 
505
    /* most common default colorspace */
 
506
    state->colorspace = gs_jpx_cs_rgb;
 
507
 
 
508
    /* default to lossy 60% quality */
 
509
    state->lossless = 0;
 
510
    state->quality = 60;
 
511
}
 
512
 
 
513
/* initialize the stream */
 
514
static int
 
515
s_jpxe_init(stream_state *ss)
 
516
{
 
517
    stream_jpxe_state *state = (stream_jpxe_state *)ss;
 
518
    unsigned long value;
 
519
    JP2_Error err;
 
520
 
 
521
    /* width, height, bpc and colorspace are set by the client,
 
522
       calculate the rest */
 
523
    switch (state->colorspace) {
 
524
        case gs_jpx_cs_gray: state->components = 1; break;
 
525
        case gs_jpx_cs_rgb: state->components = 3; break;
 
526
        case gs_jpx_cs_cmyk: state->components = 4; break;
 
527
        default: state->components = 0;
 
528
    }
 
529
    state->stride = state->width * state->components;
 
530
 
 
531
    if_debug3('w', "[w] jpxe init %lux%lu image with %d components\n",
 
532
        state->width, state->height, state->components);
 
533
    if_debug1('w', "[w] jpxe init image is %d bits per component\n", state->bpc);
 
534
 
 
535
    if (state->lossless) {
 
536
        if_debug0('w', "[w] jpxe image using lossless encoding\n");
 
537
        state->quality = 100; /* implies lossless */
 
538
    } else {
 
539
        if_debug1('w', "[w] jpxe image quality level %d\n", state->quality);
 
540
    }
 
541
 
 
542
    /* null the input buffer */
 
543
    state->inbuf = NULL;
 
544
    state->insize = 0;
 
545
    state->infill = 0;
 
546
 
 
547
    /* null the output buffer */
 
548
    state->outbuf = NULL;
 
549
    state->outsize = 0;
 
550
    state->outfill = 0;
 
551
    state->offset = 0;
 
552
 
 
553
    /* initialize the encoder */
 
554
    err = JP2_Compress_Start(&state->handle,
 
555
        /* memory allocator callbacks */
 
556
        s_jpx_alloc, (JP2_Callback_Param)state,
 
557
        s_jpx_free,  (JP2_Callback_Param)state,
 
558
        state->components);
 
559
    if (err != cJP2_Error_OK) {
 
560
        dlprintf1("Luratech JP2 error %d starting compressor\n", (int)err);
 
561
        return ERRC;
 
562
    }
 
563
 
 
564
#if defined(JP2_LICENSE_NUM_1) && defined(JP2_LICENSE_NUM_2)
 
565
    /* set license keys if appropriate */
 
566
    error = JP2_Decompress_SetLicense(state->handle,
 
567
        JP2_LICENSE_NUM_1, JP2_LICENSE_NUM_2);
 
568
    if (error != cJP2_Error_OK) {
 
569
        dlprintf1("Luratech JP2 error %d setting license\n", (int)err);
 
570
        return ERRC;
 
571
    }
 
572
#endif
 
573
 
 
574
    /* install our callbacks */
 
575
    err = JP2_Compress_SetProp(state->handle,
 
576
        cJP2_Prop_Input_Parameter, (JP2_Property_Value)state, -1, -1);
 
577
    if (err != cJP2_Error_OK) {
 
578
        dlprintf1("Luratech JP2 error %d setting input callback parameter.\n", (int)err);
 
579
        return ERRC;
 
580
    }
 
581
    err = JP2_Compress_SetProp(state->handle,
 
582
        cJP2_Prop_Input_Function, (JP2_Property_Value)s_jpxe_read, -1, -1);
 
583
    if (err != cJP2_Error_OK) {
 
584
        dlprintf1("Luratech JP2 error %d setting input callback function.\n", (int)err);
 
585
        return ERRC;
 
586
    }
 
587
    err = JP2_Compress_SetProp(state->handle,
 
588
        cJP2_Prop_Write_Parameter, (JP2_Property_Value)state, -1, -1);
 
589
    if (err != cJP2_Error_OK) {
 
590
        dlprintf1("Luratech JP2 error %d setting compressed output callback parameter.\n", (int)err);
 
591
        return ERRC;
 
592
    }
 
593
    err = JP2_Compress_SetProp(state->handle,
 
594
        cJP2_Prop_Write_Function, (JP2_Property_Value)s_jpxe_write, -1, -1);
 
595
    if (err != cJP2_Error_OK) {
 
596
        dlprintf1("Luratech JP2 error %d setting compressed output callback function.\n", (int)err);
 
597
        return ERRC;
 
598
    }
 
599
 
 
600
    /* set image parameters - the same for all components */
 
601
    err = JP2_Compress_SetProp(state->handle,
 
602
        cJP2_Prop_Width, state->width, -1, -1);
 
603
    if (err != cJP2_Error_OK) {
 
604
        dlprintf1("Luratech JP2 error %d setting width\n", (int)err);
 
605
        return ERRC;
 
606
    }
 
607
    err = JP2_Compress_SetProp(state->handle,
 
608
        cJP2_Prop_Height, state->height, -1, -1);
 
609
    if (err != cJP2_Error_OK) {
 
610
        dlprintf1("Luratech JP2 error %d setting height\n", (int)err);
 
611
        return ERRC;
 
612
    }
 
613
    err = JP2_Compress_SetProp(state->handle,
 
614
        cJP2_Prop_Bits_Per_Sample, state->bpc, -1, -1);
 
615
    if (err != cJP2_Error_OK) {
 
616
        dlprintf1("Luratech JP2 error %d setting bits per sample\n", (int)err);
 
617
        return ERRC;
 
618
    }
 
619
 
 
620
    switch (state->colorspace) {
 
621
        case gs_jpx_cs_gray: value = cJP2_Colorspace_Gray; break;
 
622
        case gs_jpx_cs_rgb: value = cJP2_Colorspace_RGBa; break;
 
623
        case gs_jpx_cs_cmyk: value = cJP2_Colorspace_CMYKa; break;
 
624
        default:
 
625
            dlprintf1("Unknown colorspace %d initializing JP2 encoder\n",
 
626
                (int)state->colorspace);
 
627
            return ERRC;
 
628
    }
 
629
    err = JP2_Compress_SetProp(state->handle,
 
630
        cJP2_Prop_Extern_Colorspace, value, -1, -1);
 
631
    if (err != cJP2_Error_OK) {
 
632
        dlprintf1("Luratech JP2 error %d setting colorspace\n", (int)err);
 
633
        return ERRC;
 
634
    }
 
635
 
 
636
    if (state->lossless) {
 
637
        /* the default encoding mode is lossless */
 
638
        return 0;
 
639
    }
 
640
 
 
641
    /* otherwise, set 9,7 wavelets and quality-target mode */
 
642
    err = JP2_Compress_SetProp(state->handle,
 
643
        cJP2_Prop_Wavelet_Filter, cJP2_Wavelet_9_7, -1, -1);
 
644
    if (err != cJP2_Error_OK) {
 
645
        dlprintf1("Luratech JP2 error %d setting wavelet filter\n", (int)err);
 
646
        return ERRC;
 
647
    }
 
648
    err = JP2_Compress_SetProp(state->handle,
 
649
        cJP2_Prop_Rate_Quality, state->quality, -1, -1);
 
650
    if (err != cJP2_Error_OK) {
 
651
        dlprintf1("Luratech JP2 error %d setting compression quality\n", (int)err);
 
652
        return ERRC;
 
653
    }
 
654
 
 
655
    /* we use the encoder's defaults for all other parameters */
 
656
 
 
657
    return 0;
 
658
}
 
659
 
 
660
/* process input and return any encoded data.
 
661
   see strimpl.h for return codes. */
 
662
static int
 
663
s_jpxe_process(stream_state *ss, stream_cursor_read *pr,
 
664
                stream_cursor_write *pw, bool last)
 
665
{
 
666
    stream_jpxe_state *state = (stream_jpxe_state *)ss;
 
667
    long in_size = pr->limit - pr->ptr;
 
668
    long out_size = pw->limit - pw->ptr;
 
669
    long available;
 
670
    JP2_Error err;
 
671
 
 
672
    /* HACK -- reinstall our callbacks in case the GC has moved our state structure */
 
673
    /* this should be done instead from a pointer relocation callback, or initialization
 
674
       moved entirely inside the process routine. */
 
675
    err = JP2_Compress_SetProp(state->handle,
 
676
        cJP2_Prop_Input_Parameter, (JP2_Property_Value)state, -1, -1);
 
677
    if (err != cJP2_Error_OK) {
 
678
        dlprintf1("Luratech JP2 error %d setting input callback parameter.\n", (int)err);
 
679
        return ERRC;
 
680
    }
 
681
    err = JP2_Compress_SetProp(state->handle,
 
682
        cJP2_Prop_Write_Parameter, (JP2_Property_Value)state, -1, -1);
 
683
    if (err != cJP2_Error_OK) {
 
684
        dlprintf1("Luratech JP2 error %d setting compressed output callback parameter.\n", (int)err);
 
685
        return ERRC;
 
686
    }
 
687
 
 
688
 
 
689
    if (in_size > 0) {
 
690
        /* allocate our input buffer if necessary */
 
691
        if (state->inbuf == NULL) {
 
692
            state->inbuf = malloc(JPX_BUFFER_SIZE);
 
693
            if (state->inbuf == NULL) {
 
694
                dprintf("jpx encode: failed to allocate input buffer.\n");
 
695
                return ERRC;
 
696
            }
 
697
            state->insize = JPX_BUFFER_SIZE;
 
698
        }
 
699
 
 
700
        /* grow our input buffer if necessary */
 
701
        while (state->infill + in_size > state->insize) {
 
702
            unsigned char *new = realloc(state->inbuf, state->insize*2);
 
703
            if (new == NULL) {
 
704
                dprintf("jpx encode: failed to resize input buffer.\n");
 
705
                return ERRC;
 
706
            }
 
707
            state->inbuf = new;
 
708
            state->insize *= 2;
 
709
        }
 
710
 
 
711
        /* copy available input */
 
712
        memcpy(state->inbuf + state->infill, pr->ptr + 1, in_size);
 
713
        state->infill += in_size;
 
714
        pr->ptr += in_size;
 
715
    }
 
716
 
 
717
    if (last && state->outbuf == NULL) {
 
718
        /* We have all the data; call the compressor.
 
719
           our callback will automatically allocate the output buffer */
 
720
        if_debug0('w', "[w] jpxe process compressing image data\n");
 
721
        err = JP2_Compress_Image(state->handle);
 
722
        if (err != cJP2_Error_OK) {
 
723
            dlprintf1("Luratech JP2 error %d compressing image data.\n", (int)err);
 
724
            return ERRC;
 
725
        }
 
726
     }
 
727
 
 
728
     if (state->outbuf != NULL) {
 
729
        /* copy out any available output data */
 
730
        available = min(out_size, state->outfill - state->offset);
 
731
        memcpy(pw->ptr + 1, state->outbuf + state->offset, available);
 
732
        pw->ptr += available;
 
733
        state->offset += available;
 
734
 
 
735
        /* do we have any more data? */
 
736
        if (state->outfill - state->offset > 0) return 1;
 
737
        else return EOFC; /* all done */
 
738
    }
 
739
 
 
740
    /* something went wrong above */
 
741
    return last;
 
742
}
 
743
 
 
744
/* stream release. free all our state. */
 
745
static void
 
746
s_jpxe_release(stream_state *ss)
 
747
{
 
748
    stream_jpxe_state *state = (stream_jpxe_state *)ss;
 
749
    JP2_Error err;
 
750
 
 
751
    /* close the library compression context */
 
752
    err = JP2_Compress_End(state->handle);
 
753
    if (err != cJP2_Error_OK) {
 
754
        /* we can't return an error, so only print on debug builds */
 
755
        if_debug1('w', "[w]jpxe Luratech JP2 error %d"
 
756
                " closing compression context", (int)err);
 
757
    }
 
758
 
 
759
    /* free our own storage */
 
760
    free(state->outbuf);
 
761
    free(state->inbuf);
 
762
}
 
763
 
 
764
/* encoder stream template */
 
765
const stream_template s_jpxe_template = {
 
766
    &st_jpxe_state,
 
767
    s_jpxe_init,
 
768
    s_jpxe_process,
 
769
    1024, 1024, /* min in and out buffer sizes */
 
770
    s_jpxe_release,
 
771
    s_jpxe_set_defaults
 
772
};