source: ImageMagick/branches/ImageMagick-6/coders/jp2.c @ 8046

Revision 8046, 33.9 KB checked in by cristy, 12 months ago (diff)
Line 
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%                              JJJ  PPPP    222                               %
7%                               J   P   P  2   2                              %
8%                               J   PPPP     22                               %
9%                            J  J   P       2                                 %
10%                             JJ    P      22222                              %
11%                                                                             %
12%                                                                             %
13%                     Read/Write JPEG-2000 Image Format                       %
14%                                                                             %
15%                                John Cristy                                  %
16%                                Nathan Brown                                 %
17%                                 June 2001                                   %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
21%  dedicated to making software imaging solutions freely available.           %
22%                                                                             %
23%  You may not use this file except in compliance with the License.  You may  %
24%  obtain a copy of the License at                                            %
25%                                                                             %
26%    http://www.imagemagick.org/script/license.php                            %
27%                                                                             %
28%  Unless required by applicable law or agreed to in writing, software        %
29%  distributed under the License is distributed on an "AS IS" BASIS,          %
30%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31%  See the License for the specific language governing permissions and        %
32%  limitations under the License.                                             %
33%                                                                             %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37*/
38
39/*
40  Include declarations.
41*/
42#include "magick/studio.h"
43#include "magick/attribute.h"
44#include "magick/blob.h"
45#include "magick/blob-private.h"
46#include "magick/cache.h"
47#include "magick/colorspace.h"
48#include "magick/colorspace-private.h"
49#include "magick/color.h"
50#include "magick/color-private.h"
51#include "magick/exception.h"
52#include "magick/exception-private.h"
53#include "magick/image.h"
54#include "magick/image-private.h"
55#include "magick/list.h"
56#include "magick/magick.h"
57#include "magick/memory_.h"
58#include "magick/monitor.h"
59#include "magick/monitor-private.h"
60#include "magick/option.h"
61#include "magick/profile.h"
62#include "magick/quantum-private.h"
63#include "magick/static.h"
64#include "magick/statistic.h"
65#include "magick/string_.h"
66#include "magick/module.h"
67#if defined(MAGICKCORE_JP2_DELEGATE)
68#ifndef JAS_IMAGE_CM_GRAY
69#define JAS_IMAGE_CM_GRAY JAS_IMAGE_CS_GRAY
70#endif
71#ifndef JAS_IMAGE_CM_RGB
72#define JAS_IMAGE_CM_RGB JAS_IMAGE_CS_RGB
73#endif
74#if !defined(uchar)
75#define uchar  unsigned char
76#endif
77#if !defined(ushort)
78#define ushort  unsigned short
79#endif
80#if !defined(uint)
81#define uint  unsigned int
82#endif
83#if !defined(ssize_tssize_t)
84#define ssize_tssize_t  long long
85#endif
86#if !defined(ussize_tssize_t)
87#define ussize_tssize_t  unsigned long long
88#endif
89
90#undef PACKAGE_NAME
91#undef PACKAGE_STRING
92#undef PACKAGE_TARNAME
93#undef PACKAGE_VERSION
94#include "jasper/jasper.h"
95#undef PACKAGE_NAME
96#undef PACKAGE_STRING
97#undef PACKAGE_TARNAME
98#undef PACKAGE_VERSION
99
100#endif
101
102/*
103  Forward declarations.
104*/
105#if defined(MAGICKCORE_JP2_DELEGATE)
106static MagickBooleanType
107  WriteJP2Image(const ImageInfo *,Image *);
108
109static volatile MagickBooleanType
110  instantiate_jp2 = MagickFalse;
111#endif
112
113/*
114%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
115%                                                                             %
116%                                                                             %
117%                                                                             %
118%   I s J P 2                                                                 %
119%                                                                             %
120%                                                                             %
121%                                                                             %
122%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
123%
124%  IsJP2() returns MagickTrue if the image format type, identified by the
125%  magick string, is JP2.
126%
127%  The format of the IsJP2 method is:
128%
129%      MagickBooleanType IsJP2(const unsigned char *magick,const size_t length)
130%
131%  A description of each parameter follows:
132%
133%    o magick: compare image format pattern against these bytes.
134%
135%    o length: Specifies the length of the magick string.
136%
137*/
138static MagickBooleanType IsJP2(const unsigned char *magick,const size_t length)
139{
140  if (length < 9)
141    return(MagickFalse);
142  if (memcmp(magick+4,"\152\120\040\040\015",5) == 0)
143    return(MagickTrue);
144  return(MagickFalse);
145}
146
147/*
148%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
149%                                                                             %
150%                                                                             %
151%                                                                             %
152%   I s J P C                                                                 %
153%                                                                             %
154%                                                                             %
155%                                                                             %
156%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
157%
158%  IsJPC()() returns MagickTrue if the image format type, identified by the
159%  magick string, is JPC.
160%
161%  The format of the IsJPC method is:
162%
163%      MagickBooleanType IsJPC(const unsigned char *magick,const size_t length)
164%
165%  A description of each parameter follows:
166%
167%    o magick: compare image format pattern against these bytes.
168%
169%    o length: Specifies the length of the magick string.
170%
171*/
172static MagickBooleanType IsJPC(const unsigned char *magick,const size_t length)
173{
174  if (length < 2)
175    return(MagickFalse);
176  if (memcmp(magick,"\377\117",2) == 0)
177    return(MagickTrue);
178  return(MagickFalse);
179}
180
181/*
182%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
183%                                                                             %
184%                                                                             %
185%                                                                             %
186%   R e a d J P 2 I m a g e                                                   %
187%                                                                             %
188%                                                                             %
189%                                                                             %
190%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
191%
192%  ReadJP2Image() reads a JPEG 2000 Image file (JP2) or JPEG 2000
193%  codestream (JPC) image file and returns it.  It allocates the memory
194%  necessary for the new Image structure and returns a pointer to the new
195%  image or set of images.
196%
197%  JP2 support is originally written by Nathan Brown, nathanbrown@letu.edu.
198%
199%  The format of the ReadJP2Image method is:
200%
201%      Image *ReadJP2Image(const ImageInfo *image_info,
202%        ExceptionInfo *exception)
203%
204%  A description of each parameter follows:
205%
206%    o image_info: the image info.
207%
208%    o exception: return any errors or warnings in this structure.
209%
210*/
211#if defined(MAGICKCORE_JP2_DELEGATE)
212
213typedef struct _StreamManager
214{
215  jas_stream_t
216    *stream;
217
218  Image
219    *image;
220} StreamManager;
221
222static int BlobRead(jas_stream_obj_t *object,char *buffer,const int length)
223{
224  ssize_t
225    count;
226
227  StreamManager
228    *source;
229
230  source=(StreamManager *) object;
231  count=ReadBlob(source->image,(size_t) length,(unsigned char *) buffer);
232  return((int) count);
233}
234
235static int BlobWrite(jas_stream_obj_t *object,char *buffer,const int length)
236{
237  ssize_t
238    count;
239
240  StreamManager
241    *source;
242
243  source=(StreamManager *) object;
244  count=WriteBlob(source->image,(size_t) length,(unsigned char *) buffer);
245  return((int) count);
246}
247
248static long BlobSeek(jas_stream_obj_t *object,long offset,int origin)
249{
250  StreamManager
251    *source;
252
253  source=(StreamManager *) object;
254  return((long) SeekBlob(source->image,offset,origin));
255}
256
257static int BlobClose(jas_stream_obj_t *object)
258{
259  StreamManager
260    *source;
261
262  source=(StreamManager *) object;
263  (void) CloseBlob(source->image);
264  free(source);
265  source=(StreamManager *) NULL;
266  return(0);
267}
268
269static inline size_t MagickMax(const size_t x,const size_t y)
270{
271  if (x > y)
272    return(x);
273  return(y);
274}
275
276static inline size_t MagickMin(const size_t x,const size_t y)
277{
278  if (x < y)
279    return(x);
280  return(y);
281}
282
283static jas_stream_t *JP2StreamManager(Image *image)
284{
285  static jas_stream_ops_t
286    StreamOperators =
287    {
288      BlobRead,
289      BlobWrite,
290      BlobSeek,
291      BlobClose
292    };
293
294  jas_stream_t
295    *stream;
296
297  StreamManager
298    *source;
299
300  stream=(jas_stream_t *) jas_malloc(sizeof(*stream));
301  if (stream == (jas_stream_t *) NULL)
302    return((jas_stream_t *) NULL);
303  (void) ResetMagickMemory(stream,0,sizeof(*stream));
304  stream->rwlimit_=(-1);
305  stream->obj_=(jas_stream_obj_t *) jas_malloc(sizeof(StreamManager));
306  if (stream->obj_ == (jas_stream_obj_t *) NULL)
307    return((jas_stream_t *) NULL);
308  (void) ResetMagickMemory(stream->obj_,0,sizeof(StreamManager));
309  stream->ops_=(&StreamOperators);
310  stream->openmode_=JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY;
311  stream->bufbase_=(unsigned char *) jas_malloc(JAS_STREAM_BUFSIZE+
312    JAS_STREAM_MAXPUTBACK);
313  if (stream->bufbase_ == (void *) NULL)
314    {
315      stream->bufbase_=stream->tinybuf_;
316      stream->bufsize_=1;
317    }
318  else
319    {
320      stream->bufmode_=JAS_STREAM_FREEBUF | JAS_STREAM_BUFMODEMASK;
321      stream->bufsize_=JAS_STREAM_BUFSIZE;
322    }
323  stream->bufstart_=(&stream->bufbase_[JAS_STREAM_MAXPUTBACK]);
324  stream->ptr_=stream->bufstart_;
325  stream->cnt_=0;
326  source=(StreamManager *) stream->obj_;
327  source->image=image;
328  return(stream);
329}
330
331static Image *ReadJP2Image(const ImageInfo *image_info,ExceptionInfo *exception)
332{
333  Image
334    *image;
335
336  jas_cmprof_t
337    *cm_profile;
338
339  jas_iccprof_t
340    *icc_profile;
341
342  jas_image_t
343    *jp2_image;
344
345  jas_matrix_t
346    *pixels[4];
347
348  jas_stream_t
349    *jp2_stream;
350
351  MagickBooleanType
352    status;
353
354  QuantumAny
355    pixel,
356    range[4];
357
358  register ssize_t
359    i,
360    x;
361
362  register PixelPacket
363    *q;
364
365  size_t
366    maximum_component_depth,
367    number_components,
368    x_step[4],
369    y_step[4];
370
371  ssize_t
372    components[4],
373    y;
374
375  /*
376    Open image file.
377  */
378  assert(image_info != (const ImageInfo *) NULL);
379  assert(image_info->signature == MagickSignature);
380  if (image_info->debug != MagickFalse)
381    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
382      image_info->filename);
383  assert(exception != (ExceptionInfo *) NULL);
384  assert(exception->signature == MagickSignature);
385  image=AcquireImage(image_info);
386  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
387  if (status == MagickFalse)
388    {
389      image=DestroyImageList(image);
390      return((Image *) NULL);
391    }
392  /*
393    Initialize JPEG 2000 API.
394  */
395  jp2_stream=JP2StreamManager(image);
396  if (jp2_stream == (jas_stream_t *) NULL)
397    ThrowReaderException(DelegateError,"UnableToManageJP2Stream");
398  jp2_image=jas_image_decode(jp2_stream,-1,0);
399  if (jp2_image == (jas_image_t *) NULL)
400    {
401      (void) jas_stream_close(jp2_stream);
402      ThrowReaderException(DelegateError,"UnableToDecodeImageFile");
403    }
404  image->columns=jas_image_width(jp2_image);
405  image->rows=jas_image_height(jp2_image);
406  image->compression=JPEG2000Compression;
407  switch (jas_clrspc_fam(jas_image_clrspc(jp2_image)))
408  {
409    case JAS_CLRSPC_FAM_RGB:
410    {
411      SetImageColorspace(image,RGBColorspace);
412      components[0]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_RGB_R);
413      components[1]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_RGB_G);
414      components[2]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_RGB_B);
415      if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0))
416        {
417          (void) jas_stream_close(jp2_stream);
418          jas_image_destroy(jp2_image);
419          ThrowReaderException(CorruptImageError,"MissingImageChannel");
420        }
421      number_components=3;
422      components[3]=jas_image_getcmptbytype(jp2_image,3);
423      if (components[3] > 0)
424        {
425          image->matte=MagickTrue;
426          number_components++;
427        }
428      break;
429    }
430    case JAS_CLRSPC_FAM_GRAY:
431    {
432      SetImageColorspace(image,GRAYColorspace);
433      components[0]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_GRAY_Y);
434      if (components[0] < 0)
435        {
436          (void) jas_stream_close(jp2_stream);
437          jas_image_destroy(jp2_image);
438          ThrowReaderException(CorruptImageError,"MissingImageChannel");
439        }
440      number_components=1;
441      break;
442    }
443    case JAS_CLRSPC_FAM_YCBCR:
444    {
445      SetImageColorspace(image,YCbCrColorspace);
446      components[0]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_YCBCR_Y);
447      components[1]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_YCBCR_CB);
448      components[2]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_YCBCR_CR);
449      if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0))
450        {
451          (void) jas_stream_close(jp2_stream);
452          jas_image_destroy(jp2_image);
453          ThrowReaderException(CorruptImageError,"MissingImageChannel");
454        }
455      number_components=3;
456      components[3]=jas_image_getcmptbytype(jp2_image,JAS_IMAGE_CT_UNKNOWN);
457      if (components[3] > 0)
458        {
459          image->matte=MagickTrue;
460          number_components++;
461        }
462      break;
463    }
464    default:
465    {
466      (void) jas_stream_close(jp2_stream);
467      jas_image_destroy(jp2_image);
468      ThrowReaderException(CoderError,"ColorspaceModelIsNotSupported");
469    }
470  }
471  for (i=0; i < (ssize_t) number_components; i++)
472  {
473    size_t
474      height,
475      width;
476
477    width=(size_t) (jas_image_cmptwidth(jp2_image,components[i])*
478      jas_image_cmpthstep(jp2_image,components[i]));
479    height=(size_t) (jas_image_cmptheight(jp2_image,components[i])*
480      jas_image_cmptvstep(jp2_image,components[i]));
481    x_step[i]=(unsigned int) jas_image_cmpthstep(jp2_image,components[i]);
482    y_step[i]=(unsigned int) jas_image_cmptvstep(jp2_image,components[i]);
483    if ((width != image->columns) || (height != image->rows) ||
484        (jas_image_cmpttlx(jp2_image,components[i]) != 0) ||
485        (jas_image_cmpttly(jp2_image,components[i]) != 0) ||
486        (jas_image_cmptsgnd(jp2_image,components[i]) != MagickFalse))
487      {
488        (void) jas_stream_close(jp2_stream);
489        jas_image_destroy(jp2_image);
490        ThrowReaderException(CoderError,"IrregularChannelGeometryNotSupported");
491      }
492  }
493  /*
494    Convert JPEG 2000 pixels.
495  */
496  image->matte=number_components > 3 ? MagickTrue : MagickFalse;
497  maximum_component_depth=0;
498  for (i=0; i < (ssize_t) number_components; i++)
499  {
500    maximum_component_depth=(unsigned int) MagickMax((size_t)
501      jas_image_cmptprec(jp2_image,components[i]),(size_t)
502      maximum_component_depth);
503    pixels[i]=jas_matrix_create(1,(int) (image->columns/x_step[i]));
504    if (pixels[i] == (jas_matrix_t *) NULL)
505      {
506        for (--i; i >= 0; i--)
507          jas_matrix_destroy(pixels[i]);
508        jas_image_destroy(jp2_image);
509        ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
510      }
511  }
512  image->depth=maximum_component_depth;
513  if (image_info->ping != MagickFalse)
514    {
515      (void) jas_stream_close(jp2_stream);
516      jas_image_destroy(jp2_image);
517      return(GetFirstImageInList(image));
518    }
519  for (i=0; i < (ssize_t) number_components; i++)
520    range[i]=GetQuantumRange((size_t) jas_image_cmptprec(jp2_image,
521      components[i]));
522  for (y=0; y < (ssize_t) image->rows; y++)
523  {
524    q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
525    if (q == (PixelPacket *) NULL)
526      break;
527    for (i=0; i < (ssize_t) number_components; i++)
528      (void) jas_image_readcmpt(jp2_image,(short) components[i],0,
529        (jas_image_coord_t) (y/y_step[i]),(jas_image_coord_t) (image->columns/
530        x_step[i]),1,pixels[i]);
531    switch (number_components)
532    {
533      case 1:
534      {
535        /*
536          Grayscale.
537        */
538        for (x=0; x < (ssize_t) image->columns; x++)
539        {
540          pixel=(QuantumAny) jas_matrix_getv(pixels[0],x/x_step[0]);
541          SetPixelRed(q,ScaleAnyToQuantum((QuantumAny) pixel,
542            range[0]));
543          SetPixelGreen(q,GetPixelRed(q));
544          SetPixelBlue(q,GetPixelRed(q));
545          q++;
546        }
547        break;
548      }
549      case 3:
550      {
551        /*
552          RGB.
553        */
554        for (x=0; x < (ssize_t) image->columns; x++)
555        {
556          pixel=(QuantumAny) jas_matrix_getv(pixels[0],x/x_step[0]);
557          SetPixelRed(q,ScaleAnyToQuantum((QuantumAny) pixel,range[0]));
558          pixel=(QuantumAny) jas_matrix_getv(pixels[1],x/x_step[1]);
559          SetPixelGreen(q,ScaleAnyToQuantum((QuantumAny) pixel,range[1]));
560          pixel=(QuantumAny) jas_matrix_getv(pixels[2],x/x_step[2]);
561          SetPixelBlue(q,ScaleAnyToQuantum((QuantumAny) pixel,range[2]));
562          q++;
563        }
564        break;
565      }
566      case 4:
567      {
568        /*
569          RGBA.
570        */
571        for (x=0; x < (ssize_t) image->columns; x++)
572        {
573          pixel=(QuantumAny) jas_matrix_getv(pixels[0],x/x_step[0]);
574          SetPixelRed(q,ScaleAnyToQuantum((QuantumAny) pixel,
575            range[0]));
576          pixel=(QuantumAny) jas_matrix_getv(pixels[1],x/x_step[1]);
577          SetPixelGreen(q,ScaleAnyToQuantum((QuantumAny) pixel,range[1]));
578          pixel=(QuantumAny) jas_matrix_getv(pixels[2],x/x_step[2]);
579          SetPixelBlue(q,ScaleAnyToQuantum((QuantumAny) pixel,range[2]));
580          pixel=(QuantumAny) jas_matrix_getv(pixels[3],x/x_step[3]);
581          SetPixelAlpha(q,ScaleAnyToQuantum((QuantumAny) pixel,range[3]));
582          q++;
583        }
584        break;
585      }
586    }
587    if (SyncAuthenticPixels(image,exception) == MagickFalse)
588      break;
589    status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
590      image->rows);
591    if (status == MagickFalse)
592      break;
593  }
594  cm_profile=jas_image_cmprof(jp2_image);
595  icc_profile=(jas_iccprof_t *) NULL;
596  if (cm_profile != (jas_cmprof_t *) NULL)
597    icc_profile=jas_iccprof_createfromcmprof(cm_profile);
598  if (icc_profile != (jas_iccprof_t *) NULL)
599    {
600      jas_stream_t
601        *icc_stream;
602
603      icc_stream=jas_stream_memopen(NULL,0);
604      if ((icc_stream != (jas_stream_t *) NULL) &&
605          (jas_iccprof_save(icc_profile,icc_stream) == 0) &&
606          (jas_stream_flush(icc_stream) == 0))
607        {
608          StringInfo
609            *icc_profile,
610            *profile;
611
612          jas_stream_memobj_t
613            *blob;
614
615          /*
616            Extract the icc profile, handle errors without much noise.
617          */
618          blob=(jas_stream_memobj_t *) icc_stream->obj_;
619          if (image->debug != MagickFalse)
620            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
621              "Profile: ICC, %.20g bytes",(double) blob->len_);
622          profile=BlobToStringInfo(blob->buf_,blob->len_);
623          if (profile == (StringInfo *) NULL)
624            ThrowReaderException(CorruptImageError,"MemoryAllocationFailed");
625          icc_profile=(StringInfo *) GetImageProfile(image,"icc");
626          if (icc_profile == (StringInfo *) NULL)
627            (void) SetImageProfile(image,"icc",profile);
628          else
629            (void) ConcatenateStringInfo(icc_profile,profile);
630          profile=DestroyStringInfo(profile);
631          (void) jas_stream_close(icc_stream);
632        }
633    }
634  (void) jas_stream_close(jp2_stream);
635  jas_image_destroy(jp2_image);
636  for (i=0; i < (ssize_t) number_components; i++)
637    jas_matrix_destroy(pixels[i]);
638  return(GetFirstImageInList(image));
639}
640#endif
641
642/*
643%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
644%                                                                             %
645%                                                                             %
646%                                                                             %
647%   R e g i s t e r J P 2 I m a g e                                           %
648%                                                                             %
649%                                                                             %
650%                                                                             %
651%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
652%
653%  RegisterJP2Image() adds attributes for the JP2 image format to the list of
654%  supported formats.  The attributes include the image format tag, a method
655%  method to read and/or write the format, whether the format supports the
656%  saving of more than one frame to the same file or blob, whether the format
657%  supports native in-memory I/O, and a brief description of the format.
658%
659%  The format of the RegisterJP2Image method is:
660%
661%      size_t RegisterJP2Image(void)
662%
663*/
664ModuleExport size_t RegisterJP2Image(void)
665{
666  MagickInfo
667    *entry;
668
669  entry=SetMagickInfo("JP2");
670  entry->description=ConstantString("JPEG-2000 File Format Syntax");
671  entry->module=ConstantString("JP2");
672  entry->magick=(IsImageFormatHandler *) IsJP2;
673  entry->adjoin=MagickFalse;
674  entry->seekable_stream=MagickTrue;
675  entry->thread_support=NoThreadSupport;
676#if defined(MAGICKCORE_JP2_DELEGATE)
677  entry->decoder=(DecodeImageHandler *) ReadJP2Image;
678  entry->encoder=(EncodeImageHandler *) WriteJP2Image;
679#endif
680  (void) RegisterMagickInfo(entry);
681  entry=SetMagickInfo("JPC");
682  entry->description=ConstantString("JPEG-2000 Code Stream Syntax");
683  entry->module=ConstantString("JP2");
684  entry->magick=(IsImageFormatHandler *) IsJPC;
685  entry->adjoin=MagickFalse;
686  entry->seekable_stream=MagickTrue;
687  entry->thread_support=NoThreadSupport;
688#if defined(MAGICKCORE_JP2_DELEGATE)
689  entry->decoder=(DecodeImageHandler *) ReadJP2Image;
690  entry->encoder=(EncodeImageHandler *) WriteJP2Image;
691#endif
692  (void) RegisterMagickInfo(entry);
693  entry=SetMagickInfo("J2C");
694  entry->description=ConstantString("JPEG-2000 Code Stream Syntax");
695  entry->module=ConstantString("JP2");
696  entry->magick=(IsImageFormatHandler *) IsJPC;
697  entry->adjoin=MagickFalse;
698  entry->seekable_stream=MagickTrue;
699  entry->thread_support=NoThreadSupport;
700#if defined(MAGICKCORE_JP2_DELEGATE)
701  entry->decoder=(DecodeImageHandler *) ReadJP2Image;
702  entry->encoder=(EncodeImageHandler *) WriteJP2Image;
703#endif
704  (void) RegisterMagickInfo(entry);
705  entry=SetMagickInfo("J2K");
706  entry->description=ConstantString("JPEG-2000 Code Stream Syntax");
707  entry->module=ConstantString("JP2");
708  entry->magick=(IsImageFormatHandler *) IsJPC;
709  entry->adjoin=MagickFalse;
710  entry->seekable_stream=MagickTrue;
711  entry->thread_support=NoThreadSupport;
712#if defined(MAGICKCORE_JP2_DELEGATE)
713  entry->decoder=(DecodeImageHandler *) ReadJP2Image;
714  entry->encoder=(EncodeImageHandler *) WriteJP2Image;
715#endif
716  (void) RegisterMagickInfo(entry);
717  entry=SetMagickInfo("JPX");
718  entry->description=ConstantString("JPEG-2000 File Format Syntax");
719  entry->module=ConstantString("JP2");
720  entry->magick=(IsImageFormatHandler *) IsJPC;
721  entry->adjoin=MagickFalse;
722  entry->seekable_stream=MagickTrue;
723  entry->thread_support=NoThreadSupport;
724#if defined(MAGICKCORE_JP2_DELEGATE)
725  entry->decoder=(DecodeImageHandler *) ReadJP2Image;
726  entry->encoder=(EncodeImageHandler *) WriteJP2Image;
727#endif
728  (void) RegisterMagickInfo(entry);
729  entry=SetMagickInfo("PGX");
730  entry->description=ConstantString("JPEG-2000 VM Format");
731  entry->module=ConstantString("JP2");
732  entry->magick=(IsImageFormatHandler *) IsJPC;
733  entry->adjoin=MagickFalse;
734  entry->seekable_stream=MagickTrue;
735  entry->thread_support=NoThreadSupport;
736#if defined(MAGICKCORE_JP2_DELEGATE)
737  entry->decoder=(DecodeImageHandler *) ReadJP2Image;
738#endif
739  (void) RegisterMagickInfo(entry);
740#if defined(MAGICKCORE_JP2_DELEGATE)
741  if (instantiate_jp2 == MagickFalse)
742    {
743      jas_init();
744      instantiate_jp2=MagickTrue;
745    }
746#endif
747  return(MagickImageCoderSignature);
748}
749
750/*
751%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
752%                                                                             %
753%                                                                             %
754%                                                                             %
755%   U n r e g i s t e r J P 2 I m a g e                                       %
756%                                                                             %
757%                                                                             %
758%                                                                             %
759%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
760%
761%  UnregisterJP2Image() removes format registrations made by the JP2 module
762%  from the list of supported formats.
763%
764%  The format of the UnregisterJP2Image method is:
765%
766%      UnregisterJP2Image(void)
767%
768*/
769ModuleExport void UnregisterJP2Image(void)
770{
771  (void) UnregisterMagickInfo("PGX");
772  (void) UnregisterMagickInfo("J2K");
773  (void) UnregisterMagickInfo("J2C");
774  (void) UnregisterMagickInfo("JPC");
775  (void) UnregisterMagickInfo("JP2");
776#if defined(MAGICKCORE_JP2_DELEGATE)
777  if (instantiate_jp2 != MagickFalse)
778    {
779      jas_cleanup();
780      instantiate_jp2=MagickFalse;
781    }
782#endif
783}
784
785#if defined(MAGICKCORE_JP2_DELEGATE)
786/*
787%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
788%                                                                             %
789%                                                                             %
790%                                                                             %
791%   W r i t e J P 2 I m a g e                                                 %
792%                                                                             %
793%                                                                             %
794%                                                                             %
795%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
796%
797%  WriteJP2Image() writes an image in the JPEG 2000 image format.
798%
799%  JP2 support originally written by Nathan Brown, nathanbrown@letu.edu
800%
801%  The format of the WriteJP2Image method is:
802%
803%      MagickBooleanType WriteJP2Image(const ImageInfo *image_info,Image *image)
804%
805%  A description of each parameter follows.
806%
807%    o image_info: the image info.
808%
809%    o image:  The image.
810%
811*/
812static MagickBooleanType WriteJP2Image(const ImageInfo *image_info,Image *image)
813{
814  char
815    *key,
816    magick[MaxTextExtent],
817    *options;
818
819  const char
820    *option;
821
822  jas_image_cmptparm_t
823    component_info[4];
824
825  jas_image_t
826    *jp2_image;
827
828  jas_matrix_t
829    *pixels[4];
830
831  jas_stream_t
832    *jp2_stream;
833
834  MagickBooleanType
835    status;
836
837  QuantumAny
838    range;
839
840  register const PixelPacket
841    *p;
842
843  register ssize_t
844    i,
845    x;
846
847  size_t
848    number_components;
849
850  ssize_t
851    format,
852    y;
853
854  /*
855    Open image file.
856  */
857  assert(image_info != (const ImageInfo *) NULL);
858  assert(image_info->signature == MagickSignature);
859  assert(image != (Image *) NULL);
860  assert(image->signature == MagickSignature);
861  if (image->debug != MagickFalse)
862    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
863  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
864  if (status == MagickFalse)
865    return(status);
866  /*
867    Initialize JPEG 2000 API.
868  */
869  if (IssRGBColorspace(image->colorspace) == MagickFalse)
870    (void) TransformImageColorspace(image,sRGBColorspace);
871  jp2_stream=JP2StreamManager(image);
872  if (jp2_stream == (jas_stream_t *) NULL)
873    ThrowWriterException(DelegateError,"UnableToManageJP2Stream");
874  number_components=image->matte ? 4UL : 3UL;
875  if ((image_info->type != TrueColorType) &&
876      (IsGrayImage(image,&image->exception) != MagickFalse))
877    number_components=1;
878  if ((image->columns != (unsigned int) image->columns) ||
879      (image->rows != (unsigned int) image->rows))
880    ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
881  (void) ResetMagickMemory(&component_info,0,sizeof(component_info));
882  for (i=0; i < (ssize_t) number_components; i++)
883  {
884    component_info[i].tlx=0;
885    component_info[i].tly=0;
886    component_info[i].hstep=1;
887    component_info[i].vstep=1;
888    component_info[i].width=(unsigned int) image->columns;
889    component_info[i].height=(unsigned int) image->rows;
890    component_info[i].prec=(int) MagickMax(MagickMin(image->depth,16),2);
891    component_info[i].sgnd=MagickFalse;
892  }
893  jp2_image=jas_image_create((int) number_components,component_info,
894    JAS_CLRSPC_UNKNOWN);
895  if (jp2_image == (jas_image_t *) NULL)
896    ThrowWriterException(DelegateError,"UnableToCreateImage");
897  if (number_components == 1)
898    {
899      /*
900        sRGB Grayscale.
901      */
902      jas_image_setclrspc(jp2_image,JAS_CLRSPC_SGRAY);
903      jas_image_setcmpttype(jp2_image,0,
904        JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y));
905    }
906  else
907    {
908      /*
909        sRGB.
910      */
911      jas_image_setclrspc(jp2_image,JAS_CLRSPC_SRGB);
912      jas_image_setcmpttype(jp2_image,0,
913        (jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R));
914      jas_image_setcmpttype(jp2_image,1,
915        (jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G));
916      jas_image_setcmpttype(jp2_image,2,
917        (jas_image_cmpttype_t) JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B));
918      if (number_components == 4)
919        jas_image_setcmpttype(jp2_image,3,JAS_IMAGE_CT_OPACITY);
920    }
921  /*
922    Convert to JPEG 2000 pixels.
923  */
924  for (i=0; i < (ssize_t) number_components; i++)
925  {
926    pixels[i]=jas_matrix_create(1,(int) image->columns);
927    if (pixels[i] == (jas_matrix_t *) NULL)
928      {
929        for (x=0; x < i; x++)
930          jas_matrix_destroy(pixels[x]);
931        jas_image_destroy(jp2_image);
932        ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
933      }
934  }
935  range=GetQuantumRange((size_t) component_info[0].prec);
936  for (y=0; y < (ssize_t) image->rows; y++)
937  {
938    p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
939    if (p == (const PixelPacket *) NULL)
940      break;
941    for (x=0; x < (ssize_t) image->columns; x++)
942    {
943      if (number_components == 1)
944        jas_matrix_setv(pixels[0],x,(jas_seqent_t) ScaleQuantumToAny(
945          PixelIntensityToQuantum(p),range));
946      else
947        {
948          jas_matrix_setv(pixels[0],x,(jas_seqent_t)
949            ScaleQuantumToAny(GetPixelRed(p),range));
950          jas_matrix_setv(pixels[1],x,(jas_seqent_t)
951            ScaleQuantumToAny(GetPixelGreen(p),range));
952          jas_matrix_setv(pixels[2],x,(jas_seqent_t)
953            ScaleQuantumToAny(GetPixelBlue(p),range));
954          if (number_components > 3)
955            jas_matrix_setv(pixels[3],x,(jas_seqent_t)
956              ScaleQuantumToAny((Quantum) (GetPixelAlpha(p)),range));
957        }
958      p++;
959    }
960    for (i=0; i < (ssize_t) number_components; i++)
961      (void) jas_image_writecmpt(jp2_image,(short) i,0,(unsigned int) y,
962        (unsigned int) image->columns,1,pixels[i]);
963    status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
964      image->rows);
965    if (status == MagickFalse)
966      break;
967  }
968  (void) CopyMagickString(magick,image_info->magick,MaxTextExtent);
969  if (LocaleCompare(magick,"J2C") == 0)
970    (void) CopyMagickString(magick,"JPC",MaxTextExtent);
971  LocaleLower(magick);
972  format=jas_image_strtofmt(magick);
973  options=(char *) NULL;
974  ResetImageOptionIterator(image_info);
975  key=GetNextImageOption(image_info);
976  for ( ; key != (char *) NULL; key=GetNextImageOption(image_info))
977  {
978    option=GetImageOption(image_info,key);
979    if (option == (const char *) NULL)
980      continue;
981    if (LocaleNCompare(key,"jp2:",4) == 0)
982      {
983        (void) ConcatenateString(&options,key+4);
984        if (*option != '\0')
985          {
986            (void) ConcatenateString(&options,"=");
987            (void) ConcatenateString(&options,option);
988          }
989        (void) ConcatenateString(&options," ");
990      }
991  }
992  option=GetImageOption(image_info,"jp2:rate");
993  if ((option == (const char *) NULL) &&
994      (image_info->compression != LosslessJPEGCompression) &&
995      (image->quality != UndefinedCompressionQuality) &&
996      ((double) image->quality <= 99.5) &&
997      ((image->rows*image->columns) > 2500))
998    {
999      char
1000        option[MaxTextExtent];
1001
1002      double
1003        alpha,
1004        header_size,
1005        number_pixels,
1006        rate,
1007        target_size;
1008
1009      alpha=115.0-image->quality;
1010      rate=100.0/(alpha*alpha);
1011      header_size=550.0;
1012      header_size+=(number_components-1)*142;
1013      number_pixels=(double) image->rows*image->columns*number_components*
1014        (GetImageQuantumDepth(image,MagickTrue)/8);
1015      target_size=(number_pixels*rate)+header_size;
1016      rate=target_size/number_pixels;
1017      (void) FormatLocaleString(option,MaxTextExtent,"rate=%g",rate);
1018      (void) ConcatenateString(&options,option);
1019    }
1020  status=jas_image_encode(jp2_image,jp2_stream,format,options) != 0 ?
1021    MagickTrue : MagickFalse;
1022  if (options != (char *) NULL)
1023    options=DestroyString(options);
1024  (void) jas_stream_close(jp2_stream);
1025  for (i=0; i < (ssize_t) number_components; i++)
1026    jas_matrix_destroy(pixels[i]);
1027  jas_image_destroy(jp2_image);
1028  if (status != MagickFalse)
1029    ThrowWriterException(DelegateError,"UnableToEncodeImageFile");
1030  return(MagickTrue);
1031}
1032#endif
Note: See TracBrowser for help on using the repository browser.