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( &parameters );
1315 
1316 	/* Set compression profile.
1317 	 */
1318 	vips_foreign_save_jp2k_set_profile( &parameters, 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 		&parameters, 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