static void copy_options(Image *image, Info *info) { char property[MaxTextExtent]; const char *value, *option; ResetImageOptionIterator(info); for (option = GetNextImageOption(info); option; option = GetNextImageOption(info)) { value = GetImageOption(info,option); if (value) { strncpy(property, value, MaxTextExtent); property[MaxTextExtent-1] = '\0'; (void) SetImageArtifact(image, property, value); } } }
/* Temporary Debugging Information FUTURE: these should be able to be printed out using 'percent escapes' Actually 'Properities' can already be output with "%[*]" */ static void OutputOptions(ImageInfo *image_info) { const char *option, *value; (void) FormatLocaleFile(stdout," Global Options:\n"); ResetImageOptionIterator(image_info); while ((option=GetNextImageOption(image_info)) != (const char *) NULL ) { (void) FormatLocaleFile(stdout," %s: ",option); value=GetImageOption(image_info,option); if (value != (const char *) NULL) (void) FormatLocaleFile(stdout,"%s\n",value); } ResetImageOptionIterator(image_info); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % 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); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % 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); }