1 /* save as jpeg2000
2 *
3 * 18/3/20
4 * - from jp2kload.c
5 */
6
7 /*
8
9 This file is part of VIPS.
10
11 VIPS is free software; you can redistribute it and/or modify
12 it under the terms of the GNU Lesser General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU Lesser General Public License for more details.
20
21 You should have received a copy of the GNU Lesser General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 02110-1301 USA
25
26 */
27
28 /*
29
30 These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
31
32 */
33
34 /*
35 #define DEBUG_VERBOSE
36 #define DEBUG
37 */
38
39 /* TODO
40 *
41 * - could support tiff-like depth parameter
42 *
43 * - could support png-like bitdepth parameter
44 *
45 * - could support cp_comment field? not very useful
46 *
47 */
48
49 #ifdef HAVE_CONFIG_H
50 #include <config.h>
51 #endif /*HAVE_CONFIG_H*/
52 #include <vips/intl.h>
53
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57
58 #include <vips/vips.h>
59 #include <vips/internal.h>
60
61 #ifdef HAVE_LIBOPENJP2
62
63 #include <openjpeg.h>
64
65 #include "pforeign.h"
66
67 /* Surely enough ... does anyone do multispectral imaging with jp2k?
68 */
69 #define MAX_BANDS (100)
70
71 typedef struct _VipsForeignSaveJp2k {
72 VipsForeignSave parent_object;
73
74 /* Where to write (set by subclasses).
75 */
76 VipsTarget *target;
77
78 int tile_width;
79 int tile_height;
80
81 /* Lossless mode.
82 */
83 gboolean lossless;
84
85 /* Quality factor.
86 */
87 int Q;
88
89 /* Chroma subsample mode.
90 */
91 VipsForeignSubsample subsample_mode;
92
93 /* Encoder state.
94 */
95 opj_stream_t *stream;
96 opj_codec_t *codec;
97 opj_cparameters_t parameters;
98 opj_image_t *image;
99
100 /* The line of tiles we are building, and the buffer we
101 * unpack to for output.
102 */
103 VipsRegion *strip;
104 VipsPel *tile_buffer;
105
106 /* If we need to subsample during unpacking.
107 */
108 gboolean subsample;
109
110 /* If we converto RGB to YCC during save.
111 */
112 gboolean save_as_ycc;
113
114 /* Accumulate a line of sums here during chroma subsample.
115 */
116 VipsPel *accumulate;
117 } VipsForeignSaveJp2k;
118
119 typedef VipsForeignSaveClass VipsForeignSaveJp2kClass;
120
121 G_DEFINE_ABSTRACT_TYPE( VipsForeignSaveJp2k, vips_foreign_save_jp2k,
122 VIPS_TYPE_FOREIGN_SAVE );
123
124 static void
vips_foreign_save_jp2k_dispose(GObject * gobject)125 vips_foreign_save_jp2k_dispose( GObject *gobject )
126 {
127 VipsForeignSaveJp2k *jp2k = (VipsForeignSaveJp2k *) gobject;
128
129 VIPS_FREEF( opj_destroy_codec, jp2k->codec );
130 VIPS_FREEF( opj_stream_destroy, jp2k->stream );
131 VIPS_FREEF( opj_image_destroy, jp2k->image );
132
133 VIPS_UNREF( jp2k->target );
134 VIPS_UNREF( jp2k->strip );
135
136 VIPS_FREE( jp2k->tile_buffer );
137 VIPS_FREE( jp2k->accumulate );
138
139 G_OBJECT_CLASS( vips_foreign_save_jp2k_parent_class )->
140 dispose( gobject );
141 }
142
143 static OPJ_SIZE_T
vips_foreign_save_jp2k_write_target(void * buffer,size_t length,void * client)144 vips_foreign_save_jp2k_write_target( void *buffer, size_t length, void *client )
145 {
146 VipsTarget *target = VIPS_TARGET( client );
147
148 if( vips_target_write( target, buffer, length ) )
149 return( 0 );
150
151 return( length );
152 }
153
154 /* Make a libopenjp2 output stream that wraps a VipsTarget.
155 */
156 static opj_stream_t *
vips_foreign_save_jp2k_target(VipsTarget * target)157 vips_foreign_save_jp2k_target( VipsTarget *target )
158 {
159 opj_stream_t *stream;
160
161 /* FALSE means a write stream.
162 */
163 if( !(stream = opj_stream_create( OPJ_J2K_STREAM_CHUNK_SIZE, FALSE )) )
164 return( NULL );
165
166 opj_stream_set_user_data( stream, target, NULL );
167 opj_stream_set_write_function( stream,
168 vips_foreign_save_jp2k_write_target );
169
170 return( stream );
171 }
172
173 static void
vips_foreign_save_jp2k_error_callback(const char * msg,void * client)174 vips_foreign_save_jp2k_error_callback( const char *msg, void *client )
175 {
176 vips_error( "jp2ksave", "%s", msg );
177 }
178
179 /* The openjpeg info and warning callbacks are incredibly chatty.
180 */
181 static void
vips_foreign_save_jp2k_warning_callback(const char * msg,void * client)182 vips_foreign_save_jp2k_warning_callback( const char *msg, void *client )
183 {
184 #ifdef DEBUG
185 g_warning( "jp2ksave: %s", msg );
186 #endif /*DEBUG*/
187 }
188
189 static void
vips_foreign_save_jp2k_info_callback(const char * msg,void * client)190 vips_foreign_save_jp2k_info_callback( const char *msg, void *client )
191 {
192 #ifdef DEBUG
193 g_info( "jp2ksave: %s", msg );
194 #endif /*DEBUG*/
195 }
196
197 static void
vips_foreign_save_jp2k_attach_handlers(opj_codec_t * codec)198 vips_foreign_save_jp2k_attach_handlers( opj_codec_t *codec )
199 {
200 opj_set_info_handler( codec,
201 vips_foreign_save_jp2k_info_callback, NULL );
202 opj_set_warning_handler( codec,
203 vips_foreign_save_jp2k_warning_callback, NULL );
204 opj_set_error_handler( codec,
205 vips_foreign_save_jp2k_error_callback, NULL );
206 }
207
208 /* See also https://en.wikipedia.org/wiki/YCbCr#JPEG_conversion
209 */
210 #define RGB_TO_YCC( TYPE ) { \
211 TYPE *tq = (TYPE *) q; \
212 \
213 for( x = 0; x < tile->width; x++ ) { \
214 int r = tq[0]; \
215 int g = tq[1]; \
216 int b = tq[2]; \
217 \
218 int y, cb, cr; \
219 \
220 y = 0.299 * r + 0.587 * g + 0.114 * b; \
221 tq[0] = VIPS_CLIP( 0, y, upb ); \
222 \
223 cb = offset - (int)(0.168736 * r + 0.331264 * g - 0.5 * b); \
224 tq[1] = VIPS_CLIP( 0, cb, upb ); \
225 \
226 cr = offset - (int)(-0.5 * r + 0.418688 * g + 0.081312 * b); \
227 tq[2] = VIPS_CLIP( 0, cr, upb ); \
228 \
229 tq += 3; \
230 } \
231 }
232
233 /* In-place RGB->YCC for a line of pels.
234 */
235 static void
vips_foreign_save_jp2k_rgb_to_ycc(VipsRegion * region,VipsRect * tile,int prec)236 vips_foreign_save_jp2k_rgb_to_ycc( VipsRegion *region,
237 VipsRect *tile, int prec )
238 {
239 VipsImage *im = region->im;
240 int offset = 1 << (prec - 1);
241 int upb = (1 << prec) - 1;
242
243 int x, y;
244
245 g_assert( im->Bands == 3 );
246
247 for( y = 0; y < tile->height; y++ ) {
248 VipsPel *q = VIPS_REGION_ADDR( region,
249 tile->left, tile->top + y );
250
251 switch( im->BandFmt ) {
252 case VIPS_FORMAT_CHAR:
253 case VIPS_FORMAT_UCHAR:
254 RGB_TO_YCC( unsigned char );
255 break;
256
257 case VIPS_FORMAT_SHORT:
258 case VIPS_FORMAT_USHORT:
259 RGB_TO_YCC( unsigned short );
260 break;
261
262 case VIPS_FORMAT_INT:
263 case VIPS_FORMAT_UINT:
264 RGB_TO_YCC( unsigned int );
265 break;
266
267 default:
268 g_assert_not_reached();
269 break;
270 }
271 }
272 }
273
274 /* Shrink in three stages:
275 * 1. copy the first line of input pels to acc
276 * 2. add subsequent lines in comp.dy.
277 * 3. horizontal average to output line
278 */
279 #define SHRINK( OUTPUT_TYPE, ACC_TYPE, PIXEL_TYPE ) { \
280 ACC_TYPE *acc = (ACC_TYPE *) accumulate; \
281 OUTPUT_TYPE *tq = (OUTPUT_TYPE *) q; \
282 const int n_pels = comp->dx * comp->dy; \
283 \
284 PIXEL_TYPE *tp; \
285 ACC_TYPE *ap; \
286 \
287 tp = (PIXEL_TYPE *) p; \
288 for( x = 0; x < tile->width; x++ ) { \
289 acc[x] = *tp; \
290 tp += n_bands; \
291 } \
292 \
293 for( z = 1; z < comp->dy; z++ ) { \
294 tp = (PIXEL_TYPE *) (p + z * lskip); \
295 for( x = 0; x < tile->width; x++ ) { \
296 acc[x] += *tp; \
297 tp += n_bands; \
298 } \
299 } \
300 \
301 ap = acc; \
302 for( x = 0; x < output_width; x++ ) { \
303 ACC_TYPE sum; \
304 \
305 sum = 0; \
306 for( z = 0; z < comp->dx; z++ ) \
307 sum += ap[z]; \
308 \
309 tq[x] = (sum + n_pels / 2) / n_pels; \
310 ap += comp->dx; \
311 } \
312 }
313
314 static void
vips_foreign_save_jp2k_unpack_subsample(VipsRegion * region,VipsRect * tile,opj_image_t * image,VipsPel * tile_buffer,VipsPel * accumulate)315 vips_foreign_save_jp2k_unpack_subsample( VipsRegion *region, VipsRect *tile,
316 opj_image_t *image, VipsPel *tile_buffer, VipsPel *accumulate )
317 {
318 VipsImage *im = region->im;
319 size_t sizeof_element = VIPS_REGION_SIZEOF_ELEMENT( region );
320 size_t lskip = VIPS_REGION_LSKIP( region );
321 int n_bands = im->Bands;
322
323 VipsPel *q;
324 int x, y, z, i;
325
326 q = tile_buffer;
327 for( i = 0; i < n_bands; i++ ) {
328 opj_image_comp_t *comp = &image->comps[i];
329
330 /* The number of pixels we write for this component. No
331 * padding.
332 */
333 int output_width = VIPS_ROUND_UINT(
334 (double) tile->width / comp->dx );
335 int output_height = VIPS_ROUND_UINT(
336 (double) tile->height / comp->dy );;
337
338 for( y = 0; y < output_height; y++ ) {
339 VipsPel *p = i * sizeof_element +
340 VIPS_REGION_ADDR( region,
341 tile->left, tile->top + y * comp->dy );
342
343 /* Shrink a line of pels to q.
344 */
345 switch( im->BandFmt ) {
346 case VIPS_FORMAT_CHAR:
347 SHRINK( signed char, int, signed char );
348 break;
349
350 case VIPS_FORMAT_UCHAR:
351 SHRINK( unsigned char, int, unsigned char );
352 break;
353
354 case VIPS_FORMAT_SHORT:
355 SHRINK( signed short, int, signed short );
356 break;
357
358 case VIPS_FORMAT_USHORT:
359 SHRINK( unsigned short, int, unsigned short );
360 break;
361
362 case VIPS_FORMAT_INT:
363 SHRINK( signed int, gint64, signed int );
364 break;
365
366 case VIPS_FORMAT_UINT:
367 SHRINK( unsigned int, gint64, unsigned int );
368 break;
369
370 default:
371 g_assert_not_reached();
372 break;
373 }
374
375 q += sizeof_element * output_width;
376 }
377 }
378 }
379
380 #define UNPACK( OUT, IN ) { \
381 OUT *tq = (OUT *) q; \
382 IN *tp = (IN *) p + i; \
383 \
384 for( x = 0; x < tile->width; x++ ) { \
385 tq[x] = *tp; \
386 tp += b; \
387 } \
388 }
389
390 static void
vips_foreign_save_jp2k_unpack(VipsRegion * region,VipsRect * tile,opj_image_t * image,VipsPel * tile_buffer)391 vips_foreign_save_jp2k_unpack( VipsRegion *region, VipsRect *tile,
392 opj_image_t *image, VipsPel *tile_buffer )
393 {
394 VipsImage *im = region->im;
395 size_t sizeof_element = VIPS_REGION_SIZEOF_ELEMENT( region );
396 size_t sizeof_line = sizeof_element * tile->width;
397 size_t sizeof_tile = sizeof_line * tile->height;
398 int b = im->Bands;
399
400 int x, y, i;
401
402 for( y = 0; y < tile->height; y++ ) {
403 VipsPel *p = VIPS_REGION_ADDR( region,
404 tile->left, tile->top + y );
405
406 for( i = 0; i < b; i++ ) {
407 VipsPel *q = tile_buffer +
408 i * sizeof_tile + y * sizeof_line;
409
410 switch( im->BandFmt ) {
411 case VIPS_FORMAT_CHAR:
412 case VIPS_FORMAT_UCHAR:
413 UNPACK( unsigned char, unsigned char );
414 break;
415
416 case VIPS_FORMAT_SHORT:
417 case VIPS_FORMAT_USHORT:
418 UNPACK( unsigned short, unsigned short );
419 break;
420
421 case VIPS_FORMAT_INT:
422 case VIPS_FORMAT_UINT:
423 UNPACK( unsigned int, unsigned int );
424 break;
425
426 default:
427 g_assert_not_reached();
428 break;
429 }
430 }
431 }
432 }
433
434 static size_t
vips_foreign_save_jp2k_sizeof_tile(VipsForeignSaveJp2k * jp2k,VipsRect * tile)435 vips_foreign_save_jp2k_sizeof_tile( VipsForeignSaveJp2k *jp2k, VipsRect *tile )
436 {
437 VipsForeignSave *save = (VipsForeignSave *) jp2k;
438 size_t sizeof_element = VIPS_IMAGE_SIZEOF_ELEMENT( save->ready );
439
440 size_t size;
441 int i;
442
443 size = 0;
444 for( i = 0; i < jp2k->image->numcomps; i++ ) {
445 opj_image_comp_t *comp = &jp2k->image->comps[i];
446
447 /* The number of pixels we write for this component. Round to
448 * nearest, and we may have to write half-pixels at the edges.
449 */
450 int output_width = VIPS_ROUND_UINT(
451 (double) tile->width / comp->dx );
452 int output_height = VIPS_ROUND_UINT(
453 (double) tile->height / comp->dy );;
454
455 size += output_width * output_height * sizeof_element;
456 }
457
458 return( size );
459 }
460
461 static int
vips_foreign_save_jp2k_write_tiles(VipsForeignSaveJp2k * jp2k)462 vips_foreign_save_jp2k_write_tiles( VipsForeignSaveJp2k *jp2k )
463 {
464 VipsForeignSave *save = (VipsForeignSave *) jp2k;
465 VipsImage *im = save->ready;
466 int tiles_across = VIPS_ROUND_UP( im->Xsize, jp2k->tile_width ) /
467 jp2k->tile_width;
468
469 int x;
470
471 for( x = 0; x < im->Xsize; x += jp2k->tile_width ) {
472 VipsRect tile;
473 size_t sizeof_tile;
474 int tile_index;
475
476 tile.left = x;
477 tile.top = jp2k->strip->valid.top;
478 tile.width = jp2k->tile_width;
479 tile.height = jp2k->tile_height;
480 vips_rect_intersectrect( &tile, &jp2k->strip->valid, &tile );
481
482 if( jp2k->save_as_ycc )
483 vips_foreign_save_jp2k_rgb_to_ycc( jp2k->strip,
484 &tile, jp2k->image->comps[0].prec );
485
486 if( jp2k->subsample )
487 vips_foreign_save_jp2k_unpack_subsample( jp2k->strip,
488 &tile, jp2k->image,
489 jp2k->tile_buffer, jp2k->accumulate );
490 else
491 vips_foreign_save_jp2k_unpack( jp2k->strip,
492 &tile, jp2k->image,
493 jp2k->tile_buffer );
494
495 sizeof_tile =
496 vips_foreign_save_jp2k_sizeof_tile( jp2k, &tile );
497 tile_index = tiles_across * tile.top / jp2k->tile_height +
498 x / jp2k->tile_width;
499 if( !opj_write_tile( jp2k->codec, tile_index,
500 (VipsPel *) jp2k->tile_buffer, sizeof_tile,
501 jp2k->stream ) )
502 return( -1 );
503 }
504
505 return( 0 );
506 }
507
508 static int
vips_foreign_save_jp2k_write_block(VipsRegion * region,VipsRect * area,void * a)509 vips_foreign_save_jp2k_write_block( VipsRegion *region, VipsRect *area,
510 void *a )
511 {
512 VipsForeignSaveJp2k *jp2k = (VipsForeignSaveJp2k *) a;
513 VipsForeignSave *save = (VipsForeignSave *) jp2k;
514
515 #ifdef DEBUG_VERBOSE
516 printf( "vips_foreign_save_jp2k_write_block: y = %d, nlines = %d\n",
517 area->top, area->height );
518 #endif /*DEBUG_VERBOSE*/
519
520 for(;;) {
521 VipsRect hit;
522 int y;
523 VipsRect strip_position;
524
525 /* The intersection with the strip is the fresh pixels we
526 * have.
527 */
528 vips_rect_intersectrect( area, &(jp2k->strip->valid), &hit );
529
530 /* Copy the new pixels into the strip.
531 */
532 for( y = 0; y < hit.height; y++ ) {
533 VipsPel *p = VIPS_REGION_ADDR( region,
534 0, hit.top + y );
535 VipsPel *q = VIPS_REGION_ADDR( jp2k->strip,
536 0, hit.top + y );
537
538 memcpy( q, p, VIPS_IMAGE_SIZEOF_LINE( region->im ) );
539 }
540
541 /* Have we failed to reach the bottom of the strip? We must
542 * have run out of fresh pixels, so we are done.
543 */
544 if( VIPS_RECT_BOTTOM( &hit ) !=
545 VIPS_RECT_BOTTOM( &jp2k->strip->valid ) )
546 break;
547
548 /* We have reached the bottom of the strip. Write this line of
549 * pixels and move the strip down.
550 */
551 if( vips_foreign_save_jp2k_write_tiles( jp2k ) )
552 return( -1 );
553
554 strip_position.left = 0;
555 strip_position.top = jp2k->strip->valid.top + jp2k->tile_height;
556 strip_position.width = save->ready->Xsize;
557 strip_position.height = jp2k->tile_height;
558 if( vips_region_buffer( jp2k->strip, &strip_position ) )
559 return( -1 );
560 }
561
562 return( 0 );
563 }
564
565 /* We can't call opj_calloc on win, sadly.
566 */
567 #define VIPS_OPJ_CALLOC( N, TYPE ) \
568 ((TYPE *) calloc( (N), sizeof( TYPE ) ))
569
570 /* Allocate an openjpeg image structure. Openjpeg has opj_image_create(), but
571 * that always allocates memory for each channel, and we don't want that when
572 * we are doing tiled write.
573 */
574 static opj_image_t *
vips_opj_image_create(OPJ_UINT32 numcmpts,opj_image_cmptparm_t * cmptparms,OPJ_COLOR_SPACE clrspc,gboolean allocate)575 vips_opj_image_create( OPJ_UINT32 numcmpts,
576 opj_image_cmptparm_t *cmptparms, OPJ_COLOR_SPACE clrspc,
577 gboolean allocate )
578 {
579 OPJ_UINT32 compno;
580 opj_image_t *image = NULL;
581
582 if( !(image = VIPS_OPJ_CALLOC( 1, opj_image_t )) )
583 return( NULL );
584
585 image->color_space = clrspc;
586 image->numcomps = numcmpts;
587 image->comps = VIPS_OPJ_CALLOC( image->numcomps, opj_image_comp_t );
588 if( !image->comps ) {
589 opj_image_destroy( image );
590 return( NULL );
591 }
592
593 for( compno = 0; compno < numcmpts; compno++ ) {
594 opj_image_comp_t *comp = &image->comps[compno];
595
596 comp->dx = cmptparms[compno].dx;
597 comp->dy = cmptparms[compno].dy;
598 comp->w = cmptparms[compno].w;
599 comp->h = cmptparms[compno].h;
600 comp->x0 = cmptparms[compno].x0;
601 comp->y0 = cmptparms[compno].y0;
602 comp->prec = cmptparms[compno].prec;
603 comp->bpp = cmptparms[compno].bpp;
604 comp->sgnd = cmptparms[compno].sgnd;
605
606 if( comp->h != 0 &&
607 (OPJ_SIZE_T) comp->w > SIZE_MAX / comp->h /
608 sizeof( OPJ_INT32 ) ) {
609 opj_image_destroy( image );
610 return( NULL );
611 }
612
613 /* Allocation is optional.
614 */
615 if( allocate ) {
616 size_t bytes = (size_t) comp->w * comp->h *
617 sizeof( OPJ_INT32 );
618
619 comp->data = (OPJ_INT32*) opj_image_data_alloc( bytes );
620 if( !comp->data ) {
621 opj_image_destroy( image );
622 return NULL;
623 }
624 memset( comp->data, 0, bytes );
625 }
626 }
627
628 return( image );
629 }
630
631 static opj_image_t *
vips_foreign_save_jp2k_new_image(VipsImage * im,int width,int height,gboolean subsample,gboolean save_as_ycc,gboolean allocate)632 vips_foreign_save_jp2k_new_image( VipsImage *im,
633 int width, int height,
634 gboolean subsample, gboolean save_as_ycc, gboolean allocate )
635 {
636 OPJ_COLOR_SPACE color_space;
637 int expected_bands;
638 int bits_per_pixel;
639 opj_image_cmptparm_t comps[MAX_BANDS];
640 opj_image_t *image;
641 int i;
642
643 if( im->Bands > MAX_BANDS )
644 return( NULL );
645
646 /* CIELAB etc. do not seem to be well documented.
647 */
648 switch( im->Type ) {
649 case VIPS_INTERPRETATION_B_W:
650 case VIPS_INTERPRETATION_GREY16:
651 color_space = OPJ_CLRSPC_GRAY;
652 expected_bands = 1;
653 break;
654
655 case VIPS_INTERPRETATION_sRGB:
656 case VIPS_INTERPRETATION_RGB16:
657 color_space = save_as_ycc ? OPJ_CLRSPC_SYCC : OPJ_CLRSPC_SRGB;
658 expected_bands = 3;
659 break;
660
661 case VIPS_INTERPRETATION_CMYK:
662 color_space = OPJ_CLRSPC_CMYK;
663 expected_bands = 4;
664 break;
665
666 default:
667 color_space = OPJ_CLRSPC_UNSPECIFIED;
668 expected_bands = im->Bands;
669 break;
670 }
671
672 switch( im->BandFmt ) {
673 case VIPS_FORMAT_CHAR:
674 case VIPS_FORMAT_UCHAR:
675 bits_per_pixel = 8;
676 break;
677
678 case VIPS_FORMAT_SHORT:
679 case VIPS_FORMAT_USHORT:
680 bits_per_pixel = 16;
681 break;
682
683 case VIPS_FORMAT_INT:
684 case VIPS_FORMAT_UINT:
685 /* OpenJPEG only supports up to 31.
686 */
687 bits_per_pixel = 31;
688 break;
689
690 default:
691 g_assert_not_reached();
692 break;
693 }
694
695 for( i = 0; i < im->Bands; i++ ) {
696 comps[i].dx = (subsample && i > 0) ? 2 : 1;
697 comps[i].dy = (subsample && i > 0) ? 2 : 1;
698 comps[i].w = width;
699 comps[i].h = height;
700 comps[i].x0 = 0;
701 comps[i].y0 = 0;
702 comps[i].prec = bits_per_pixel;
703 comps[i].bpp = bits_per_pixel;
704 comps[i].sgnd = !vips_band_format_isuint( im->BandFmt );
705 }
706
707 image = vips_opj_image_create( im->Bands, comps, color_space,
708 allocate );
709 image->x1 = width;
710 image->y1 = height;
711
712 /* Tag alpha channels.
713 */
714 for( i = 0; i < im->Bands; i++ )
715 image->comps[i].alpha = i >= expected_bands;
716
717 return( image );
718 }
719
720 /* Compression profile derived from the BM's recommenadations, see:
721 *
722 * https://purl.pt/24107/1/iPres2013_PDF/An%20Analysis%20of%20Contemporary%20JPEG2000%20Codecs%20for%20Image%20Format%20Migration.pdf
723 *
724 * Some of these settings (eg. numresolution) are overridden later.
725 */
726 static void
vips_foreign_save_jp2k_set_profile(opj_cparameters_t * parameters,gboolean lossless,int Q)727 vips_foreign_save_jp2k_set_profile( opj_cparameters_t *parameters,
728 gboolean lossless, int Q )
729 {
730 if( lossless )
731 parameters->irreversible = FALSE;
732 else {
733 int i;
734
735 /* Equivalent command-line flags:
736 *
737 * -I -p RPCL -n 7 \
738 * -c[256,256],[256,256],[256,256],[256,256],[256,256],[256,256],[256,256] \
739 * -b 64,64
740 */
741
742 parameters->irreversible = TRUE;
743 parameters->prog_order = OPJ_RPCL;
744 parameters->cblockw_init = 64;
745 parameters->cblockh_init = 64;
746 parameters->cp_disto_alloc = 1;
747 parameters->cp_fixed_quality = TRUE;
748 parameters->tcp_numlayers = 1;
749 parameters->numresolution = 7;
750
751 /* No idea what this does, but opj_compress sets it.
752 */
753 parameters->csty = 1;
754
755 parameters->res_spec = 7;
756 for( i = 0; i < parameters->res_spec; i++ ) {
757 parameters->prch_init[i] = 256;
758 parameters->prcw_init[i] = 256;
759 parameters->tcp_distoratio[i] = Q + 10 * i;
760 }
761 }
762 }
763
764 static int
vips_foreign_save_jp2k_build(VipsObject * object)765 vips_foreign_save_jp2k_build( VipsObject *object )
766 {
767 VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
768 VipsForeignSave *save = (VipsForeignSave *) object;
769 VipsForeignSaveJp2k *jp2k = (VipsForeignSaveJp2k *) object;
770
771 size_t sizeof_tile;
772 size_t sizeof_line;
773 VipsRect strip_position;
774
775 if( VIPS_OBJECT_CLASS( vips_foreign_save_jp2k_parent_class )->
776 build( object ) )
777 return( -1 );
778
779 /* Analyze our arguments.
780 */
781
782 if( !vips_band_format_isint( save->ready->BandFmt ) ) {
783 vips_error( class->nickname,
784 "%s", _( "not an integer format" ) );
785 return( -1 );
786 }
787
788 switch( jp2k->subsample_mode ) {
789 case VIPS_FOREIGN_SUBSAMPLE_AUTO:
790 jp2k->subsample =
791 !jp2k->lossless &&
792 jp2k->Q < 90 &&
793 save->ready->Xsize % 2 == 0 &&
794 save->ready->Ysize % 2 == 0 &&
795 (save->ready->Type == VIPS_INTERPRETATION_sRGB ||
796 save->ready->Type == VIPS_INTERPRETATION_RGB16) &&
797 save->ready->Bands == 3;
798 break;
799
800 case VIPS_FOREIGN_SUBSAMPLE_ON:
801 jp2k->subsample = TRUE;
802 break;
803
804 case VIPS_FOREIGN_SUBSAMPLE_OFF:
805 jp2k->subsample = FALSE;
806 break;
807
808 default:
809 g_assert_not_reached();
810 break;
811 }
812
813 if( jp2k->subsample )
814 jp2k->save_as_ycc = TRUE;
815
816 /* Set parameters for compressor.
817 */
818 opj_set_default_encoder_parameters( &jp2k->parameters );
819
820 /* Set compression profile.
821 */
822 vips_foreign_save_jp2k_set_profile( &jp2k->parameters,
823 jp2k->lossless, jp2k->Q );
824
825 /* Always tile.
826 */
827 jp2k->parameters.tile_size_on = OPJ_TRUE;
828 jp2k->parameters.cp_tdx = jp2k->tile_width;
829 jp2k->parameters.cp_tdy = jp2k->tile_height;
830
831 /* Makes many-band, non-subsampled images smaller, somehow.
832 */
833 jp2k->parameters.tcp_mct = save->ready->Bands >= 3 && !jp2k->subsample;
834
835 /* Number of layers to write. Smallest layer is c. 2^5 on the smallest
836 * axis.
837 */
838 jp2k->parameters.numresolution = VIPS_MAX( 1,
839 log( VIPS_MIN( save->ready->Xsize, save->ready->Ysize ) ) /
840 log( 2 ) - 5 );
841 #ifdef DEBUG
842 printf( "vips_foreign_save_jp2k_build: numresolutions = %d\n",
843 jp2k->parameters.numresolution );
844 #endif /*DEBUG*/
845
846 /* Set up compressor.
847 */
848
849 jp2k->codec = opj_create_compress( OPJ_CODEC_J2K );
850 vips_foreign_save_jp2k_attach_handlers( jp2k->codec );
851 /* FALSE means don't alloc memory for image planes (we write in
852 * tiles, not whole images).
853 */
854 if( !(jp2k->image = vips_foreign_save_jp2k_new_image( save->ready,
855 save->ready->Xsize, save->ready->Ysize,
856 jp2k->subsample, jp2k->save_as_ycc, FALSE )) )
857 return( -1 );
858 if( !opj_setup_encoder( jp2k->codec, &jp2k->parameters, jp2k->image ) )
859 return( -1 );
860
861 opj_codec_set_threads( jp2k->codec, vips_concurrency_get() );
862
863 if( !(jp2k->stream = vips_foreign_save_jp2k_target( jp2k->target )) )
864 return( -1 );
865
866 if( !opj_start_compress( jp2k->codec, jp2k->image, jp2k->stream ) )
867 return( -1 );
868
869 /* The buffer we repack tiles to for write. Large enough for one
870 * complete tile.
871 */
872 sizeof_tile = VIPS_IMAGE_SIZEOF_PEL( save->ready ) *
873 jp2k->tile_width * jp2k->tile_height;
874 if( !(jp2k->tile_buffer = VIPS_ARRAY( NULL, sizeof_tile, VipsPel )) )
875 return( -1 );
876
877 /* We need a line of sums for chroma subsample. At worst, gint64.
878 */
879 sizeof_line = sizeof( gint64 ) * jp2k->tile_width;
880 if( !(jp2k->accumulate = VIPS_ARRAY( NULL, sizeof_line, VipsPel )) )
881 return( -1 );
882
883 /* The line of tiles we are building. It's used by the bg thread, so
884 * no ownership.
885 */
886 jp2k->strip = vips_region_new( save->ready );
887 vips__region_no_ownership( jp2k->strip );
888
889 /* Position strip at the top of the image, the height of a row of
890 * tiles.
891 */
892 strip_position.left = 0;
893 strip_position.top = 0;
894 strip_position.width = save->ready->Xsize;
895 strip_position.height = jp2k->tile_height;
896 if( vips_region_buffer( jp2k->strip, &strip_position ) )
897 return( -1 );
898
899 /* Write data.
900 */
901 if( vips_sink_disc( save->ready,
902 vips_foreign_save_jp2k_write_block, jp2k ) )
903 return( -1 );
904
905 opj_end_compress( jp2k->codec, jp2k->stream );
906
907 vips_target_finish( jp2k->target );
908
909 return( 0 );
910 }
911
912 static void
vips_foreign_save_jp2k_class_init(VipsForeignSaveJp2kClass * class)913 vips_foreign_save_jp2k_class_init( VipsForeignSaveJp2kClass *class )
914 {
915 GObjectClass *gobject_class = G_OBJECT_CLASS( class );
916 VipsObjectClass *object_class = (VipsObjectClass *) class;
917 VipsForeignClass *foreign_class = (VipsForeignClass *) class;
918 VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class;
919
920 gobject_class->dispose = vips_foreign_save_jp2k_dispose;
921 gobject_class->set_property = vips_object_set_property;
922 gobject_class->get_property = vips_object_get_property;
923
924 object_class->nickname = "jp2ksave_base";
925 object_class->description = _( "save image in JPEG2000 format" );
926 object_class->build = vips_foreign_save_jp2k_build;
927
928 foreign_class->suffs = vips__jp2k_suffs;
929
930 save_class->saveable = VIPS_SAVEABLE_ANY;
931
932 VIPS_ARG_INT( class, "tile_width", 11,
933 _( "Tile width" ),
934 _( "Tile width in pixels" ),
935 VIPS_ARGUMENT_OPTIONAL_INPUT,
936 G_STRUCT_OFFSET( VipsForeignSaveJp2k, tile_width ),
937 1, 32768, 512 );
938
939 VIPS_ARG_INT( class, "tile_height", 12,
940 _( "Tile height" ),
941 _( "Tile height in pixels" ),
942 VIPS_ARGUMENT_OPTIONAL_INPUT,
943 G_STRUCT_OFFSET( VipsForeignSaveJp2k, tile_height ),
944 1, 32768, 512 );
945
946 VIPS_ARG_BOOL( class, "lossless", 13,
947 _( "Lossless" ),
948 _( "Enable lossless compression" ),
949 VIPS_ARGUMENT_OPTIONAL_INPUT,
950 G_STRUCT_OFFSET( VipsForeignSaveJp2k, lossless ),
951 FALSE );
952
953 VIPS_ARG_ENUM( class, "subsample_mode", 19,
954 _( "Subsample mode" ),
955 _( "Select chroma subsample operation mode" ),
956 VIPS_ARGUMENT_OPTIONAL_INPUT,
957 G_STRUCT_OFFSET( VipsForeignSaveJp2k, subsample_mode ),
958 VIPS_TYPE_FOREIGN_SUBSAMPLE,
959 VIPS_FOREIGN_SUBSAMPLE_AUTO );
960
961 VIPS_ARG_INT( class, "Q", 14,
962 _( "Q" ),
963 _( "Q factor" ),
964 VIPS_ARGUMENT_OPTIONAL_INPUT,
965 G_STRUCT_OFFSET( VipsForeignSaveJp2k, Q ),
966 1, 100, 48 );
967
968 }
969
970 static void
vips_foreign_save_jp2k_init(VipsForeignSaveJp2k * jp2k)971 vips_foreign_save_jp2k_init( VipsForeignSaveJp2k *jp2k )
972 {
973 jp2k->tile_width = 512;
974 jp2k->tile_height = 512;
975
976 /* Chosen to give about the same filesize as regular jpg Q75.
977 */
978 jp2k->Q = 48;
979
980 jp2k->subsample_mode = VIPS_FOREIGN_SUBSAMPLE_AUTO;
981 }
982
983 typedef struct _VipsForeignSaveJp2kFile {
984 VipsForeignSaveJp2k parent_object;
985
986 /* Filename for save.
987 */
988 char *filename;
989
990 } VipsForeignSaveJp2kFile;
991
992 typedef VipsForeignSaveJp2kClass VipsForeignSaveJp2kFileClass;
993
994 G_DEFINE_TYPE( VipsForeignSaveJp2kFile, vips_foreign_save_jp2k_file,
995 vips_foreign_save_jp2k_get_type() );
996
997 static int
vips_foreign_save_jp2k_file_build(VipsObject * object)998 vips_foreign_save_jp2k_file_build( VipsObject *object )
999 {
1000 VipsForeignSaveJp2k *jp2k = (VipsForeignSaveJp2k *) object;
1001 VipsForeignSaveJp2kFile *file = (VipsForeignSaveJp2kFile *) object;
1002
1003 if( !(jp2k->target = vips_target_new_to_file( file->filename )) )
1004 return( -1 );
1005
1006 if( VIPS_OBJECT_CLASS( vips_foreign_save_jp2k_file_parent_class )->
1007 build( object ) )
1008 return( -1 );
1009
1010 return( 0 );
1011 }
1012
1013 static void
vips_foreign_save_jp2k_file_class_init(VipsForeignSaveJp2kFileClass * class)1014 vips_foreign_save_jp2k_file_class_init( VipsForeignSaveJp2kFileClass *class )
1015 {
1016 GObjectClass *gobject_class = G_OBJECT_CLASS( class );
1017 VipsObjectClass *object_class = (VipsObjectClass *) class;
1018
1019 gobject_class->set_property = vips_object_set_property;
1020 gobject_class->get_property = vips_object_get_property;
1021
1022 object_class->nickname = "jp2ksave";
1023 object_class->build = vips_foreign_save_jp2k_file_build;
1024
1025 VIPS_ARG_STRING( class, "filename", 1,
1026 _( "Filename" ),
1027 _( "Filename to load from" ),
1028 VIPS_ARGUMENT_REQUIRED_INPUT,
1029 G_STRUCT_OFFSET( VipsForeignSaveJp2kFile, filename ),
1030 NULL );
1031
1032 }
1033
1034 static void
vips_foreign_save_jp2k_file_init(VipsForeignSaveJp2kFile * file)1035 vips_foreign_save_jp2k_file_init( VipsForeignSaveJp2kFile *file )
1036 {
1037 }
1038
1039 typedef struct _VipsForeignSaveJp2kBuffer {
1040 VipsForeignSaveJp2k parent_object;
1041
1042 /* Save to a buffer.
1043 */
1044 VipsArea *buf;
1045
1046 } VipsForeignSaveJp2kBuffer;
1047
1048 typedef VipsForeignSaveJp2kClass VipsForeignSaveJp2kBufferClass;
1049
1050 G_DEFINE_TYPE( VipsForeignSaveJp2kBuffer, vips_foreign_save_jp2k_buffer,
1051 vips_foreign_save_jp2k_get_type() );
1052
1053 static int
vips_foreign_save_jp2k_buffer_build(VipsObject * object)1054 vips_foreign_save_jp2k_buffer_build( VipsObject *object )
1055 {
1056 VipsForeignSaveJp2k *jp2k = (VipsForeignSaveJp2k *) object;
1057 VipsForeignSaveJp2kBuffer *buffer =
1058 (VipsForeignSaveJp2kBuffer *) object;
1059
1060 VipsBlob *blob;
1061
1062 if( !(jp2k->target = vips_target_new_to_memory()) )
1063 return( -1 );
1064
1065 if( VIPS_OBJECT_CLASS( vips_foreign_save_jp2k_buffer_parent_class )->
1066 build( object ) )
1067 return( -1 );
1068
1069 g_object_get( jp2k->target, "blob", &blob, NULL );
1070 g_object_set( buffer, "buffer", blob, NULL );
1071 vips_area_unref( VIPS_AREA( blob ) );
1072
1073 return( 0 );
1074 }
1075
1076 static void
vips_foreign_save_jp2k_buffer_class_init(VipsForeignSaveJp2kBufferClass * class)1077 vips_foreign_save_jp2k_buffer_class_init(
1078 VipsForeignSaveJp2kBufferClass *class )
1079 {
1080 GObjectClass *gobject_class = G_OBJECT_CLASS( class );
1081 VipsObjectClass *object_class = (VipsObjectClass *) class;
1082
1083 gobject_class->set_property = vips_object_set_property;
1084 gobject_class->get_property = vips_object_get_property;
1085
1086 object_class->nickname = "jp2ksave_buffer";
1087 object_class->build = vips_foreign_save_jp2k_buffer_build;
1088
1089 VIPS_ARG_BOXED( class, "buffer", 1,
1090 _( "Buffer" ),
1091 _( "Buffer to save to" ),
1092 VIPS_ARGUMENT_REQUIRED_OUTPUT,
1093 G_STRUCT_OFFSET( VipsForeignSaveJp2kBuffer, buf ),
1094 VIPS_TYPE_BLOB );
1095
1096 }
1097
1098 static void
vips_foreign_save_jp2k_buffer_init(VipsForeignSaveJp2kBuffer * buffer)1099 vips_foreign_save_jp2k_buffer_init( VipsForeignSaveJp2kBuffer *buffer )
1100 {
1101 }
1102
1103 typedef struct _VipsForeignSaveJp2kTarget {
1104 VipsForeignSaveJp2k parent_object;
1105
1106 VipsTarget *target;
1107 } VipsForeignSaveJp2kTarget;
1108
1109 typedef VipsForeignSaveJp2kClass VipsForeignSaveJp2kTargetClass;
1110
1111 G_DEFINE_TYPE( VipsForeignSaveJp2kTarget, vips_foreign_save_jp2k_target,
1112 vips_foreign_save_jp2k_get_type() );
1113
1114 static int
vips_foreign_save_jp2k_target_build(VipsObject * object)1115 vips_foreign_save_jp2k_target_build( VipsObject *object )
1116 {
1117 VipsForeignSaveJp2k *jp2k = (VipsForeignSaveJp2k *) object;
1118 VipsForeignSaveJp2kTarget *target =
1119 (VipsForeignSaveJp2kTarget *) object;
1120
1121 if( target->target ) {
1122 jp2k->target = target->target;
1123 g_object_ref( jp2k->target );
1124 }
1125
1126 if( VIPS_OBJECT_CLASS( vips_foreign_save_jp2k_target_parent_class )->
1127 build( object ) )
1128 return( -1 );
1129
1130 return( 0 );
1131 }
1132
1133 static void
vips_foreign_save_jp2k_target_class_init(VipsForeignSaveJp2kTargetClass * class)1134 vips_foreign_save_jp2k_target_class_init(
1135 VipsForeignSaveJp2kTargetClass *class )
1136 {
1137 GObjectClass *gobject_class = G_OBJECT_CLASS( class );
1138 VipsObjectClass *object_class = (VipsObjectClass *) class;
1139
1140 gobject_class->set_property = vips_object_set_property;
1141 gobject_class->get_property = vips_object_get_property;
1142
1143 object_class->nickname = "jp2ksave_target";
1144 object_class->build = vips_foreign_save_jp2k_target_build;
1145
1146 VIPS_ARG_OBJECT( class, "target", 1,
1147 _( "Target" ),
1148 _( "Target to save to" ),
1149 VIPS_ARGUMENT_REQUIRED_INPUT,
1150 G_STRUCT_OFFSET( VipsForeignSaveJp2kTarget, target ),
1151 VIPS_TYPE_TARGET );
1152
1153 }
1154
1155 static void
vips_foreign_save_jp2k_target_init(VipsForeignSaveJp2kTarget * target)1156 vips_foreign_save_jp2k_target_init( VipsForeignSaveJp2kTarget *target )
1157 {
1158 }
1159
1160 /* Stuff we track during tile compress.
1161 */
1162 typedef struct _TileCompress {
1163 opj_codec_t *codec;
1164 opj_image_t *image;
1165 opj_stream_t *stream;
1166 VipsPel *accumulate;
1167 } TileCompress;
1168
1169 /* Unpack from @tile within @region to the int data pointers on @image with
1170 * subsampling.
1171 */
1172 static void
vips_foreign_save_jp2k_unpack_subsample_image(VipsRegion * region,VipsRect * tile,opj_image_t * image,VipsPel * accumulate)1173 vips_foreign_save_jp2k_unpack_subsample_image( VipsRegion *region,
1174 VipsRect *tile, opj_image_t *image, VipsPel *accumulate )
1175 {
1176 VipsImage *im = region->im;
1177 size_t sizeof_element = VIPS_REGION_SIZEOF_ELEMENT( region );
1178 size_t lskip = VIPS_REGION_LSKIP( region );
1179 int n_bands = im->Bands;
1180
1181 int x, y, z, i;
1182
1183 for( i = 0; i < n_bands; i++ ) {
1184 opj_image_comp_t *comp = &image->comps[i];
1185 int *q = comp->data;
1186
1187 /* The number of pixels we write for this component. Lines
1188 * align to scanlines on comp.
1189 */
1190 int output_width = VIPS_ROUND_UINT(
1191 (double) comp->w / comp->dx );
1192 int output_height = VIPS_ROUND_UINT(
1193 (double) comp->h / comp->dy );
1194
1195 for( y = 0; y < output_height; y++ ) {
1196 VipsPel *p = i * sizeof_element +
1197 VIPS_REGION_ADDR( region,
1198 tile->left, tile->top + y * comp->dy );
1199
1200 /* Shrink a line of pels to q.
1201 */
1202 switch( im->BandFmt ) {
1203 case VIPS_FORMAT_CHAR:
1204 SHRINK( int, int, signed char );
1205 break;
1206
1207 case VIPS_FORMAT_UCHAR:
1208 SHRINK( int, int, unsigned char );
1209 break;
1210
1211 case VIPS_FORMAT_SHORT:
1212 SHRINK( int, int, signed short );
1213 break;
1214
1215 case VIPS_FORMAT_USHORT:
1216 SHRINK( int, int, unsigned short );
1217 break;
1218
1219 case VIPS_FORMAT_INT:
1220 SHRINK( int, gint64, signed int );
1221 break;
1222
1223 case VIPS_FORMAT_UINT:
1224 SHRINK( int, gint64, unsigned int );
1225 break;
1226
1227 default:
1228 g_assert_not_reached();
1229 break;
1230 }
1231
1232 q += output_width;
1233 }
1234 }
1235 }
1236
1237 /* Unpack from @tile within @region to the int data pointers on @image. No
1238 * subsampling.
1239 */
1240 static void
vips_foreign_save_jp2k_unpack_image(VipsRegion * region,VipsRect * tile,opj_image_t * image)1241 vips_foreign_save_jp2k_unpack_image( VipsRegion *region, VipsRect *tile,
1242 opj_image_t *image )
1243 {
1244 VipsImage *im = region->im;
1245 int b = im->Bands;
1246
1247 int x, y, i;
1248
1249 for( y = 0; y < tile->height; y++ ) {
1250 VipsPel *p = VIPS_REGION_ADDR( region,
1251 tile->left, tile->top + y );
1252
1253 for( i = 0; i < b; i++ ) {
1254 opj_image_comp_t *comp = &image->comps[i];
1255 int *q = comp->data + y * comp->w;
1256
1257 switch( im->BandFmt ) {
1258 case VIPS_FORMAT_CHAR:
1259 case VIPS_FORMAT_UCHAR:
1260 UNPACK( int, unsigned char );
1261 break;
1262
1263 case VIPS_FORMAT_SHORT:
1264 case VIPS_FORMAT_USHORT:
1265 UNPACK( int, unsigned short );
1266 break;
1267
1268 case VIPS_FORMAT_INT:
1269 case VIPS_FORMAT_UINT:
1270 UNPACK( int, unsigned int );
1271 break;
1272
1273 default:
1274 g_assert_not_reached();
1275 break;
1276 }
1277 }
1278 }
1279 }
1280
1281 void
vips__foreign_load_jp2k_compress_free(TileCompress * compress)1282 vips__foreign_load_jp2k_compress_free( TileCompress *compress )
1283 {
1284 VIPS_FREEF( opj_destroy_codec, compress->codec );
1285 VIPS_FREEF( opj_image_destroy, compress->image );
1286 VIPS_FREEF( opj_stream_destroy, compress->stream );
1287 VIPS_FREE( compress->accumulate );
1288 }
1289
1290 /* Compress area @tile within @region and write to @target as a @tile_width by
1291 * @tile_height jp2k compressed image. This is called from eg. vips2tiff to
1292 * write jp2k-compressed tiles.
1293 *
1294 * You'd think we could reuse things like the encoder between calls but ...
1295 * nope, openjpeg does not allow that.
1296 */
1297 int
vips__foreign_load_jp2k_compress(VipsRegion * region,VipsRect * tile,VipsTarget * target,int tile_width,int tile_height,gboolean save_as_ycc,gboolean subsample,gboolean lossless,int Q)1298 vips__foreign_load_jp2k_compress( VipsRegion *region,
1299 VipsRect *tile, VipsTarget *target,
1300 int tile_width, int tile_height,
1301 gboolean save_as_ycc, gboolean subsample, gboolean lossless, int Q )
1302 {
1303 TileCompress compress = { 0 };
1304 opj_cparameters_t parameters;
1305 size_t sizeof_line;
1306
1307 /* Our rgb->ycc only works for exactly 3 bands.
1308 */
1309 save_as_ycc = save_as_ycc && region->im->Bands == 3;
1310 subsample = subsample && save_as_ycc;
1311
1312 /* Set compression params.
1313 */
1314 opj_set_default_encoder_parameters( ¶meters );
1315
1316 /* Set compression profile.
1317 */
1318 vips_foreign_save_jp2k_set_profile( ¶meters, lossless, Q );
1319
1320 /* Makes three band images smaller, somehow.
1321 */
1322 parameters.tcp_mct = region->im->Bands >= 3 ? 1 : 0;
1323
1324 /* Create output image. TRUE means we alloc memory for the image
1325 * planes.
1326 */
1327 if( !(compress.image = vips_foreign_save_jp2k_new_image( region->im,
1328 tile_width, tile_height, subsample, save_as_ycc, TRUE )) ) {
1329 vips__foreign_load_jp2k_compress_free( &compress );
1330 return( -1 );
1331 }
1332
1333 /* We need a line of sums for chroma subsample. At worst, gint64.
1334 */
1335 sizeof_line = sizeof( gint64 ) * tile->width;
1336 if( !(compress.accumulate =
1337 VIPS_ARRAY( NULL, sizeof_line, VipsPel )) ) {
1338 vips__foreign_load_jp2k_compress_free( &compress );
1339 return( -1 );
1340 }
1341
1342 compress.codec = opj_create_compress( OPJ_CODEC_J2K );
1343 vips_foreign_save_jp2k_attach_handlers( compress.codec );
1344 if( !opj_setup_encoder( compress.codec,
1345 ¶meters, compress.image ) ) {
1346 vips__foreign_load_jp2k_compress_free( &compress );
1347 return( -1 );
1348 }
1349
1350 opj_codec_set_threads( compress.codec, vips_concurrency_get() );
1351
1352 if( save_as_ycc )
1353 vips_foreign_save_jp2k_rgb_to_ycc( region,
1354 tile, compress.image->comps[0].prec );
1355
1356 /* we need to unpack to the int arrays on comps[i].data
1357 */
1358 if( subsample )
1359 vips_foreign_save_jp2k_unpack_subsample_image( region,
1360 tile, compress.image,
1361 compress.accumulate );
1362 else
1363 vips_foreign_save_jp2k_unpack_image( region,
1364 tile, compress.image );
1365
1366 if( !(compress.stream = vips_foreign_save_jp2k_target( target )) ) {
1367 vips__foreign_load_jp2k_compress_free( &compress );
1368 return( -1 );
1369 }
1370
1371 if( !opj_start_compress( compress.codec,
1372 compress.image, compress.stream ) ) {
1373 vips__foreign_load_jp2k_compress_free( &compress );
1374 return( -1 );
1375 }
1376
1377 if( !opj_encode( compress.codec, compress.stream ) ) {
1378 vips__foreign_load_jp2k_compress_free( &compress );
1379 return( -1 );
1380 }
1381
1382 opj_end_compress( compress.codec, compress.stream );
1383
1384 vips__foreign_load_jp2k_compress_free( &compress );
1385
1386 return( 0 );
1387 }
1388
1389 #else /*!HAVE_LIBOPENJP2*/
1390
1391 int
vips__foreign_load_jp2k_compress(VipsRegion * region,VipsRect * tile,VipsTarget * target,int tile_width,int tile_height,gboolean save_as_ycc,gboolean subsample,gboolean lossless,int Q)1392 vips__foreign_load_jp2k_compress( VipsRegion *region,
1393 VipsRect *tile, VipsTarget *target,
1394 int tile_width, int tile_height,
1395 gboolean save_as_ycc, gboolean subsample, gboolean lossless, int Q )
1396 {
1397 vips_error( "jp2k",
1398 "%s", _( "libvips built without JPEG2000 support" ) );
1399 return( -1 );
1400 }
1401
1402 #endif /*HAVE_LIBOPENJP2*/
1403
1404 /**
1405 * vips_jp2ksave: (method)
1406 * @in: image to save
1407 * @filename: file to write to
1408 * @...: %NULL-terminated list of optional named arguments
1409 *
1410 * Optional arguments:
1411 *
1412 * * @Q: %gint, quality factor
1413 * * @lossless: %gboolean, enables lossless compression
1414 * * @tile_width: %gint for tile size
1415 * * @tile_height: %gint for tile size
1416 * * @subsample_mode: #VipsForeignSubsample, chroma subsampling mode
1417 *
1418 * Write a VIPS image to a file in JPEG2000 format.
1419 * The saver supports 8, 16 and 32-bit int pixel
1420 * values, signed and unsigned. It supports greyscale, RGB, CMYK and
1421 * multispectral images.
1422 *
1423 * Use @Q to set the compression quality factor. The default value
1424 * produces file with approximately the same size as regular JPEG Q 75.
1425 *
1426 * Set @lossless to enable lossless compresion.
1427 *
1428 * Use @tile_width and @tile_height to set the tile size. The default is 512.
1429 *
1430 * Chroma subsampling is normally automatically disabled for Q >= 90. You can
1431 * force the subsampling mode with @subsample_mode.
1432 *
1433 * This operation always writes a pyramid.
1434 *
1435 * See also: vips_image_write_to_file(), vips_jp2kload().
1436 *
1437 * Returns: 0 on success, -1 on error.
1438 */
1439 int
vips_jp2ksave(VipsImage * in,const char * filename,...)1440 vips_jp2ksave( VipsImage *in, const char *filename, ... )
1441 {
1442 va_list ap;
1443 int result;
1444
1445 va_start( ap, filename );
1446 result = vips_call_split( "jp2ksave", ap, in, filename );
1447 va_end( ap );
1448
1449 return( result );
1450 }
1451
1452 /**
1453 * vips_jp2ksave_buffer: (method)
1454 * @in: image to save
1455 * @buf: (array length=len) (element-type guint8): return output buffer here
1456 * @len: (type gsize): return output length here
1457 * @...: %NULL-terminated list of optional named arguments
1458 *
1459 * Optional arguments:
1460 *
1461 * * @Q: %gint, quality factor
1462 * * @lossless: %gboolean, enables lossless compression
1463 * * @tile_width: %gint for tile size
1464 * * @tile_height: %gint for tile size
1465 * * @subsample_mode: #VipsForeignSubsample, chroma subsampling mode
1466 *
1467 * As vips_jp2ksave(), but save to a target.
1468 *
1469 * See also: vips_jp2ksave(), vips_image_write_to_target().
1470 *
1471 * Returns: 0 on success, -1 on error.
1472 */
1473 int
vips_jp2ksave_buffer(VipsImage * in,void ** buf,size_t * len,...)1474 vips_jp2ksave_buffer( VipsImage *in, void **buf, size_t *len, ... )
1475 {
1476 va_list ap;
1477 VipsArea *area;
1478 int result;
1479
1480 area = NULL;
1481
1482 va_start( ap, len );
1483 result = vips_call_split( "jp2ksave_buffer", ap, in, &area );
1484 va_end( ap );
1485
1486 if( !result &&
1487 area ) {
1488 if( buf ) {
1489 *buf = area->data;
1490 area->free_fn = NULL;
1491 }
1492 if( len )
1493 *len = area->length;
1494
1495 vips_area_unref( area );
1496 }
1497
1498 return( result );
1499 }
1500
1501 /**
1502 * vips_jp2ksave_target: (method)
1503 * @in: image to save
1504 * @target: save image to this target
1505 * @...: %NULL-terminated list of optional named arguments
1506 *
1507 * Optional arguments:
1508 *
1509 * * @Q: %gint, quality factor
1510 * * @lossless: %gboolean, enables lossless compression
1511 * * @tile_width: %gint for tile size
1512 * * @tile_height: %gint for tile size
1513 * * @subsample_mode: #VipsForeignSubsample, chroma subsampling mode
1514 *
1515 * As vips_jp2ksave(), but save to a target.
1516 *
1517 * See also: vips_jp2ksave(), vips_image_write_to_target().
1518 *
1519 * Returns: 0 on success, -1 on error.
1520 */
1521 int
vips_jp2ksave_target(VipsImage * in,VipsTarget * target,...)1522 vips_jp2ksave_target( VipsImage *in, VipsTarget *target, ... )
1523 {
1524 va_list ap;
1525 int result;
1526
1527 va_start( ap, target );
1528 result = vips_call_split( "jp2ksave_target", ap, in, target );
1529 va_end( ap );
1530
1531 return( result );
1532 }
1533