root / ImageMagick / trunk / coders / cmyk.c

Revision 12033, 36.6 kB (checked in by cristy, 7 days ago)
Line 
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%                         CCCC  M   M  Y   Y  K   K                           %
7%                        C      MM MM   Y Y   K  K                            %
8%                        C      M M M    Y    KKK                             %
9%                        C      M   M    Y    K  K                            %
10%                         CCCC  M   M    Y    K   K                           %
11%                                                                             %
12%                                                                             %
13%                     Read/Write RAW CMYK Image Format.                       %
14%                                                                             %
15%                              Software Design                                %
16%                                John Cristy                                  %
17%                                 July 1992                                   %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2008 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/blob.h"
44#include "magick/blob-private.h"
45#include "magick/colorspace.h"
46#include "magick/constitute.h"
47#include "magick/exception.h"
48#include "magick/exception-private.h"
49#include "magick/image.h"
50#include "magick/image-private.h"
51#include "magick/list.h"
52#include "magick/magick.h"
53#include "magick/memory_.h"
54#include "magick/monitor.h"
55#include "magick/monitor-private.h"
56#include "magick/pixel-private.h"
57#include "magick/quantum-private.h"
58#include "magick/static.h"
59#include "magick/statistic.h"
60#include "magick/string_.h"
61#include "magick/module.h"
62#include "magick/utility.h"
63
64/*
65  Forward declarations.
66*/
67static MagickBooleanType
68  WriteCMYKImage(const ImageInfo *,Image *);
69
70/*
71%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
72%                                                                             %
73%                                                                             %
74%                                                                             %
75%   R e a d C M Y K I m a g e                                                 %
76%                                                                             %
77%                                                                             %
78%                                                                             %
79%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
80%
81%  ReadCMYKImage() reads an image of raw cyan, magenta, yellow, and black
82%  samples and returns it.  It allocates the memory necessary for the new Image
83%  structure and returns a pointer to the new image.
84%
85%  The format of the ReadCMYKImage method is:
86%
87%      Image *ReadCMYKImage(const ImageInfo *image_info,
88%        ExceptionInfo *exception)
89%
90%  A description of each parameter follows:
91%
92%    o image_info: the image info.
93%
94%    o exception: return any errors or warnings in this structure.
95%
96*/
97static Image *ReadCMYKImage(const ImageInfo *image_info,
98  ExceptionInfo *exception)
99{
100  Image
101    *canvas_image,
102    *image;
103
104  long
105    y;
106
107  MagickBooleanType
108    status;
109
110  QuantumInfo
111    *quantum_info;
112
113  QuantumType
114    quantum_type;
115
116  register const IndexPacket
117    *canvas_indexes;
118
119  register const PixelPacket
120    *p;
121
122  register IndexPacket
123    *indexes;
124
125  register long
126    i,
127    x;
128
129  register PixelPacket
130    *q;
131
132  ssize_t
133    count;
134
135  size_t
136    length;
137
138  unsigned char
139    *pixels;
140
141  /*
142    Open image file.
143  */
144  assert(image_info != (const ImageInfo *) NULL);
145  assert(image_info->signature == MagickSignature);
146  if (image_info->debug != MagickFalse)
147    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
148      image_info->filename);
149  assert(exception != (ExceptionInfo *) NULL);
150  assert(exception->signature == MagickSignature);
151  image=AcquireImage(image_info);
152  if ((image->columns == 0) || (image->rows == 0))
153    ThrowReaderException(OptionError,"MustSpecifyImageSize");
154  image->colorspace=CMYKColorspace;
155  if (image_info->interlace != PartitionInterlace)
156    {
157      status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
158      if (status == MagickFalse)
159        {
160          image=DestroyImageList(image);
161          return((Image *) NULL);
162        }
163      for (i=0; i < image->offset; i++)
164        if (ReadBlobByte(image) == EOF)
165          {
166            ThrowFileException(exception,CorruptImageError,
167              "UnexpectedEndOfFile",image->filename);
168            break;
169          }
170    }
171  /*
172    Create virtual canvas to support cropping (i.e. image.cmyk[100x100+10+20]).
173  */
174  canvas_image=CloneImage(image,image->extract_info.width,1,MagickTrue,
175    exception);
176  (void) SetImageVirtualPixelMethod(canvas_image,BlackVirtualPixelMethod);
177  quantum_info=AcquireQuantumInfo(image_info,canvas_image);
178  pixels=GetQuantumPixels(quantum_info);
179  quantum_type=CMYKQuantum;
180  if (LocaleCompare(image_info->magick,"CMYKA") == 0)
181    {
182      quantum_type=CMYKAQuantum;
183      image->matte=MagickTrue;
184    }
185  if (image_info->number_scenes != 0)
186    while (image->scene < image_info->scene)
187    {
188      /*
189        Skip to next image.
190      */
191      image->scene++;
192      length=GetQuantumExtent(canvas_image,quantum_info,quantum_type);
193      for (y=0; y < (long) image->rows; y++)
194      {
195        count=ReadBlob(image,length,pixels);
196        if (count != (ssize_t) length)
197          break;
198      }
199    }
200  do
201  {
202    /*
203      Read pixels to virtual canvas image then push to image.
204    */
205    if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
206      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
207        break;
208    if ((SetImageExtent(image,0,0) == MagickFalse) ||
209        (SetImageExtent(canvas_image,0,0) == MagickFalse))
210      break;
211    switch (image_info->interlace)
212    {
213      case NoInterlace:
214      default:
215      {
216        /*
217          No interlacing:  CMYKCMYKCMYKCMYKCMYKCMYK...
218        */
219        length=GetQuantumExtent(canvas_image,quantum_info,quantum_type);
220        count=ReadBlob(image,length,pixels);
221        if (count != (ssize_t) length)
222          break;
223        for (y=0; y < (long) image->extract_info.height; y++)
224        {
225          q=GetImagePixels(canvas_image,0,0,canvas_image->columns,1);
226          if (q == (PixelPacket *) NULL)
227            break;
228          length=ImportQuantumPixels(canvas_image,quantum_info,quantum_type,
229            pixels);
230          if (SyncImagePixels(canvas_image) == MagickFalse)
231            break;
232          count=ReadBlob(image,length,pixels);
233          if (((y-image->extract_info.y) >= 0) &&
234              ((y-image->extract_info.y) < (long) image->rows))
235            {
236              p=AcquireImagePixels(canvas_image,canvas_image->extract_info.x,0,
237                canvas_image->columns,1,exception);
238              q=SetImagePixels(image,0,y-image->extract_info.y,image->columns,
239                1);
240              if ((p == (const PixelPacket *) NULL) ||
241                  (q == (PixelPacket *) NULL))
242                break;
243              indexes=GetIndexes(image);
244              canvas_indexes=AcquireIndexes(canvas_image);
245              for (x=0; x < (long) image->columns; x++)
246              {
247                q->red=p->red;
248                q->green=p->green;
249                q->blue=p->blue;
250                indexes[x]=canvas_indexes[image->extract_info.x+x];
251                if (image->matte != MagickFalse)
252                  q->opacity=p->opacity;
253                p++;
254                q++;
255              }
256              if (SyncImagePixels(image) == MagickFalse)
257                break;
258            }
259          if (image->previous == (Image *) NULL)
260            {
261              status=SetImageProgress(image,LoadImageTag,y,image->rows);
262              if (status == MagickFalse)
263                break;
264            }
265        }
266        break;
267      }
268      case LineInterlace:
269      {
270        static QuantumType
271          quantum_types[5] =
272          {
273            CyanQuantum,
274            MagentaQuantum,
275            YellowQuantum,
276            BlackQuantum,
277            OpacityQuantum
278          };
279
280        /*
281          Line interlacing:  CCC...MMM...YYY...KKK...CCC...MMM...
282        */
283        length=GetQuantumExtent(canvas_image,quantum_info,CyanQuantum);
284        count=ReadBlob(image,length,pixels);
285        if (count != (ssize_t) length)
286          break;
287        for (y=0; y < (long) image->extract_info.height; y++)
288        {
289          for (i=0; i < (image->matte != MagickFalse ? 5 : 4); i++)
290          {
291            quantum_type=quantum_types[i];
292            q=GetImagePixels(canvas_image,0,0,canvas_image->columns,1);
293            if (q == (PixelPacket *) NULL)
294              break;
295            length=ImportQuantumPixels(canvas_image,quantum_info,quantum_type,
296              pixels);
297            if (SyncImagePixels(canvas_image) == MagickFalse)
298              break;
299            count=ReadBlob(image,length,pixels);
300            if (((y-image->extract_info.y) >= 0) &&
301                ((y-image->extract_info.y) < (long) image->rows))
302              {
303                p=AcquireImagePixels(canvas_image,canvas_image->extract_info.x,
304                  0,canvas_image->columns,1,exception);
305                q=SetImagePixels(image,0,y-image->extract_info.y,image->columns,
306                  1);
307                if ((p == (const PixelPacket *) NULL) ||
308                    (q == (PixelPacket *) NULL))
309                  break;
310                indexes=GetIndexes(image);
311                canvas_indexes=AcquireIndexes(canvas_image);
312                for (x=0; x < (long) image->columns; x++)
313                {
314                  switch (quantum_type)
315                  {
316                    case CyanQuantum: q->red=p->red; break;
317                    case MagentaQuantum: q->green=p->green; break;
318                    case YellowQuantum: q->blue=p->blue; break;
319                    case BlackQuantum: indexes[x]=
320                      canvas_indexes[image->extract_info.x+x]; break;
321                    case OpacityQuantum: q->opacity=p->opacity; break;
322                    default: break;
323                  }
324                  p++;
325                  q++;
326                }
327                if (SyncImagePixels(image) == MagickFalse)
328                  break;
329              }
330          }
331          if (image->previous == (Image *) NULL)
332            {
333              status=SetImageProgress(image,LoadImageTag,y,image->rows);
334              if (status == MagickFalse)
335                break;
336            }
337        }
338        break;
339      }
340      case PlaneInterlace:
341      case PartitionInterlace:
342      {
343        /*
344          Plane interlacing:  CCC...MMM...YYY...KKK...
345        */
346        if (image_info->interlace == PartitionInterlace)
347          {
348            AppendImageFormat("C",image->filename);
349            status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
350            if (status == MagickFalse)
351              {
352                canvas_image=DestroyImageList(canvas_image);
353                image=DestroyImageList(image);
354                return((Image *) NULL);
355              }
356             for (i=0; i < image->offset; i++)
357               if (ReadBlobByte(image) == EOF)
358                 {
359                   ThrowFileException(exception,CorruptImageError,
360                     "UnexpectedEndOfFile",image->filename);
361                   break;
362                 }
363          }
364        length=GetQuantumExtent(canvas_image,quantum_info,CyanQuantum);
365        count=ReadBlob(image,length,pixels);
366        if (count != (ssize_t) length)
367          break;
368        for (y=0; y < (long) image->extract_info.height; y++)
369        {
370          q=GetImagePixels(canvas_image,0,0,canvas_image->columns,1);
371          if (q == (PixelPacket *) NULL)
372            break;
373          length=ImportQuantumPixels(canvas_image,quantum_info,CyanQuantum,
374            pixels);
375          if (SyncImagePixels(canvas_image) == MagickFalse)
376            break;
377          count=ReadBlob(image,length,pixels);
378          if (((y-image->extract_info.y) >= 0) &&
379              ((y-image->extract_info.y) < (long) image->rows))
380            {
381              p=AcquireImagePixels(canvas_image,canvas_image->extract_info.x,0,
382                canvas_image->columns,1,exception);
383              q=SetImagePixels(image,0,y-image->extract_info.y,image->columns,
384                1);
385              if ((p == (const PixelPacket *) NULL) ||
386                  (q == (PixelPacket *) NULL))
387                break;
388              for (x=0; x < (long) image->columns; x++)
389              {
390                q->red=p->red;
391                p++;
392                q++;
393              }
394              if (SyncImagePixels(image) == MagickFalse)
395                break;
396            }
397        }
398        if (image->previous == (Image *) NULL)
399          {
400            status=SetImageProgress(image,LoadImageTag,1,5);
401            if (status == MagickFalse)
402              break;
403          }
404        if (image_info->interlace == PartitionInterlace)
405          {
406            (void) CloseBlob(image);
407            AppendImageFormat("M",image->filename);
408            status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
409            if (status == MagickFalse)
410              {
411                canvas_image=DestroyImageList(canvas_image);
412                image=DestroyImageList(image);
413                return((Image *) NULL);
414              }
415          }
416        count=ReadBlob(image,length,pixels);
417        if (count != (ssize_t) length)
418          break;
419        for (y=0; y < (long) image->extract_info.height; y++)
420        {
421          q=GetImagePixels(canvas_image,0,0,canvas_image->columns,1);
422          if (q == (PixelPacket *) NULL)
423            break;
424          length=ImportQuantumPixels(canvas_image,quantum_info,MagentaQuantum,
425            pixels);
426          if (SyncImagePixels(canvas_image) == MagickFalse)
427            break;
428          count=ReadBlob(image,length,pixels);
429          if (((y-image->extract_info.y) >= 0) &&
430              ((y-image->extract_info.y) < (long) image->rows))
431            {
432              p=AcquireImagePixels(canvas_image,canvas_image->extract_info.x,0,
433                canvas_image->columns,1,exception);
434              q=SetImagePixels(image,0,y-image->extract_info.y,image->columns,
435                1);
436              if ((p == (const PixelPacket *) NULL) ||
437                  (q == (PixelPacket *) NULL))
438                break;
439              for (x=0; x < (long) image->columns; x++)
440              {
441                q->green=p->green;
442                p++;
443                q++;
444              }
445              if (SyncImagePixels(image) == MagickFalse)
446                break;
447            }
448        }
449        if (image->previous == (Image *) NULL)
450          {
451            status=SetImageProgress(image,LoadImageTag,2,5);
452            if (status == MagickFalse)
453              break;
454          }
455        if (image_info->interlace == PartitionInterlace)
456          {
457            (void) CloseBlob(image);
458            AppendImageFormat("Y",image->filename);
459            status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
460            if (status == MagickFalse)
461              {
462                canvas_image=DestroyImageList(canvas_image);
463                image=DestroyImageList(image);
464                return((Image *) NULL);
465              }
466          }
467        count=ReadBlob(image,length,pixels);
468        if (count != (ssize_t) length)
469          break;
470        for (y=0; y < (long) image->extract_info.height; y++)
471        {
472          q=GetImagePixels(canvas_image,0,0,canvas_image->columns,1);
473          if (q == (PixelPacket *) NULL)
474            break;
475          length=ImportQuantumPixels(canvas_image,quantum_info,YellowQuantum,
476            pixels);
477          if (SyncImagePixels(canvas_image) == MagickFalse)
478            break;
479          count=ReadBlob(image,length,pixels);
480          if (((y-image->extract_info.y) >= 0) &&
481              ((y-image->extract_info.y) < (long) image->rows))
482            {
483              p=AcquireImagePixels(canvas_image,canvas_image->extract_info.x,0,
484                canvas_image->columns,1,exception);
485              q=SetImagePixels(image,0,y-image->extract_info.y,image->columns,
486                1);
487              if ((p == (const PixelPacket *) NULL) ||
488                  (q == (PixelPacket *) NULL))
489                break;
490              for (x=0; x < (long) image->columns; x++)
491              {
492                q->blue=p->blue;
493                p++;
494                q++;
495              }
496              if (SyncImagePixels(image) == MagickFalse)
497                break;
498            }
499        }
500        if (image->previous == (Image *) NULL)
501          {
502            status=SetImageProgress(image,LoadImageTag,3,5);
503            if (status == MagickFalse)
504              break;
505          }
506        if (image_info->interlace == PartitionInterlace)
507          {
508            (void) CloseBlob(image);
509            AppendImageFormat("K",image->filename);
510            status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
511            if (status == MagickFalse)
512              {
513                canvas_image=DestroyImageList(canvas_image);
514                image=DestroyImageList(image);
515                return((Image *) NULL);
516              }
517          }
518        count=ReadBlob(image,length,pixels);
519        if (count != (ssize_t) length)
520          break;
521        for (y=0; y < (long) image->extract_info.height; y++)
522        {
523          q=GetImagePixels(canvas_image,0,0,canvas_image->columns,1);
524          if (q == (PixelPacket *) NULL)
525            break;
526          length=ImportQuantumPixels(canvas_image,quantum_info,YellowQuantum,
527            pixels);
528          if (SyncImagePixels(canvas_image) == MagickFalse)
529            break;
530          count=ReadBlob(image,length,pixels);
531          if (((y-image->extract_info.y) >= 0) &&
532              ((y-image->extract_info.y) < (long) image->rows))
533            {
534              p=AcquireImagePixels(canvas_image,canvas_image->extract_info.x,0,
535                canvas_image->columns,1,exception);
536              q=SetImagePixels(image,0,y-image->extract_info.y,image->columns,
537                1);
538              if ((p == (const PixelPacket *) NULL) ||
539                  (q == (PixelPacket *) NULL))
540                break;
541              indexes=GetIndexes(image);
542              canvas_indexes=AcquireIndexes(canvas_image);
543              for (x=0; x < (long) image->columns; x++)
544              {
545                indexes[x]=canvas_indexes[image->extract_info.x+x];
546                p++;
547                q++;
548              }
549              if (SyncImagePixels(image) == MagickFalse)
550                break;
551            }
552        }
553        if (image->previous == (Image *) NULL)
554          {
555            status=SetImageProgress(image,LoadImageTag,4,5);
556            if (status == MagickFalse)
557              break;
558          }
559        if (image->matte != MagickFalse)
560          {
561            if (image_info->interlace == PartitionInterlace)
562              {
563                (void) CloseBlob(image);
564                AppendImageFormat("A",image->filename);
565                status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
566                if (status == MagickFalse)
567                  {
568                    canvas_image=DestroyImageList(canvas_image);
569                    image=DestroyImageList(image);
570                    return((Image *) NULL);
571                  }
572              }
573            count=ReadBlob(image,length,pixels);
574            if (count != (ssize_t) length)
575              break;
576            for (y=0; y < (long) image->extract_info.height; y++)
577            {
578              q=GetImagePixels(canvas_image,0,0,canvas_image->columns,1);
579              if (q == (PixelPacket *) NULL)
580                break;
581              length=ImportQuantumPixels(canvas_image,quantum_info,AlphaQuantum,
582                pixels);
583              if (SyncImagePixels(canvas_image) == MagickFalse)
584                 break;
585              count=ReadBlob(image,length,pixels);
586              if (((y-image->extract_info.y) >= 0) &&
587                  ((y-image->extract_info.y) < (long) image->rows))
588                {
589                  p=AcquireImagePixels(canvas_image,
590                    canvas_image->extract_info.x,0,canvas_image->columns,1,
591                    exception);
592                  q=SetImagePixels(image,0,y-image->extract_info.y,
593                    image->columns,1);
594                  if ((p == (const PixelPacket *) NULL) ||
595                      (q == (PixelPacket *) NULL))
596                    break;
597                  for (x=0; x < (long) image->columns; x++)
598                  {
599                    q->opacity=p->opacity;
600                    p++;
601                    q++;
602                  }
603                  if (SyncImagePixels(image) == MagickFalse)
604                    break;
605                }
606            }
607          }
608        if (image->previous == (Image *) NULL)
609          {
610            status=SetImageProgress(image,LoadImageTag,5,5);
611            if (status == MagickFalse)
612              break;
613          }
614        break;
615      }
616    }
617    SetQuantumImageType(image,quantum_type);
618    /*
619      Proceed to next image.
620    */
621    if (image_info->number_scenes != 0)
622      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
623        break;
624    if (count == (ssize_t) length)
625      {
626        /*
627          Allocate next image structure.
628        */
629        AcquireNextImage(image_info,image);
630        if (GetNextImageInList(image) == (Image *) NULL)
631          {
632            image=DestroyImageList(image);
633            return((Image *) NULL);
634          }
635        image=SyncNextImageInList(image);
636        status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
637          GetBlobSize(image));
638        if (status == MagickFalse)
639          break;
640      }
641  } while (count == (ssize_t) length);
642  quantum_info=DestroyQuantumInfo(quantum_info);
643  InheritException(exception,&canvas_image->exception);
644  canvas_image=DestroyImage(canvas_image);
645  (void) CloseBlob(image);
646  return(GetFirstImageInList(image));
647}
648
649/*
650%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
651%                                                                             %
652%                                                                             %
653%                                                                             %
654%   R e g i s t e r C M Y K I m a g e                                         %
655%                                                                             %
656%                                                                             %
657%                                                                             %
658%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
659%
660%  RegisterCMYKImage() adds attributes for the CMYK image format to
661%  the list of supported formats.  The attributes include the image format
662%  tag, a method to read and/or write the format, whether the format
663%  supports the saving of more than one frame to the same file or blob,
664%  whether the format supports native in-memory I/O, and a brief
665%  description of the format.
666%
667%  The format of the RegisterCMYKImage method is:
668%
669%      unsigned long RegisterCMYKImage(void)
670%
671*/
672ModuleExport unsigned long RegisterCMYKImage(void)
673{
674  MagickInfo
675    *entry;
676
677  entry=SetMagickInfo("CMYK");
678  entry->decoder=(DecodeImageHandler *) ReadCMYKImage;
679  entry->encoder=(EncodeImageHandler *) WriteCMYKImage;
680  entry->raw=MagickTrue;
681  entry->endian_support=MagickTrue;
682  entry->description=ConstantString(
683    "Raw cyan, magenta, yellow, and black samples");
684  entry->module=ConstantString("CMYK");
685  (void) RegisterMagickInfo(entry);
686  entry=SetMagickInfo("CMYKA");
687  entry->decoder=(DecodeImageHandler *) ReadCMYKImage;
688  entry->encoder=(EncodeImageHandler *) WriteCMYKImage;
689  entry->raw=MagickTrue;
690  entry->endian_support=MagickTrue;
691  entry->description=ConstantString(
692    "Raw cyan, magenta, yellow, black, and opacity samples");
693  entry->module=ConstantString("CMYK");
694  (void) RegisterMagickInfo(entry);
695  return(MagickImageCoderSignature);
696}
697
698/*
699%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
700%                                                                             %
701%                                                                             %
702%                                                                             %
703%   U n r e g i s t e r C M Y K I m a g e                                     %
704%                                                                             %
705%                                                                             %
706%                                                                             %
707%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
708%
709%  UnregisterCMYKImage() removes format registrations made by the
710%  CMYK module from the list of supported formats.
711%
712%  The format of the UnregisterCMYKImage method is:
713%
714%      UnregisterCMYKImage(void)
715%
716*/
717ModuleExport void UnregisterCMYKImage(void)
718{
719  (void) UnregisterMagickInfo("CMYK");
720  (void) UnregisterMagickInfo("CMYKA");
721}
722
723/*
724%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
725%                                                                             %
726%                                                                             %
727%                                                                             %
728%   W r i t e C M Y K I m a g e                                               %
729%                                                                             %
730%                                                                             %
731%                                                                             %
732%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
733%
734%  WriteCMYKImage() writes an image to a file in cyan, magenta, yellow, and
735%  black raw image format.
736%
737%  The format of the WriteCMYKImage method is:
738%
739%      MagickBooleanType WriteCMYKImage(const ImageInfo *image_info,
740%        Image *image)
741%
742%  A description of each parameter follows.
743%
744%    o image_info: the image info.
745%
746%    o image:  The image.
747%
748*/
749static MagickBooleanType WriteCMYKImage(const ImageInfo *image_info,
750  Image *image)
751{
752  long
753    y;
754
755  MagickBooleanType
756    status;
757
758  MagickOffsetType
759    scene;
760
761  QuantumInfo
762    *quantum_info;
763
764  QuantumType
765    quantum_type;
766
767  register const PixelPacket
768    *p;
769
770  ssize_t
771    count;
772
773  size_t
774    length;
775
776  unsigned char
777    *pixels;
778
779  /*
780    Allocate memory for pixels.
781  */
782  assert(image_info != (const ImageInfo *) NULL);
783  assert(image_info->signature == MagickSignature);
784  assert(image != (Image *) NULL);
785  assert(image->signature == MagickSignature);
786  if (image->debug != MagickFalse)
787    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
788  if (image_info->interlace != PartitionInterlace)
789    {
790      /*
791        Open output image file.
792      */
793      status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
794      if (status == MagickFalse)
795        return(status);
796    }
797  quantum_type=CMYKQuantum;
798  if (LocaleCompare(image_info->magick,"CMYKA") == 0)
799    {
800      quantum_type=CMYKAQuantum;
801      image->matte=MagickTrue;
802    }
803  scene=0;
804  do
805  {
806    /*
807      Convert MIFF to CMYK raster pixels.
808    */
809    if (image->colorspace != RGBColorspace)
810      (void) SetImageColorspace(image,CMYKColorspace);
811    if ((LocaleCompare(image_info->magick,"CMYKA") == 0) &&
812        (image->matte == MagickFalse))
813      (void) SetImageAlphaChannel(image,ResetAlphaChannel);
814    quantum_info=AcquireQuantumInfo(image_info,image);
815    pixels=GetQuantumPixels(quantum_info);
816    switch (image_info->interlace)
817    {
818      case NoInterlace:
819      default:
820      {
821        /*
822          No interlacing:  CMYKCMYKCMYKCMYKCMYKCMYK...
823        */
824        for (y=0; y < (long) image->rows; y++)
825        {
826          p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
827          if (p == (const PixelPacket *) NULL)
828            break;
829          length=ExportQuantumPixels(image,quantum_info,quantum_type,pixels);
830          count=WriteBlob(image,length,pixels);
831          if (count != (ssize_t) length)
832            break;
833          if (image->previous == (Image *) NULL)
834            {
835              status=SetImageProgress(image,SaveImageTag,y,image->rows);
836              if (status == MagickFalse)
837                break;
838            }
839        }
840        break;
841      }
842      case LineInterlace:
843      {
844        /*
845          Line interlacing:  CCC...MMM...YYY...KKK...CCC...MMM...
846        */
847        for (y=0; y < (long) image->rows; y++)
848        {
849          p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
850          if (p == (const PixelPacket *) NULL)
851            break;
852          length=ExportQuantumPixels(image,quantum_info,CyanQuantum,pixels);
853          count=WriteBlob(image,length,pixels);
854          if (count != (ssize_t) length)
855            break;
856          length=ExportQuantumPixels(image,quantum_info,MagentaQuantum,pixels);
857          count=WriteBlob(image,length,pixels);
858          if (count != (ssize_t) length)
859            break;
860          length=ExportQuantumPixels(image,quantum_info,YellowQuantum,pixels);
861          count=WriteBlob(image,length,pixels);
862          if (count != (ssize_t) length)
863            break;
864          length=ExportQuantumPixels(image,quantum_info,BlackQuantum,pixels);
865          count=WriteBlob(image,length,pixels);
866          if (count != (ssize_t) length)
867            break;
868          if (quantum_type == CMYKAQuantum)
869            {
870              length=ExportQuantumPixels(image,quantum_info,AlphaQuantum,
871                pixels);
872              count=WriteBlob(image,length,pixels);
873              if (count != (ssize_t) length)
874                break;
875            }
876          if (image->previous == (Image *) NULL)
877            {
878              status=SetImageProgress(image,SaveImageTag,y,image->rows);
879              if (status == MagickFalse)
880                break;
881            }
882        }
883        break;
884      }
885      case PlaneInterlace:
886      case PartitionInterlace:
887      {
888        /*
889          Plane interlacing:  CCCCCC...MMMMMM...YYYYYY...KKKKKK
890        */
891        if (image_info->interlace == PartitionInterlace)
892          {
893            AppendImageFormat("C",image->filename);
894            status=OpenBlob(image_info,image,WriteBinaryBlobMode,
895              &image->exception);
896            if (status == MagickFalse)
897              return(status);
898          }
899        for (y=0; y < (long) image->rows; y++)
900        {
901          p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
902          if (p == (const PixelPacket *) NULL)
903            break;
904          length=ExportQuantumPixels(image,quantum_info,CyanQuantum,pixels);
905          count=WriteBlob(image,length,pixels);
906          if (count != (ssize_t) length)
907            break;
908        }
909        if (image->previous == (Image *) NULL)
910          {
911            status=SetImageProgress(image,SaveImageTag,1,5);
912            if (status == MagickFalse)
913              break;
914          }
915        if (image_info->interlace == PartitionInterlace)
916          {
917            (void) CloseBlob(image);
918            AppendImageFormat("M",image->filename);
919            status=OpenBlob(image_info,image,WriteBinaryBlobMode,
920              &image->exception);
921            if (status == MagickFalse)
922              return(status);
923          }
924        for (y=0; y < (long) image->rows; y++)
925        {
926          p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
927          if (p == (const PixelPacket *) NULL)
928            break;
929          length=ExportQuantumPixels(image,quantum_info,MagentaQuantum,pixels);
930          count=WriteBlob(image,length,pixels);
931          if (count != (ssize_t) length)
932            break;
933        }
934        if (image->previous == (Image *) NULL)
935          {
936            status=SetImageProgress(image,SaveImageTag,2,5);
937            if (status == MagickFalse)
938              break;
939          }
940        if (image_info->interlace == PartitionInterlace)
941          {
942            (void) CloseBlob(image);
943            AppendImageFormat("Y",image->filename);
944            status=OpenBlob(image_info,image,WriteBinaryBlobMode,
945              &image->exception);
946            if (status == MagickFalse)
947              return(status);
948          }
949        for (y=0; y < (long) image->rows; y++)
950        {
951          p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
952          if (p == (const PixelPacket *) NULL)
953            break;
954          length=ExportQuantumPixels(image,quantum_info,YellowQuantum,pixels);
955          count=WriteBlob(image,length,pixels);
956          if (count != (ssize_t) length)
957            break;
958        }
959        if (image_info->interlace == PartitionInterlace)
960          {
961            (void) CloseBlob(image);
962            AppendImageFormat("K",image->filename);
963            status=OpenBlob(image_info,image,WriteBinaryBlobMode,
964              &image->exception);
965            if (status == MagickFalse)
966              return(status);
967          }
968        for (y=0; y < (long) image->rows; y++)
969        {
970          p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
971          if (p == (const PixelPacket *) NULL)
972            break;
973          length=ExportQuantumPixels(image,quantum_info,BlackQuantum,pixels);
974          count=WriteBlob(image,length,pixels);
975          if (count != (ssize_t) length)
976            break;
977        }
978        if (image->previous == (Image *) NULL)
979          {
980            status=SetImageProgress(image,SaveImageTag,3,5);
981            if (status == MagickFalse)
982              break;
983          }
984        if (quantum_type == CMYKAQuantum)
985          {
986            if (image_info->interlace == PartitionInterlace)
987              {
988                (void) CloseBlob(image);
989                AppendImageFormat("A",image->filename);
990                status=OpenBlob(image_info,image,WriteB