source: ImageMagick/trunk/coders/jp2.c @ 4683

Revision 4683, 33.2 KB checked in by glennrp, 23 months ago (diff)

spelling (initialize)

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