static void jpg_put_pixel_rows(j_decompress_ptr cinfo, jpg_dest_t *dinfo, JDIMENSION rows_supplied) { JSAMPLE *bufptr; int cmptno; JDIMENSION x; uint_fast32_t width; if (dinfo->error) { return; } assert(cinfo->output_components == jas_image_numcmpts(dinfo->image)); for (cmptno = 0; cmptno < cinfo->output_components; ++cmptno) { width = jas_image_cmptwidth(dinfo->image, cmptno); bufptr = (dinfo->buffer[0]) + cmptno; for (x = 0; x < width; ++x) { jas_matrix_set(dinfo->data, 0, x, GETJSAMPLE(*bufptr)); bufptr += cinfo->output_components; } if (jas_image_writecmpt(dinfo->image, cmptno, 0, dinfo->row, width, 1, dinfo->data)) { dinfo->error = 1; } } dinfo->row += rows_supplied; }
jas_image_t *makediffimage(jas_matrix_t *origdata, jas_matrix_t *recondata) { jas_image_t *diffimage; jas_matrix_t *diffdata[3]; int width; int height; int i; int j; int k; jas_image_cmptparm_t compparms[3]; jas_seqent_t a; jas_seqent_t b; width = jas_matrix_numcols(origdata); height = jas_matrix_numrows(origdata); for (i = 0; i < 3; ++i) { compparms[i].tlx = 0; compparms[i].tly = 0; compparms[i].hstep = 1; compparms[i].vstep = 1; compparms[i].width = width; compparms[i].height = height; compparms[i].prec = 8; compparms[i].sgnd = jas_false; } if (!(diffimage = jas_image_create(3, compparms, JAS_CLRSPC_SRGB))) { abort(); } for (i = 0; i < 3; ++i) { if (!(diffdata[i] = jas_matrix_create(height, width))) { jas_eprintf("internal error\n"); return 0; } } for (j = 0; j < height; ++j) { for (k = 0; k < width; ++k) { a = jas_matrix_get(origdata, j, k); b = jas_matrix_get(recondata, j, k); if (a > b) { jas_matrix_set(diffdata[0], j, k, 255); jas_matrix_set(diffdata[1], j, k, 0); jas_matrix_set(diffdata[2], j, k, 0); } else if (a < b) { jas_matrix_set(diffdata[0], j, k, 0); jas_matrix_set(diffdata[1], j, k, 255); jas_matrix_set(diffdata[2], j, k, 0); } else { jas_matrix_set(diffdata[0], j, k, a); jas_matrix_set(diffdata[1], j, k, a); jas_matrix_set(diffdata[2], j, k, a); } } } for (i = 0; i < 3; ++i) { if (jas_image_writecmpt(diffimage, i, 0, 0, width, height, diffdata[i])) { return 0; } } return diffimage; }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % W r i t e J P 2 I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Method WriteJP2Image writes an image in the JPEG 2000 image format. % % JP2 support originally written by Nathan Brown, [email protected] % % The format of the WriteJP2Image method is: % % MagickPassFail WriteJP2Image(const ImageInfo *image_info,Image *image) % % A description of each parameter follows. % % o status: Method WriteJP2Image return MagickTrue if the image is written. % MagickFalse is returned is there is a memory shortage or if the image file % fails to write. % % o image_info: Specifies a pointer to a ImageInfo structure. % % o image: A pointer to an Image structure. % % */ static MagickPassFail WriteJP2Image(const ImageInfo *image_info,Image *image) { char magick[MaxTextExtent], option_keyval[MaxTextExtent], *options = NULL; int format; long y; jas_image_cmptparm_t component_info; jas_image_t *jp2_image; jas_matrix_t *jp2_pixels; jas_stream_t *jp2_stream; register const PixelPacket *p; register int x; unsigned int rate_specified=False, status; int component, number_components; unsigned short *lut; ImageCharacteristics characteristics; /* Open image file. */ assert(image_info != (const ImageInfo *) NULL); assert(image_info->signature == MagickSignature); assert(image != (Image *) NULL); assert(image->signature == MagickSignature); status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); if (status == False) ThrowWriterException(FileOpenError,UnableToOpenFile,image); /* Ensure that image is in RGB space. */ (void) TransformColorspace(image,RGBColorspace); /* Analyze image to be written. */ if (!GetImageCharacteristics(image,&characteristics, (OptimizeType == image_info->type), &image->exception)) { CloseBlob(image); return MagickFail; } /* Obtain a JP2 stream. */ jp2_stream=JP2StreamManager(image); if (jp2_stream == (jas_stream_t *) NULL) ThrowWriterException(DelegateError,UnableToManageJP2Stream,image); number_components=image->matte ? 4 : 3; if ((image_info->type != TrueColorType) && (characteristics.grayscale)) number_components=1; jp2_image=jas_image_create0(); if (jp2_image == (jas_image_t *) NULL) ThrowWriterException(DelegateError,UnableToCreateImage,image); for (component=0; component < number_components; component++) { (void) memset((void *)&component_info,0,sizeof(jas_image_cmptparm_t)); component_info.tlx=0; /* top left x ordinate */ component_info.tly=0; /* top left y ordinate */ component_info.hstep=1; /* horizontal pixels per step */ component_info.vstep=1; /* vertical pixels per step */ component_info.width=(unsigned int) image->columns; component_info.height=(unsigned int) image->rows; component_info.prec=(unsigned int) Max(2,Min(image->depth,16)); /* bits in range */ component_info.sgnd = false; /* range is signed value? */ if (jas_image_addcmpt(jp2_image, component,&component_info)) { jas_image_destroy(jp2_image); ThrowWriterException(DelegateError,UnableToCreateImageComponent,image); } } /* Allocate and compute LUT. */ { unsigned long i, max_value; double scale_to_component; lut=MagickAllocateArray(unsigned short *,MaxMap+1,sizeof(*lut)); if (lut == (unsigned short *) NULL) { jas_image_destroy(jp2_image); ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image); } max_value=MaxValueGivenBits(component_info.prec); scale_to_component=max_value/MaxRGBDouble; for(i=0; i <= MaxMap; i++) lut[i]=scale_to_component*i+0.5; } if (number_components == 1) { /* FIXME: If image has an attached ICC profile, then the profile should be transferred and the image colorspace set to JAS_CLRSPC_GENGRAY */ /* sRGB Grayscale */ (void) LogMagickEvent(CoderEvent,GetMagickModule(), "Setting SGRAY colorspace"); jas_image_setclrspc(jp2_image, JAS_CLRSPC_SGRAY); (void) LogMagickEvent(CoderEvent,GetMagickModule(), "Setting GRAY channel to channel 0"); jas_image_setcmpttype(jp2_image,0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y)); } else { /* FIXME: If image has an attached ICC profile, then the profile should be transferred and the image colorspace set to JAS_CLRSPC_GENRGB */ /* sRGB */ (void) LogMagickEvent(CoderEvent,GetMagickModule(), "Setting SRGB colorspace"); jas_image_setclrspc(jp2_image, JAS_CLRSPC_SRGB); (void) LogMagickEvent(CoderEvent,GetMagickModule(), "Setting RED channel to channel 0"); jas_image_setcmpttype(jp2_image,0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R)); (void) LogMagickEvent(CoderEvent,GetMagickModule(), "Setting GREEN channel to channel 1"); jas_image_setcmpttype(jp2_image,1, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G)); (void) LogMagickEvent(CoderEvent,GetMagickModule(), "Setting BLUE channel to channel 2"); jas_image_setcmpttype(jp2_image,2, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B)); if (number_components == 4 ) { (void) LogMagickEvent(CoderEvent,GetMagickModule(), "Setting OPACITY channel to channel 3"); jas_image_setcmpttype(jp2_image,3, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_OPACITY)); } } /* Convert to JPEG 2000 pixels. */ jp2_pixels=jas_matrix_create(1,(unsigned int) image->columns); if (jp2_pixels == (jas_matrix_t *) NULL) { MagickFreeMemory(lut); jas_image_destroy(jp2_image); ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image); } for (y=0; y < (long) image->rows; y++) { p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception); if (p == (const PixelPacket *) NULL) break; if (number_components == 1) { for (x=0; x < (long) image->columns; x++) jas_matrix_setv(jp2_pixels,x,lut[ScaleQuantumToMap(PixelIntensityToQuantum(&p[x]))]); (void) jas_image_writecmpt(jp2_image,0,0,(unsigned int) y, (unsigned int) image->columns,1,jp2_pixels); } else { for (x=0; x < (long) image->columns; x++) jas_matrix_setv(jp2_pixels,x,lut[ScaleQuantumToMap(p[x].red)]); (void) jas_image_writecmpt(jp2_image,0,0,(unsigned int) y, (unsigned int) image->columns,1,jp2_pixels); for (x=0; x < (long) image->columns; x++) jas_matrix_setv(jp2_pixels,x,lut[ScaleQuantumToMap(p[x].green)]); (void) jas_image_writecmpt(jp2_image,1,0,(unsigned int) y, (unsigned int) image->columns,1,jp2_pixels); for (x=0; x < (long) image->columns; x++) jas_matrix_setv(jp2_pixels,x,lut[ScaleQuantumToMap(p[x].blue)]); (void) jas_image_writecmpt(jp2_image,2,0,(unsigned int) y, (unsigned int) image->columns,1,jp2_pixels); if (number_components > 3) for (x=0; x < (long) image->columns; x++) jas_matrix_setv(jp2_pixels,x,lut[ScaleQuantumToMap(MaxRGB-p[x].opacity)]); (void) jas_image_writecmpt(jp2_image,3,0,(unsigned int) y, (unsigned int) image->columns,1,jp2_pixels); } if (image->previous == (Image *) NULL) if (QuantumTick(y,image->rows)) if (!MagickMonitorFormatted(y,image->rows,&image->exception, SaveImageText,image->filename, image->columns,image->rows)) break; } (void) strlcpy(magick,image_info->magick,MaxTextExtent); /* J2C is an alias for JPC but Jasper only supports "JPC". */ if (LocaleCompare(magick,"j2c") == 0) (void) strlcpy(magick,"jpc",sizeof(magick)); LocaleLower(magick); format=jas_image_strtofmt(magick); /* Support passing Jasper options. */ { const char **option_name; static const char *jasper_options[] = { "imgareatlx", "imgareatly", "tilegrdtlx", "tilegrdtly", "tilewidth", "tileheight", "prcwidth", "prcheight", "cblkwidth", "cblkheight", "mode", "ilyrrates", "prg", "nomct", "numrlvls", "sop", "eph", "lazy", "rate", "termall", "segsym", "vcausal", "pterm", "resetprob", "numgbits", NULL }; for (option_name = jasper_options; *option_name != NULL; option_name++) { const char *value; if ((value=AccessDefinition(image_info,"jp2",*option_name)) != NULL) { if(LocaleCompare(*option_name,"rate") == 0) rate_specified=True; FormatString(option_keyval,"%s=%.1024s ",*option_name,value); ConcatenateString(&options,option_keyval); } } } /* Provide an emulation of IJG JPEG "quality" by default. */ if (rate_specified == False) { double rate=1.0; /* A rough approximation to JPEG v1 quality using JPEG-2000. Default "quality" 75 results in a request for 16:1 compression, which results in image sizes approximating that of JPEG v1. */ if ((image_info->quality < 99.5) && (image->rows*image->columns > 2500)) { double header_size, current_size, target_size, d; d=115-image_info->quality; /* Best number is 110-115 */ rate=100.0/(d*d); header_size=550.0; /* Base file size. */ header_size+=(number_components-1)*142; /* Additional components */ /* FIXME: Need to account for any ICC profiles here */ current_size=(double)((image->rows*image->columns*image->depth)/8)* number_components; target_size=(current_size*rate)+header_size; rate=target_size/current_size; } FormatString(option_keyval,"%s=%g ","rate",rate); ConcatenateString(&options,option_keyval); (void) LogMagickEvent(CoderEvent,GetMagickModule(), "Compression rate: %g (%3.2f:1)",rate,1.0/rate); } if (options) (void) LogMagickEvent(CoderEvent,GetMagickModule(), "Jasper options: \"%s\"", options); (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Encoding image"); status=jas_image_encode(jp2_image,jp2_stream,format,options); (void) jas_stream_close(jp2_stream); MagickFreeMemory(options); MagickFreeMemory(lut); jas_matrix_destroy(jp2_pixels); jas_image_destroy(jp2_image); if (status) ThrowWriterException(DelegateError,UnableToEncodeImageFile,image); return(True); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % W r i t e J P 2 I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % WriteJP2Image() writes an image in the JPEG 2000 image format. % % JP2 support originally written by Nathan Brown, [email protected] % % The format of the WriteJP2Image method is: % % MagickBooleanType WriteJP2Image(const ImageInfo *image_info, % Image *image,ExceptionInfo *exception) % % A description of each parameter follows. % % o image_info: the image info. % % o image: The image. % % o exception: return any errors or warnings in this structure. % */ static MagickBooleanType WriteJP2Image(const ImageInfo *image_info,Image *image, ExceptionInfo *exception) { char *key, magick[MaxTextExtent], *options; const char *option; jas_image_cmptparm_t component_info[4]; jas_image_t *jp2_image; jas_matrix_t *pixels[4]; jas_stream_t *jp2_stream; MagickBooleanType status; QuantumAny range; register const Quantum *p; register ssize_t i, x; size_t number_components; ssize_t format, y; /* Open image file. */ assert(image_info != (const ImageInfo *) NULL); assert(image_info->signature == MagickSignature); assert(image != (Image *) NULL); assert(image->signature == MagickSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickSignature); status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); if (status == MagickFalse) return(status); /* Initialize JPEG 2000 API. */ if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) (void) TransformImageColorspace(image,sRGBColorspace,exception); jp2_stream=JP2StreamManager(image); if (jp2_stream == (jas_stream_t *) NULL) ThrowWriterException(DelegateError,"UnableToManageJP2Stream"); number_components=image->alpha_trait ? 4UL : 3UL; if (IsGrayColorspace(image->colorspace) != MagickFalse) number_components=1; if ((image->columns != (unsigned int) image->columns) || (image->rows != (unsigned int) image->rows)) ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit"); (void) ResetMagickMemory(&component_info,0,sizeof(component_info)); for (i=0; i < (ssize_t) number_components; i++) { component_info[i].tlx=0; component_info[i].tly=0; component_info[i].hstep=1; component_info[i].vstep=1; component_info[i].width=(unsigned int) image->columns; component_info[i].height=(unsigned int) image->rows; component_info[i].prec=(int) MagickMax(MagickMin(image->depth,16),2); component_info[i].sgnd=MagickFalse; } jp2_image=jas_image_create((int) number_components,component_info, JAS_CLRSPC_UNKNOWN); if (jp2_image == (jas_image_t *) NULL) ThrowWriterException(DelegateError,"UnableToCreateImage"); switch (image->colorspace) { case RGBColorspace: case sRGBColorspace: { /* RGB colorspace. */ jas_image_setclrspc(jp2_image,JAS_CLRSPC_SRGB); jas_image_setcmpttype(jp2_image,0, (jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R)); jas_image_setcmpttype(jp2_image,1, (jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G)); jas_image_setcmpttype(jp2_image,2, (jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B)); if (number_components == 4) jas_image_setcmpttype(jp2_image,3,JAS_IMAGE_CT_OPACITY); break; } case GRAYColorspace: { /* Grayscale colorspace. */ jas_image_setclrspc(jp2_image,JAS_CLRSPC_SGRAY); jas_image_setcmpttype(jp2_image,0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y)); break; } case YCbCrColorspace: { /* YCbCr colorspace. */ jas_image_setclrspc(jp2_image,JAS_CLRSPC_SYCBCR); jas_image_setcmpttype(jp2_image,0,(jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(0)); jas_image_setcmpttype(jp2_image,1,(jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(1)); jas_image_setcmpttype(jp2_image,2,(jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(2)); if (number_components == 4) jas_image_setcmpttype(jp2_image,3,JAS_IMAGE_CT_OPACITY); break; } case XYZColorspace: { /* XYZ colorspace. */ jas_image_setclrspc(jp2_image,JAS_CLRSPC_CIEXYZ); jas_image_setcmpttype(jp2_image,0,(jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(0)); jas_image_setcmpttype(jp2_image,1,(jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(1)); jas_image_setcmpttype(jp2_image,2,(jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(2)); if (number_components == 4) jas_image_setcmpttype(jp2_image,3,JAS_IMAGE_CT_OPACITY); break; } case LabColorspace: { /* Lab colorspace. */ jas_image_setclrspc(jp2_image,JAS_CLRSPC_CIELAB); jas_image_setcmpttype(jp2_image,0,(jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(0)); jas_image_setcmpttype(jp2_image,1,(jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(1)); jas_image_setcmpttype(jp2_image,2,(jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(2)); if (number_components == 4) jas_image_setcmpttype(jp2_image,3,JAS_IMAGE_CT_OPACITY); break; } default: { /* Unknow. */ jas_image_setclrspc(jp2_image,JAS_CLRSPC_UNKNOWN); jas_image_setcmpttype(jp2_image,0,(jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(0)); jas_image_setcmpttype(jp2_image,1,(jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(1)); jas_image_setcmpttype(jp2_image,2,(jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(2)); if (number_components == 4) jas_image_setcmpttype(jp2_image,3,JAS_IMAGE_CT_OPACITY); break; } } /* Convert to JPEG 2000 pixels. */ for (i=0; i < (ssize_t) number_components; i++) { pixels[i]=jas_matrix_create(1,(int) image->columns); if (pixels[i] == (jas_matrix_t *) NULL) { for (x=0; x < i; x++) jas_matrix_destroy(pixels[x]); jas_image_destroy(jp2_image); ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); } } range=GetQuantumRange((size_t) component_info[0].prec); for (y=0; y < (ssize_t) image->rows; y++) { p=GetVirtualPixels(image,0,y,image->columns,1,exception); if (p == (const Quantum *) NULL) break; for (x=0; x < (ssize_t) image->columns; x++) { if (number_components == 1) jas_matrix_setv(pixels[0],x,(jas_seqent_t) ScaleQuantumToAny( GetPixelIntensity(image,p),range)); else { jas_matrix_setv(pixels[0],x,(jas_seqent_t) ScaleQuantumToAny( GetPixelRed(image,p),range)); jas_matrix_setv(pixels[1],x,(jas_seqent_t) ScaleQuantumToAny( GetPixelGreen(image,p),range)); jas_matrix_setv(pixels[2],x,(jas_seqent_t) ScaleQuantumToAny( GetPixelBlue(image,p),range)); if (number_components > 3) jas_matrix_setv(pixels[3],x,(jas_seqent_t) ScaleQuantumToAny( GetPixelAlpha(image,p),range)); } p+=GetPixelChannels(image); } for (i=0; i < (ssize_t) number_components; i++) (void) jas_image_writecmpt(jp2_image,(short) i,0,(unsigned int) y, (unsigned int) image->columns,1,pixels[i]); status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, image->rows); if (status == MagickFalse) break; } (void) CopyMagickString(magick,image_info->magick,MaxTextExtent); if (LocaleCompare(magick,"J2C") == 0) (void) CopyMagickString(magick,"JPC",MaxTextExtent); LocaleLower(magick); format=jas_image_strtofmt(magick); options=(char *) NULL; ResetImageOptionIterator(image_info); key=GetNextImageOption(image_info); for ( ; key != (char *) NULL; key=GetNextImageOption(image_info)) { option=GetImageOption(image_info,key); if (option == (const char *) NULL) continue; if (LocaleNCompare(key,"jp2:",4) == 0) { (void) ConcatenateString(&options,key+4); if (*option != '\0') { (void) ConcatenateString(&options,"="); (void) ConcatenateString(&options,option); } (void) ConcatenateString(&options," "); } } option=GetImageOption(image_info,"jp2:rate"); if ((option == (const char *) NULL) && (image_info->compression != LosslessJPEGCompression) && (image->quality != UndefinedCompressionQuality) && ((double) image->quality <= 99.5) && ((image->rows*image->columns) > 2500)) { char option[MaxTextExtent]; double alpha, header_size, number_pixels, rate, target_size; alpha=115.0-image->quality; rate=100.0/(alpha*alpha); header_size=550.0; header_size+=(number_components-1)*142; number_pixels=(double) image->rows*image->columns*number_components* (GetImageQuantumDepth(image,MagickTrue)/8); target_size=(number_pixels*rate)+header_size; rate=target_size/number_pixels; (void) FormatLocaleString(option,MaxTextExtent,"rate=%g",rate); (void) ConcatenateString(&options,option); } status=jas_image_encode(jp2_image,jp2_stream,format,options) != 0 ? MagickTrue : MagickFalse; if (options != (char *) NULL) options=DestroyString(options); (void) jas_stream_close(jp2_stream); for (i=0; i < (ssize_t) number_components; i++) jas_matrix_destroy(pixels[i]); jas_image_destroy(jp2_image); if (status != MagickFalse) ThrowWriterException(DelegateError,"UnableToEncodeImageFile"); return(MagickTrue); }
static void WriteJP2KImage( const GenericImage<P>& img, const ImageInfo& info, const ImageOptions& options, jas_stream_t* jp2Stream, jas_image_t* jp2Image, int jp2Format, const JPEG2000ImageOptions& jp2Options ) { jas_matrix_t* pixels = nullptr; try { pixels = jas_matrix_create( 1, img.Width() ); if ( pixels == nullptr ) throw Error( "Memory allocation error writing JPEG2000 image." ); for ( int c = 0; c < img.NumberOfChannels(); ++c ) { for ( int y = 0; y < img.Height(); ++y ) { const typename P::sample* f = img.ScanLine( y, c ); if ( options.bitsPerSample == 8 ) { if ( jp2Options.signedSample ) { int8 v; for ( int x = 0; x < img.Width(); ++x ) { P::FromSample( v, *f++ ); jas_matrix_set( pixels, 0, x, v ); } } else { uint8 v; for ( int x = 0; x < img.Width(); ++x ) { P::FromSample( v, *f++ ); jas_matrix_set( pixels, 0, x, v ); } } } else { if ( jp2Options.signedSample ) { int16 v; for ( int x = 0; x < img.Width(); ++x ) { P::FromSample( v, *f++ ); jas_matrix_set( pixels, 0, x, v ); } } else { uint16 v; for ( int x = 0; x < img.Width(); ++x ) { P::FromSample( v, *f++ ); jas_matrix_set( pixels, 0, x, v ); } } } jas_image_writecmpt( jp2Image, c, 0, y, img.Width(), 1, pixels ); } } IsoString jp2OptionsStr; jp2OptionsStr.AppendFormat( "mode=%s", jp2Options.lossyCompression ? "real" : "int" ); if ( jp2Options.lossyCompression ) jp2OptionsStr.AppendFormat( " rate=%g", jp2Options.compressionRate ); if ( jp2Options.tiledImage ) { jp2OptionsStr.AppendFormat( " tilewidth=%d", Range( jp2Options.tileWidth, 8, img.Width() ) ); jp2OptionsStr.AppendFormat( " tileheight=%d", Range( jp2Options.tileHeight, 8, img.Height() ) ); } if ( jp2Options.numberOfLayers > 1 ) { jp2OptionsStr.Append( " ilyrrates=" ); float dr = (jp2Options.lossyCompression ? jp2Options.compressionRate : 1.0F)/jp2Options.numberOfLayers; for ( int l = 1; ; ) { jp2OptionsStr.AppendFormat( "%g", l*dr ); if ( ++l == jp2Options.numberOfLayers ) break; jp2OptionsStr.Append( ',' ); } jp2OptionsStr.Append( " prg=" ); switch ( jp2Options.progressionOrder ) { default: case JPEG2000ProgressionOrder::LRCP: jp2OptionsStr.Append( "lrcp" ); break; case JPEG2000ProgressionOrder::RLCP: jp2OptionsStr.Append( "rlcp" ); break; case JPEG2000ProgressionOrder::RPCL: jp2OptionsStr.Append( "rpcl" ); break; case JPEG2000ProgressionOrder::PCRL: jp2OptionsStr.Append( "pcrl" ); break; case JPEG2000ProgressionOrder::CPRL: jp2OptionsStr.Append( "cprl" ); break; } } if ( jas_image_encode( jp2Image, jp2Stream, jp2Format, jp2OptionsStr.Begin() ) < 0 ) throw Error( "Unable to encode JPEG2000 image." ); jas_matrix_destroy( pixels ), pixels = nullptr; } catch ( ... ) { if ( pixels != nullptr ) jas_matrix_destroy( pixels ); throw; } }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % W r i t e J P 2 I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % WriteJP2Image() writes an image in the JPEG 2000 image format. % % JP2 support originally written by Nathan Brown, [email protected] % % The format of the WriteJP2Image method is: % % MagickBooleanType WriteJP2Image(const ImageInfo *image_info,Image *image) % % A description of each parameter follows. % % o image_info: the image info. % % o image: The image. % */ static MagickBooleanType WriteJP2Image(const ImageInfo *image_info,Image *image) { char *key, magick[MaxTextExtent], *options; const char *option; long format, y; jas_image_cmptparm_t component_info[4]; jas_image_t *jp2_image; jas_matrix_t *pixels[4]; jas_stream_t *jp2_stream; MagickBooleanType status; QuantumAny range; register const PixelPacket *p; register long i, x; unsigned short *map; unsigned long number_components; /* Open image file. */ assert(image_info != (const ImageInfo *) NULL); assert(image_info->signature == MagickSignature); assert(image != (Image *) NULL); assert(image->signature == MagickSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); if (status == MagickFalse) return(status); /* Intialize JPEG 2000 API. */ if (image->colorspace != RGBColorspace) (void) TransformImageColorspace(image,RGBColorspace); jp2_stream=JP2StreamManager(image); if (jp2_stream == (jas_stream_t *) NULL) ThrowWriterException(DelegateError,"UnableToManageJP2Stream"); number_components=image->matte ? 4UL : 3UL; if ((image_info->type != TrueColorType) && IsGrayImage(image,&image->exception)) number_components=1; if ((image->columns != (unsigned int) image->columns) || (image->rows != (unsigned int) image->rows)) ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit"); (void) ResetMagickMemory(&component_info,0,sizeof(component_info)); for (i=0; i < (long) number_components; i++) { component_info[i].tlx=0; component_info[i].tly=0; component_info[i].hstep=1; component_info[i].vstep=1; component_info[i].width=(unsigned int) image->columns; component_info[i].height=(unsigned int) image->rows; component_info[i].prec=(int) MagickMax(MagickMin(image->depth,16),2); component_info[i].sgnd=MagickFalse; } jp2_image=jas_image_create((int) number_components,component_info, JAS_CLRSPC_UNKNOWN); if (jp2_image == (jas_image_t *) NULL) ThrowWriterException(DelegateError,"UnableToCreateImage"); if (number_components == 1) { /* sRGB Grayscale. */ jas_image_setclrspc(jp2_image,JAS_CLRSPC_SGRAY); jas_image_setcmpttype(jp2_image,0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y)); } else { /* sRGB. */ jas_image_setclrspc(jp2_image,JAS_CLRSPC_SRGB); jas_image_setcmpttype(jp2_image,0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R)); jas_image_setcmpttype(jp2_image,1, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G)); jas_image_setcmpttype(jp2_image,2, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B)); if (number_components == 4) jas_image_setcmpttype(jp2_image,3,JAS_IMAGE_CT_OPACITY); } /* Convert to JPEG 2000 pixels. */ for (i=0; i < (long) number_components; i++) { pixels[i]=jas_matrix_create(1,(int) image->columns); if (pixels[i] == (jas_matrix_t *) NULL) { for (x=0; x < i; x++) jas_matrix_destroy(pixels[x]); jas_image_destroy(jp2_image); ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); } } range=GetQuantumRange((unsigned long) component_info[0].prec); map=(unsigned short *) AcquireQuantumMemory(MaxMap+1,sizeof(*map)); for (i=0; i <= (long) MaxMap; i++) map[i]=(unsigned short) ScaleQuantumToMap((Quantum) ScaleQuantumToAny((Quantum) i,range)); if (map == (unsigned short *) NULL) { for (i=0; i < (long) number_components; i++) jas_matrix_destroy(pixels[i]); jas_image_destroy(jp2_image); ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); } for (y=0; y < (long) image->rows; y++) { p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception); if (p == (const PixelPacket *) NULL) break; for (x=0; x < (long) image->columns; x++) { if (number_components == 1) jas_matrix_setv(pixels[0],x,map[ScaleQuantumToMap( PixelIntensityToQuantum(p))]); else { jas_matrix_setv(pixels[0],x,map[ScaleQuantumToMap(p->red)]); jas_matrix_setv(pixels[1],x,map[ScaleQuantumToMap(p->green)]); jas_matrix_setv(pixels[2],x,map[ScaleQuantumToMap(p->blue)]); if (number_components > 3) jas_matrix_setv(pixels[3],x,map[ScaleQuantumToMap((Quantum) (QuantumRange-p->opacity))]); } p++; } for (i=0; i < (long) number_components; i++) (void) jas_image_writecmpt(jp2_image,(short) i,0,(unsigned int) y, (unsigned int) image->columns,1,pixels[i]); status=SetImageProgress(image,SaveImageTag,y,image->rows); if (status == MagickFalse) break; } map=(unsigned short *) RelinquishMagickMemory(map); (void) CopyMagickString(magick,image_info->magick,MaxTextExtent); LocaleLower(magick); format=jas_image_strtofmt(magick); options=(char *) NULL; ResetImageOptionIterator(image_info); key=GetNextImageOption(image_info); while (key != (char *) NULL) { option=GetImageOption(image_info,key); if (option != (const char *) NULL) { if (LocaleNCompare(key,"jp2:",4) == 0) { (void) ConcatenateString(&options,key+4); if (*option != '\0') { (void) ConcatenateString(&options,"="); (void) ConcatenateString(&options,option); } (void) ConcatenateString(&options," "); } } key=GetNextImageOption(image_info); } option=GetImageOption(image_info,"jp2:rate"); if ((option == (const char *) NULL) && (image_info->compression != LosslessJPEGCompression) && (image->quality != UndefinedCompressionQuality) && ((double) image->quality <= 99.5) && ((image->rows*image->columns) > 2500)) { char option[MaxTextExtent]; double alpha, header_size, number_pixels, rate, target_size; alpha=115.0-image->quality; rate=100.0/(alpha*alpha); header_size=550.0; header_size+=(number_components-1)*142; number_pixels=(double) image->rows*image->columns*number_components* (GetImageQuantumDepth(image,MagickTrue)/8); target_size=(number_pixels*rate)+header_size; rate=target_size/number_pixels; (void) FormatMagickString(option,MaxTextExtent,"rate=%g",rate); (void) ConcatenateString(&options,option); } status=jas_image_encode(jp2_image,jp2_stream,format,options) != 0 ? MagickTrue : MagickFalse; (void) jas_stream_close(jp2_stream); for (i=0; i < (long) number_components; i++) jas_matrix_destroy(pixels[i]); jas_image_destroy(jp2_image); if (status != MagickFalse) ThrowWriterException(DelegateError,"UnableToEncodeImageFile"); return(MagickTrue); }
bool JP2KLoader::save(const QString& filePath, DImgLoaderObserver* observer) { FILE* file = fopen(QFile::encodeName(filePath), "wb"); if (!file) { return false; } fclose(file); // ------------------------------------------------------------------- // Initialize JPEG 2000 API. register long i, x, y; unsigned long number_components; jas_image_t* jp2_image = 0; jas_stream_t* jp2_stream = 0; jas_matrix_t* pixels[4]; jas_image_cmptparm_t component_info[4]; int init = jas_init(); if (init != 0) { kDebug() << "Unable to init JPEG2000 decoder"; return false; } jp2_stream = jas_stream_fopen(QFile::encodeName(filePath), "wb"); if (jp2_stream == 0) { kDebug() << "Unable to open JPEG2000 stream"; return false; } number_components = imageHasAlpha() ? 4 : 3; for (i = 0 ; i < (long)number_components ; ++i) { component_info[i].tlx = 0; component_info[i].tly = 0; component_info[i].hstep = 1; component_info[i].vstep = 1; component_info[i].width = imageWidth(); component_info[i].height = imageHeight(); component_info[i].prec = imageBitsDepth(); component_info[i].sgnd = false; } jp2_image = jas_image_create(number_components, component_info, JAS_CLRSPC_UNKNOWN); if (jp2_image == 0) { jas_stream_close(jp2_stream); kDebug() << "Unable to create JPEG2000 image"; return false; } if (observer) { observer->progressInfo(m_image, 0.1F); } // ------------------------------------------------------------------- // Check color space. if (number_components >= 3 ) // RGB & RGBA { // Alpha Channel if (number_components == 4 ) { jas_image_setcmpttype(jp2_image, 3, JAS_IMAGE_CT_OPACITY); } jas_image_setclrspc(jp2_image, JAS_CLRSPC_SRGB); jas_image_setcmpttype(jp2_image, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R)); jas_image_setcmpttype(jp2_image, 1, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G)); jas_image_setcmpttype(jp2_image, 2, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B)); } // ------------------------------------------------------------------- // Set ICC color profile. // FIXME : doesn't work yet! jas_cmprof_t* cm_profile = 0; jas_iccprof_t* icc_profile = 0; QByteArray profile_rawdata = m_image->getIccProfile().data(); icc_profile = jas_iccprof_createfrombuf((uchar*)profile_rawdata.data(), profile_rawdata.size()); if (icc_profile != 0) { cm_profile = jas_cmprof_createfromiccprof(icc_profile); if (cm_profile != 0) { jas_image_setcmprof(jp2_image, cm_profile); } } // ------------------------------------------------------------------- // Convert to JPEG 2000 pixels. for (i = 0 ; i < (long)number_components ; ++i) { pixels[i] = jas_matrix_create(1, (unsigned int)imageWidth()); if (pixels[i] == 0) { for (x = 0 ; x < i ; ++x) { jas_matrix_destroy(pixels[x]); } jas_image_destroy(jp2_image); kDebug() << "Error encoding JPEG2000 image data : Memory Allocation Failed"; return false; } } unsigned char* data = imageData(); unsigned char* pixel; unsigned short r, g, b, a=0; uint checkpoint = 0; for (y = 0 ; y < (long)imageHeight() ; ++y) { if (observer && y == (long)checkpoint) { checkpoint += granularity(observer, imageHeight(), 0.8F); if (!observer->continueQuery(m_image)) { jas_image_destroy(jp2_image); for (i = 0 ; i < (long)number_components ; ++i) { jas_matrix_destroy(pixels[i]); } jas_cleanup(); return false; } observer->progressInfo(m_image, 0.1 + (0.8 * ( ((float)y)/((float)imageHeight()) ))); } for (x = 0 ; x < (long)imageWidth() ; ++x) { pixel = &data[((y * imageWidth()) + x) * imageBytesDepth()]; if ( imageSixteenBit() ) // 16 bits image. { b = (unsigned short)(pixel[0]+256*pixel[1]); g = (unsigned short)(pixel[2]+256*pixel[3]); r = (unsigned short)(pixel[4]+256*pixel[5]); if (imageHasAlpha()) { a = (unsigned short)(pixel[6]+256*pixel[7]); } } else // 8 bits image. { b = (unsigned short)pixel[0]; g = (unsigned short)pixel[1]; r = (unsigned short)pixel[2]; if (imageHasAlpha()) { a = (unsigned short)(pixel[3]); } } jas_matrix_setv(pixels[0], x, r); jas_matrix_setv(pixels[1], x, g); jas_matrix_setv(pixels[2], x, b); if (number_components > 3) { jas_matrix_setv(pixels[3], x, a); } } for (i = 0 ; i < (long)number_components ; ++i) { int ret = jas_image_writecmpt(jp2_image, (short) i, 0, (unsigned int)y, (unsigned int)imageWidth(), 1, pixels[i]); if (ret != 0) { kDebug() << "Error encoding JPEG2000 image data"; jas_image_destroy(jp2_image); for (i = 0 ; i < (long)number_components ; ++i) { jas_matrix_destroy(pixels[i]); } jas_cleanup(); return false; } } } QVariant qualityAttr = imageGetAttribute("quality"); int quality = qualityAttr.isValid() ? qualityAttr.toInt() : 90; if (quality < 0) { quality = 90; } if (quality > 100) { quality = 100; } QString rate; QTextStream ts( &rate, QIODevice::WriteOnly ); // NOTE: to have a lossless compression use quality=100. // jp2_encode()::optstr: // - rate=#B => the resulting file size is about # bytes // - rate=0.0 .. 1.0 => the resulting file size is about the factor times // the uncompressed size ts << "rate=" << ( quality / 100.0F ); kDebug() << "JPEG2000 quality: " << quality; kDebug() << "JPEG2000 " << rate; int ret = jp2_encode(jp2_image, jp2_stream, rate.toUtf8().data()); if (ret != 0) { kDebug() << "Unable to encode JPEG2000 image"; jas_image_destroy(jp2_image); jas_stream_close(jp2_stream); for (i = 0 ; i < (long)number_components ; ++i) { jas_matrix_destroy(pixels[i]); } jas_cleanup(); return false; } if (observer) { observer->progressInfo(m_image, 1.0); } imageSetAttribute("savedformat", "JP2K"); saveMetadata(filePath); jas_image_destroy(jp2_image); jas_stream_close(jp2_stream); for (i = 0 ; i < (long)number_components ; ++i) { jas_matrix_destroy(pixels[i]); } jas_cleanup(); return true; }
static void createJasperRaster(struct pam * const inpamP, jas_image_t * const jasperP) { jas_matrix_t ** matrix; /* malloc'ed */ /* matrix[X] is the data for Plane X of the current row */ unsigned int plane; unsigned int row; tuple * tuplerow; bool oddMaxval; sample jasperMaxval; matrix = malloc(inpamP->depth * sizeof(jas_matrix_t *)); if (matrix == NULL) pm_error("Out of memory"); for (plane = 0; plane < inpamP->depth; ++plane) { matrix[plane] = jas_matrix_create(1, inpamP->width); if (matrix[plane] == NULL) pm_error("Unable to create matrix for plane %u. " "jas_matrix_create() failed.", plane); } tuplerow = pnm_allocpamrow(inpamP); jasperMaxval = pm_bitstomaxval(pm_maxvaltobits(inpamP->maxval)); oddMaxval = jasperMaxval != inpamP->maxval; for (row = 0; row < inpamP->height; ++row) { unsigned int col; pnm_readpamrow(inpamP, tuplerow); for (col = 0; col < inpamP->width; ++col) { unsigned int plane; for (plane = 0; plane < inpamP->depth; ++plane) { unsigned int jasperSample; if (oddMaxval) jasperSample = tuplerow[col][plane] * jasperMaxval / inpamP->maxval; else jasperSample = tuplerow[col][plane]; jas_matrix_set(matrix[plane], 0, col, jasperSample); } } { unsigned int plane; for (plane = 0; plane < inpamP->depth; ++plane) { int rc; rc = jas_image_writecmpt(jasperP, plane, 0, row, inpamP->width, 1, matrix[plane]); if (rc != 0) pm_error("jas_image_writecmpt() of plane %u failed.", plane); } } } pnm_freepamrow(tuplerow); for (plane = 0; plane < inpamP->depth; ++plane) jas_matrix_destroy(matrix[plane]); free(matrix); }