MagickWand 6.9.6
Loading...
Searching...
No Matches
wand-view.c
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% W W AAA N N DDDD %
6% W W A A NN N D D %
7% W W W AAAAA N N N D D %
8% WW WW A A N NN D D %
9% W W A A N N DDDD %
10% %
11% V V IIIII EEEEE W W %
12% V V I E W W %
13% V V I EEE W W W %
14% V V I E WW WW %
15% V IIIII EEEEE W W %
16% %
17% %
18% MagickWand Wand View Methods %
19% %
20% Software Design %
21% Cristy %
22% March 2003 %
23% %
24% %
25% Copyright 1999 ImageMagick Studio LLC, a non-profit organization %
26% dedicated to making software imaging solutions freely available. %
27% %
28% You may not use this file except in compliance with the License. You may %
29% obtain a copy of the License at %
30% %
31% https://imagemagick.org/script/license.php %
32% %
33% Unless required by applicable law or agreed to in writing, software %
34% distributed under the License is distributed on an "AS IS" BASIS, %
35% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
36% See the License for the specific language governing permissions and %
37% limitations under the License. %
38% %
39%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
40%
41%
42%
43*/
44
45/*
46 Include declarations.
47*/
48#include "wand/studio.h"
49#include "wand/MagickWand.h"
50#include "wand/magick-wand-private.h"
51#include "wand/wand.h"
52#include "magick/monitor-private.h"
53#include "magick/thread-private.h"
54/*
55 Define declarations.
56*/
57#define WandViewId "WandView"
58
59/*
60 Typedef declarations.
61*/
63{
64 size_t
65 id;
66
67 char
68 name[MaxTextExtent],
69 *description;
70
71 RectangleInfo
72 extent;
73
75 *wand;
76
77 CacheView
78 *view;
79
80 size_t
81 number_threads;
82
84 ***pixel_wands;
85
86 ExceptionInfo
87 *exception;
88
89 MagickBooleanType
90 debug;
91
92 size_t
93 signature;
94};
95
96/*
97%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
98% %
99% %
100% %
101% C l o n e W a n d V i e w %
102% %
103% %
104% %
105%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
106%
107% CloneWandView() makes a copy of the specified wand view.
108%
109% The format of the CloneWandView method is:
110%
111% WandView *CloneWandView(const WandView *wand_view)
112%
113% A description of each parameter follows:
114%
115% o wand_view: the wand view.
116%
117*/
118WandExport WandView *CloneWandView(const WandView *wand_view)
119{
121 *clone_view;
122
123 ssize_t
124 i;
125
126 assert(wand_view != (WandView *) NULL);
127 assert(wand_view->signature == WandSignature);
128 if (wand_view->debug != MagickFalse)
129 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand_view->name);
130 clone_view=(WandView *) AcquireCriticalMemory(sizeof(*clone_view));
131 (void) memset(clone_view,0,sizeof(*clone_view));
132 clone_view->id=AcquireWandId();
133 (void) FormatLocaleString(clone_view->name,MaxTextExtent,"%s-%.20g",
134 WandViewId,(double) clone_view->id);
135 clone_view->description=ConstantString(wand_view->description);
136 clone_view->view=CloneCacheView(wand_view->view);
137 clone_view->extent=wand_view->extent;
138 clone_view->number_threads=wand_view->number_threads;
139 clone_view->exception=AcquireExceptionInfo();
140 InheritException(clone_view->exception,wand_view->exception);
141 for (i=0; i < (ssize_t) wand_view->number_threads; i++)
142 clone_view->pixel_wands[i]=ClonePixelWands((const PixelWand **)
143 wand_view->pixel_wands[i],wand_view->extent.width);
144 clone_view->debug=wand_view->debug;
145 if (clone_view->debug != MagickFalse)
146 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",clone_view->name);
147 clone_view->signature=WandSignature;
148 return(clone_view);
149}
150
151/*
152%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
153% %
154% %
155% %
156% D e s t r o y W a n d V i e w %
157% %
158% %
159% %
160%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
161%
162% DestroyWandView() deallocates memory associated with a wand view.
163%
164% The format of the DestroyWandView method is:
165%
166% WandView *DestroyWandView(WandView *wand_view)
167%
168% A description of each parameter follows:
169%
170% o wand_view: the wand view.
171%
172*/
173
174static PixelWand ***DestroyPixelsTLS(PixelWand ***pixel_wands,
175 const size_t number_wands,const size_t number_threads)
176{
177 ssize_t
178 i;
179
180 assert(pixel_wands != (PixelWand ***) NULL);
181 for (i=0; i < (ssize_t) number_threads; i++)
182 if (pixel_wands[i] != (PixelWand **) NULL)
183 pixel_wands[i]=DestroyPixelWands(pixel_wands[i],number_wands);
184 pixel_wands=(PixelWand ***) RelinquishMagickMemory(pixel_wands);
185 return(pixel_wands);
186}
187
188WandExport WandView *DestroyWandView(WandView *wand_view)
189{
190 assert(wand_view != (WandView *) NULL);
191 assert(wand_view->signature == WandSignature);
192 wand_view->pixel_wands=DestroyPixelsTLS(wand_view->pixel_wands,
193 wand_view->extent.width,wand_view->number_threads);
194 wand_view->view=DestroyCacheView(wand_view->view);
195 wand_view->exception=DestroyExceptionInfo(wand_view->exception);
196 wand_view->signature=(~WandSignature);
197 RelinquishWandId(wand_view->id);
198 wand_view=(WandView *) RelinquishMagickMemory(wand_view);
199 return(wand_view);
200}
201
202/*
203%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
204% %
205% %
206% %
207% D u p l e x T r a n s f e r W a n d V i e w I t e r a t o r %
208% %
209% %
210% %
211%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
212%
213% DuplexTransferWandViewIterator() iterates over three wand views in
214% parallel and calls your transfer method for each scanline of the view. The
215% source and duplex pixel extent is not confined to the image canvas-- that is
216% you can include negative offsets or widths or heights that exceed the image
217% dimension. However, the destination wand view is confined to the image
218% canvas-- that is no negative offsets or widths or heights that exceed the
219% image dimension are permitted.
220%
221% The callback signature is:
222%
223% MagickBooleanType DuplexTransferImageViewMethod(const WandView *source,
224% const WandView *duplex,WandView *destination,const ssize_t y,
225% const int thread_id,void *context)
226%
227% Use this pragma if the view is not single threaded:
228%
229% #pragma omp critical
230%
231% to define a section of code in your callback transfer method that must be
232% executed by a single thread at a time.
233%
234% The format of the DuplexTransferWandViewIterator method is:
235%
236% MagickBooleanType DuplexTransferWandViewIterator(WandView *source,
237% WandView *duplex,WandView *destination,
238% DuplexTransferWandViewMethod transfer,void *context)
239%
240% A description of each parameter follows:
241%
242% o source: the source wand view.
243%
244% o duplex: the duplex wand view.
245%
246% o destination: the destination wand view.
247%
248% o transfer: the transfer callback method.
249%
250% o context: the user defined context.
251%
252*/
253WandExport MagickBooleanType DuplexTransferWandViewIterator(WandView *source,
254 WandView *duplex,WandView *destination,DuplexTransferWandViewMethod transfer,
255 void *context)
256{
257 ExceptionInfo
258 *exception;
259
260 Image
261 *destination_image,
262 *duplex_image,
263 *source_image;
264
265 MagickBooleanType
266 status;
267
268 MagickOffsetType
269 progress;
270
271#if defined(MAGICKCORE_OPENMP_SUPPORT)
272 size_t
273 height;
274#endif
275
276 ssize_t
277 y;
278
279 assert(source != (WandView *) NULL);
280 assert(source->signature == WandSignature);
281 if (transfer == (DuplexTransferWandViewMethod) NULL)
282 return(MagickFalse);
283 source_image=source->wand->images;
284 duplex_image=duplex->wand->images;
285 destination_image=destination->wand->images;
286 if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
287 return(MagickFalse);
288 status=MagickTrue;
289 progress=0;
290 exception=destination->exception;
291#if defined(MAGICKCORE_OPENMP_SUPPORT)
292 height=(size_t) (source->extent.height-source->extent.y);
293 #pragma omp parallel for schedule(static) shared(progress,status) \
294 magick_number_threads(source_image,destination_image,height,1)
295#endif
296 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
297 {
298 const int
299 id = GetOpenMPThreadId();
300
301 MagickBooleanType
302 sync;
303
304 const IndexPacket
305 *magick_restrict duplex_indexes,
306 *magick_restrict indexes;
307
308 const PixelPacket
309 *magick_restrict duplex_pixels,
310 *magick_restrict pixels;
311
312 IndexPacket
313 *magick_restrict destination_indexes;
314
315 ssize_t
316 x;
317
318 PixelPacket
319 *magick_restrict destination_pixels;
320
321 if (status == MagickFalse)
322 continue;
323 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
324 source->extent.width,1,source->exception);
325 if (pixels == (const PixelPacket *) NULL)
326 {
327 status=MagickFalse;
328 continue;
329 }
330 indexes=GetCacheViewVirtualIndexQueue(source->view);
331 for (x=0; x < (ssize_t) source->extent.width; x++)
332 PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
333 if (source_image->colorspace == CMYKColorspace)
334 for (x=0; x < (ssize_t) source->extent.width; x++)
335 PixelSetBlackQuantum(source->pixel_wands[id][x],
336 GetPixelBlack(indexes+x));
337 if (source_image->storage_class == PseudoClass)
338 for (x=0; x < (ssize_t) source->extent.width; x++)
339 PixelSetIndex(source->pixel_wands[id][x],
340 GetPixelIndex(indexes+x));
341 duplex_pixels=GetCacheViewVirtualPixels(duplex->view,duplex->extent.x,y,
342 duplex->extent.width,1,duplex->exception);
343 if (duplex_pixels == (const PixelPacket *) NULL)
344 {
345 status=MagickFalse;
346 continue;
347 }
348 duplex_indexes=GetCacheViewVirtualIndexQueue(duplex->view);
349 for (x=0; x < (ssize_t) duplex->extent.width; x++)
350 PixelSetQuantumColor(duplex->pixel_wands[id][x],duplex_pixels+x);
351 if (duplex_image->colorspace == CMYKColorspace)
352 for (x=0; x < (ssize_t) duplex->extent.width; x++)
353 PixelSetBlackQuantum(duplex->pixel_wands[id][x],
354 GetPixelBlack(duplex_indexes+x));
355 if (duplex_image->storage_class == PseudoClass)
356 for (x=0; x < (ssize_t) duplex->extent.width; x++)
357 PixelSetIndex(duplex->pixel_wands[id][x],
358 GetPixelIndex(duplex_indexes+x));
359 destination_pixels=GetCacheViewAuthenticPixels(destination->view,
360 destination->extent.x,y,destination->extent.width,1,exception);
361 if (destination_pixels == (PixelPacket *) NULL)
362 {
363 status=MagickFalse;
364 continue;
365 }
366 destination_indexes=GetCacheViewAuthenticIndexQueue(destination->view);
367 for (x=0; x < (ssize_t) destination->extent.width; x++)
368 PixelSetQuantumColor(destination->pixel_wands[id][x],
369 destination_pixels+x);
370 if (destination_image->colorspace == CMYKColorspace)
371 for (x=0; x < (ssize_t) destination->extent.width; x++)
372 PixelSetBlackQuantum(destination->pixel_wands[id][x],
373 GetPixelBlack(destination_indexes+x));
374 if (destination_image->storage_class == PseudoClass)
375 for (x=0; x < (ssize_t) destination->extent.width; x++)
376 PixelSetIndex(destination->pixel_wands[id][x],
377 GetPixelIndex(destination_indexes+x));
378 if (transfer(source,duplex,destination,y,id,context) == MagickFalse)
379 status=MagickFalse;
380 for (x=0; x < (ssize_t) destination->extent.width; x++)
381 PixelGetQuantumColor(destination->pixel_wands[id][x],
382 destination_pixels+x);
383 if (destination_image->colorspace == CMYKColorspace)
384 for (x=0; x < (ssize_t) destination->extent.width; x++)
385 SetPixelBlack(destination_indexes+x,PixelGetBlackQuantum(
386 destination->pixel_wands[id][x]));
387 sync=SyncCacheViewAuthenticPixels(destination->view,exception);
388 if (sync == MagickFalse)
389 {
390 InheritException(destination->exception,GetCacheViewException(
391 source->view));
392 status=MagickFalse;
393 }
394 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
395 {
396 MagickBooleanType
397 proceed;
398
399#if defined(MAGICKCORE_OPENMP_SUPPORT)
400 #pragma omp atomic
401#endif
402 progress++;
403 proceed=SetImageProgress(source_image,source->description,progress,
404 source->extent.height);
405 if (proceed == MagickFalse)
406 status=MagickFalse;
407 }
408 }
409 return(status);
410}
411
412/*
413%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
414% %
415% %
416% %
417% G e t W a n d V i e w E x c e p t i o n %
418% %
419% %
420% %
421%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
422%
423% GetWandViewException() returns the severity, reason, and description of any
424% error that occurs when utilizing a wand view.
425%
426% The format of the GetWandViewException method is:
427%
428% char *GetWandViewException(const WandView *wand_view,
429% ExceptionType *severity)
430%
431% A description of each parameter follows:
432%
433% o wand_view: the pixel wand_view.
434%
435% o severity: the severity of the error is returned here.
436%
437*/
438WandExport char *GetWandViewException(const WandView *wand_view,
439 ExceptionType *severity)
440{
441 char
442 *description;
443
444 assert(wand_view != (const WandView *) NULL);
445 assert(wand_view->signature == WandSignature);
446 if (wand_view->debug != MagickFalse)
447 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand_view->name);
448 assert(severity != (ExceptionType *) NULL);
449 *severity=wand_view->exception->severity;
450 description=(char *) AcquireQuantumMemory(2UL*MaxTextExtent,
451 sizeof(*description));
452 if (description == (char *) NULL)
453 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
454 wand_view->name);
455 *description='\0';
456 if (wand_view->exception->reason != (char *) NULL)
457 (void) CopyMagickString(description,GetLocaleExceptionMessage(
458 wand_view->exception->severity,wand_view->exception->reason),
459 MaxTextExtent);
460 if (wand_view->exception->description != (char *) NULL)
461 {
462 (void) ConcatenateMagickString(description," (",MaxTextExtent);
463 (void) ConcatenateMagickString(description,GetLocaleExceptionMessage(
464 wand_view->exception->severity,wand_view->exception->description),
465 MaxTextExtent);
466 (void) ConcatenateMagickString(description,")",MaxTextExtent);
467 }
468 return(description);
469}
470
471/*
472%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
473% %
474% %
475% %
476% G e t W a n d V i e w E x t e n t %
477% %
478% %
479% %
480%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
481%
482% GetWandViewExtent() returns the wand view extent.
483%
484% The format of the GetWandViewExtent method is:
485%
486% RectangleInfo GetWandViewExtent(const WandView *wand_view)
487%
488% A description of each parameter follows:
489%
490% o wand_view: the wand view.
491%
492*/
493WandExport RectangleInfo GetWandViewExtent(const WandView *wand_view)
494{
495 assert(wand_view != (WandView *) NULL);
496 assert(wand_view->signature == WandSignature);
497 return(wand_view->extent);
498}
499
500/*
501%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
502% %
503% %
504% %
505% G e t W a n d V i e w I t e r a t o r %
506% %
507% %
508% %
509%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
510%
511% GetWandViewIterator() iterates over the wand view in parallel and calls
512% your get method for each scanline of the view. The pixel extent is
513% not confined to the image canvas-- that is you can include negative offsets
514% or widths or heights that exceed the image dimension. Any updates to
515% the pixels in your callback are ignored.
516%
517% The callback signature is:
518%
519% MagickBooleanType GetImageViewMethod(const WandView *source,
520% const ssize_t y,const int thread_id,void *context)
521%
522% Use this pragma if the view is not single threaded:
523%
524% #pragma omp critical
525%
526% to define a section of code in your callback get method that must be
527% executed by a single thread at a time.
528%
529% The format of the GetWandViewIterator method is:
530%
531% MagickBooleanType GetWandViewIterator(WandView *source,
532% GetWandViewMethod get,void *context)
533%
534% A description of each parameter follows:
535%
536% o source: the source wand view.
537%
538% o get: the get callback method.
539%
540% o context: the user defined context.
541%
542*/
543WandExport MagickBooleanType GetWandViewIterator(WandView *source,
544 GetWandViewMethod get,void *context)
545{
546 Image
547 *source_image;
548
549 MagickBooleanType
550 status;
551
552 MagickOffsetType
553 progress;
554
555#if defined(MAGICKCORE_OPENMP_SUPPORT)
556 size_t
557 height;
558#endif
559
560 ssize_t
561 y;
562
563 assert(source != (WandView *) NULL);
564 assert(source->signature == WandSignature);
565 if (get == (GetWandViewMethod) NULL)
566 return(MagickFalse);
567 source_image=source->wand->images;
568 status=MagickTrue;
569 progress=0;
570#if defined(MAGICKCORE_OPENMP_SUPPORT)
571 height=(size_t) (source->extent.height-source->extent.y);
572 #pragma omp parallel for schedule(static) shared(progress,status) \
573 magick_number_threads(source_image,source_image,height,1)
574#endif
575 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
576 {
577 const int
578 id = GetOpenMPThreadId();
579
580 const IndexPacket
581 *indexes;
582
583 const PixelPacket
584 *pixels;
585
586 ssize_t
587 x;
588
589 if (status == MagickFalse)
590 continue;
591 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
592 source->extent.width,1,source->exception);
593 if (pixels == (const PixelPacket *) NULL)
594 {
595 status=MagickFalse;
596 continue;
597 }
598 indexes=GetCacheViewVirtualIndexQueue(source->view);
599 for (x=0; x < (ssize_t) source->extent.width; x++)
600 PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
601 if (source_image->colorspace == CMYKColorspace)
602 for (x=0; x < (ssize_t) source->extent.width; x++)
603 PixelSetBlackQuantum(source->pixel_wands[id][x],
604 GetPixelBlack(indexes+x));
605 if (source_image->storage_class == PseudoClass)
606 for (x=0; x < (ssize_t) source->extent.width; x++)
607 PixelSetIndex(source->pixel_wands[id][x],
608 GetPixelIndex(indexes+x));
609 if (get(source,y,id,context) == MagickFalse)
610 status=MagickFalse;
611 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
612 {
613 MagickBooleanType
614 proceed;
615
616#if defined(MAGICKCORE_OPENMP_SUPPORT)
617 #pragma omp atomic
618#endif
619 progress++;
620 proceed=SetImageProgress(source_image,source->description,progress,
621 source->extent.height);
622 if (proceed == MagickFalse)
623 status=MagickFalse;
624 }
625 }
626 return(status);
627}
628
629/*
630%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
631% %
632% %
633% %
634% G e t W a n d V i e w P i x e l s %
635% %
636% %
637% %
638%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
639%
640% GetWandViewPixels() returns the wand view pixel_wands.
641%
642% The format of the GetWandViewPixels method is:
643%
644% PixelWand *GetWandViewPixels(const WandView *wand_view)
645%
646% A description of each parameter follows:
647%
648% o wand_view: the wand view.
649%
650*/
651WandExport PixelWand **GetWandViewPixels(const WandView *wand_view)
652{
653 const int
654 id = GetOpenMPThreadId();
655
656 assert(wand_view != (WandView *) NULL);
657 assert(wand_view->signature == WandSignature);
658 return(wand_view->pixel_wands[id]);
659}
660
661/*
662%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
663% %
664% %
665% %
666% G e t W a n d V i e w W a n d %
667% %
668% %
669% %
670%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
671%
672% GetWandViewWand() returns the magick wand associated with the wand view.
673%
674% The format of the GetWandViewWand method is:
675%
676% MagickWand *GetWandViewWand(const WandView *wand_view)
677%
678% A description of each parameter follows:
679%
680% o wand_view: the wand view.
681%
682*/
683WandExport MagickWand *GetWandViewWand(const WandView *wand_view)
684{
685 assert(wand_view != (WandView *) NULL);
686 assert(wand_view->signature == WandSignature);
687 return(wand_view->wand);
688}
689
690/*
691%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
692% %
693% %
694% %
695% I s W a n d V i e w %
696% %
697% %
698% %
699%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
700%
701% IsWandView() returns MagickTrue if the parameter is verified as a wand
702% view object.
703%
704% The format of the IsWandView method is:
705%
706% MagickBooleanType IsWandView(const WandView *wand_view)
707%
708% A description of each parameter follows:
709%
710% o wand_view: the wand view.
711%
712*/
713WandExport MagickBooleanType IsWandView(const WandView *wand_view)
714{
715 size_t
716 length;
717
718 if (wand_view == (const WandView *) NULL)
719 return(MagickFalse);
720 if (wand_view->signature != WandSignature)
721 return(MagickFalse);
722 length=strlen(WandViewId);
723 if (LocaleNCompare(wand_view->name,WandViewId,length) != 0)
724 return(MagickFalse);
725 return(MagickTrue);
726}
727
728/*
729%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
730% %
731% %
732% %
733% N e w W a n d V i e w %
734% %
735% %
736% %
737%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
738%
739% NewWandView() returns a wand view required for all other methods in the
740% Wand View API.
741%
742% The format of the NewWandView method is:
743%
744% WandView *NewWandView(MagickWand *wand)
745%
746% A description of each parameter follows:
747%
748% o wand: the wand.
749%
750*/
751
752static PixelWand ***AcquirePixelsTLS(const size_t number_wands,
753 const size_t number_threads)
754{
756 ***pixel_wands;
757
758 ssize_t
759 i;
760
761 pixel_wands=(PixelWand ***) AcquireQuantumMemory(number_threads,
762 sizeof(*pixel_wands));
763 if (pixel_wands == (PixelWand ***) NULL)
764 return((PixelWand ***) NULL);
765 (void) memset(pixel_wands,0,number_threads*sizeof(*pixel_wands));
766 for (i=0; i < (ssize_t) number_threads; i++)
767 {
768 pixel_wands[i]=NewPixelWands(number_wands);
769 if (pixel_wands[i] == (PixelWand **) NULL)
770 return(DestroyPixelsTLS(pixel_wands,number_wands,number_threads));
771 }
772 return(pixel_wands);
773}
774
775WandExport WandView *NewWandView(MagickWand *wand)
776{
778 *wand_view;
779
780 assert(wand != (MagickWand *) NULL);
781 assert(wand->signature == WandSignature);
782 wand_view=(WandView *) AcquireCriticalMemory(sizeof(*wand_view));
783 (void) memset(wand_view,0,sizeof(*wand_view));
784 wand_view->id=AcquireWandId();
785 (void) FormatLocaleString(wand_view->name,MaxTextExtent,"%s-%.20g",
786 WandViewId,(double) wand_view->id);
787 wand_view->description=ConstantString("WandView");
788 wand_view->wand=wand;
789 wand_view->exception=AcquireExceptionInfo();
790 wand_view->view=AcquireVirtualCacheView(wand_view->wand->images,
791 wand_view->exception);
792 wand_view->extent.width=wand->images->columns;
793 wand_view->extent.height=wand->images->rows;
794 wand_view->number_threads=GetOpenMPMaximumThreads();
795 wand_view->pixel_wands=AcquirePixelsTLS(wand_view->extent.width,
796 wand_view->number_threads);
797 if (wand_view->pixel_wands == (PixelWand ***) NULL)
798 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
799 GetExceptionMessage(errno));
800 wand_view->debug=IsEventLogging();
801 wand_view->signature=WandSignature;
802 return(wand_view);
803}
804
805/*
806%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
807% %
808% %
809% %
810% N e w W a n d V i e w E x t e n t %
811% %
812% %
813% %
814%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
815%
816% NewWandViewExtent() returns a wand view required for all other methods
817% in the Wand View API.
818%
819% The format of the NewWandViewExtent method is:
820%
821% WandView *NewWandViewExtent(MagickWand *wand,const ssize_t x,
822% const ssize_t y,const size_t width,const size_t height)
823%
824% A description of each parameter follows:
825%
826% o wand: the magick wand.
827%
828% o x,y,columns,rows: These values define the perimeter of a extent of
829% pixel_wands view.
830%
831*/
832WandExport WandView *NewWandViewExtent(MagickWand *wand,const ssize_t x,
833 const ssize_t y,const size_t width,const size_t height)
834{
836 *wand_view;
837
838 assert(wand != (MagickWand *) NULL);
839 assert(wand->signature == WandSignature);
840 wand_view=(WandView *) AcquireCriticalMemory(sizeof(*wand_view));
841 (void) memset(wand_view,0,sizeof(*wand_view));
842 wand_view->id=AcquireWandId();
843 (void) FormatLocaleString(wand_view->name,MaxTextExtent,"%s-%.20g",
844 WandViewId,(double) wand_view->id);
845 wand_view->description=ConstantString("WandView");
846 wand_view->exception=AcquireExceptionInfo();
847 wand_view->view=AcquireVirtualCacheView(wand_view->wand->images,
848 wand_view->exception);
849 wand_view->wand=wand;
850 wand_view->extent.width=width;
851 wand_view->extent.height=height;
852 wand_view->extent.x=x;
853 wand_view->extent.y=y;
854 wand_view->number_threads=GetOpenMPMaximumThreads();
855 wand_view->pixel_wands=AcquirePixelsTLS(wand_view->extent.width,
856 wand_view->number_threads);
857 if (wand_view->pixel_wands == (PixelWand ***) NULL)
858 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
859 GetExceptionMessage(errno));
860 wand_view->debug=IsEventLogging();
861 wand_view->signature=WandSignature;
862 return(wand_view);
863}
864
865/*
866%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
867% %
868% %
869% %
870% S e t W a n d V i e w D e s c r i p t i o n %
871% %
872% %
873% %
874%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
875%
876% SetWandViewDescription() associates a description with an image view.
877%
878% The format of the SetWandViewDescription method is:
879%
880% void SetWandViewDescription(WandView *image_view,const char *description)
881%
882% A description of each parameter follows:
883%
884% o wand_view: the wand view.
885%
886% o description: the wand view description.
887%
888*/
889MagickExport void SetWandViewDescription(WandView *wand_view,
890 const char *description)
891{
892 assert(wand_view != (WandView *) NULL);
893 assert(wand_view->signature == WandSignature);
894 wand_view->description=ConstantString(description);
895}
896
897/*
898%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
899% %
900% %
901% %
902% S e t W a n d V i e w I t e r a t o r %
903% %
904% %
905% %
906%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
907%
908% SetWandViewIterator() iterates over the wand view in parallel and calls
909% your set method for each scanline of the view. The pixel extent is
910% confined to the image canvas-- that is no negative offsets or widths or
911% heights that exceed the image dimension. The pixels are initially
912% undefined and any settings you make in the callback method are automagically
913% synced back to your image.
914%
915% The callback signature is:
916%
917% MagickBooleanType SetImageViewMethod(ImageView *destination,
918% const ssize_t y,const int thread_id,void *context)
919%
920% Use this pragma if the view is not single threaded:
921%
922% #pragma omp critical
923%
924% to define a section of code in your callback set method that must be
925% executed by a single thread at a time.
926%
927% The format of the SetWandViewIterator method is:
928%
929% MagickBooleanType SetWandViewIterator(WandView *destination,
930% SetWandViewMethod set,void *context)
931%
932% A description of each parameter follows:
933%
934% o destination: the wand view.
935%
936% o set: the set callback method.
937%
938% o context: the user defined context.
939%
940*/
941WandExport MagickBooleanType SetWandViewIterator(WandView *destination,
942 SetWandViewMethod set,void *context)
943{
944 ExceptionInfo
945 *exception;
946
947 Image
948 *destination_image;
949
950 MagickBooleanType
951 status;
952
953 MagickOffsetType
954 progress;
955
956#if defined(MAGICKCORE_OPENMP_SUPPORT)
957 size_t
958 height;
959#endif
960
961 ssize_t
962 y;
963
964 assert(destination != (WandView *) NULL);
965 assert(destination->signature == WandSignature);
966 if (set == (SetWandViewMethod) NULL)
967 return(MagickFalse);
968 destination_image=destination->wand->images;
969 if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
970 return(MagickFalse);
971 status=MagickTrue;
972 progress=0;
973 exception=destination->exception;
974#if defined(MAGICKCORE_OPENMP_SUPPORT)
975 height=(size_t) (destination->extent.height-destination->extent.y);
976 #pragma omp parallel for schedule(static) shared(progress,status) \
977 magick_number_threads(destination_image,destination_image,height,1)
978#endif
979 for (y=destination->extent.y; y < (ssize_t) destination->extent.height; y++)
980 {
981 const int
982 id = GetOpenMPThreadId();
983
984 MagickBooleanType
985 sync;
986
987 IndexPacket
988 *magick_restrict indexes;
989
990 ssize_t
991 x;
992
993 PixelPacket
994 *magick_restrict pixels;
995
996 if (status == MagickFalse)
997 continue;
998 pixels=GetCacheViewAuthenticPixels(destination->view,destination->extent.x,
999 y,destination->extent.width,1,exception);
1000 if (pixels == (PixelPacket *) NULL)
1001 {
1002 InheritException(destination->exception,GetCacheViewException(
1003 destination->view));
1004 status=MagickFalse;
1005 continue;
1006 }
1007 indexes=GetCacheViewAuthenticIndexQueue(destination->view);
1008 if (set(destination,y,id,context) == MagickFalse)
1009 status=MagickFalse;
1010 for (x=0; x < (ssize_t) destination->extent.width; x++)
1011 PixelGetQuantumColor(destination->pixel_wands[id][x],pixels+x);
1012 if (destination_image->colorspace == CMYKColorspace)
1013 for (x=0; x < (ssize_t) destination->extent.width; x++)
1014 SetPixelBlack(indexes+x,PixelGetBlackQuantum(
1015 destination->pixel_wands[id][x]));
1016 sync=SyncCacheViewAuthenticPixels(destination->view,exception);
1017 if (sync == MagickFalse)
1018 {
1019 InheritException(destination->exception,GetCacheViewException(
1020 destination->view));
1021 status=MagickFalse;
1022 }
1023 if (destination_image->progress_monitor != (MagickProgressMonitor) NULL)
1024 {
1025 MagickBooleanType
1026 proceed;
1027
1028#if defined(MAGICKCORE_OPENMP_SUPPORT)
1029 #pragma omp atomic
1030#endif
1031 progress++;
1032 proceed=SetImageProgress(destination_image,destination->description,
1033 progress,destination->extent.height);
1034 if (proceed == MagickFalse)
1035 status=MagickFalse;
1036 }
1037 }
1038 return(status);
1039}
1040
1041/*
1042%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1043% %
1044% %
1045% %
1046% S e t W a n d V i e w T h r e a d s %
1047% %
1048% %
1049% %
1050%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1051%
1052% SetWandViewThreads() sets the number of threads in a thread team.
1053%
1054% The format of the SetWandViewDescription method is:
1055%
1056% void SetWandViewThreads(WandView *image_view,
1057% const size_t number_threads)
1058%
1059% A description of each parameter follows:
1060%
1061% o image_view: the image view.
1062%
1063% o number_threads: the number of threads in a thread team.
1064%
1065*/
1066MagickExport void SetWandViewThreads(WandView *image_view,
1067 const size_t number_threads)
1068{
1069 assert(image_view != (WandView *) NULL);
1070 assert(image_view->signature == MagickCoreSignature);
1071 image_view->number_threads=number_threads;
1072 if (number_threads > (size_t) GetMagickResourceLimit(ThreadResource))
1073 image_view->number_threads=GetOpenMPMaximumThreads();
1074}
1075
1076/*
1077%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1078% %
1079% %
1080% %
1081% T r a n s f e r W a n d V i e w I t e r a t o r %
1082% %
1083% %
1084% %
1085%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1086%
1087% TransferWandViewIterator() iterates over two wand views in parallel and
1088% calls your transfer method for each scanline of the view. The source pixel
1089% extent is not confined to the image canvas-- that is you can include
1090% negative offsets or widths or heights that exceed the image dimension.
1091% However, the destination wand view is confined to the image canvas-- that
1092% is no negative offsets or widths or heights that exceed the image dimension
1093% are permitted.
1094%
1095% The callback signature is:
1096%
1097% MagickBooleanType TransferImageViewMethod(const WandView *source,
1098% WandView *destination,const ssize_t y,const int thread_id,
1099% void *context)
1100%
1101% Use this pragma if the view is not single threaded:
1102%
1103% #pragma omp critical
1104%
1105% to define a section of code in your callback transfer method that must be
1106% executed by a single thread at a time.
1107%
1108% The format of the TransferWandViewIterator method is:
1109%
1110% MagickBooleanType TransferWandViewIterator(WandView *source,
1111% WandView *destination,TransferWandViewMethod transfer,void *context)
1112%
1113% A description of each parameter follows:
1114%
1115% o source: the source wand view.
1116%
1117% o destination: the destination wand view.
1118%
1119% o transfer: the transfer callback method.
1120%
1121% o context: the user defined context.
1122%
1123*/
1124WandExport MagickBooleanType TransferWandViewIterator(WandView *source,
1125 WandView *destination,TransferWandViewMethod transfer,void *context)
1126{
1127 ExceptionInfo
1128 *exception;
1129
1130 Image
1131 *destination_image,
1132 *source_image;
1133
1134 MagickBooleanType
1135 status;
1136
1137 MagickOffsetType
1138 progress;
1139
1140#if defined(MAGICKCORE_OPENMP_SUPPORT)
1141 size_t
1142 height;
1143#endif
1144
1145 ssize_t
1146 y;
1147
1148 assert(source != (WandView *) NULL);
1149 assert(source->signature == WandSignature);
1150 if (transfer == (TransferWandViewMethod) NULL)
1151 return(MagickFalse);
1152 source_image=source->wand->images;
1153 destination_image=destination->wand->images;
1154 if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
1155 return(MagickFalse);
1156 status=MagickTrue;
1157 progress=0;
1158 exception=destination->exception;
1159#if defined(MAGICKCORE_OPENMP_SUPPORT)
1160 height=(size_t) (source->extent.height-source->extent.y);
1161 #pragma omp parallel for schedule(static) shared(progress,status) \
1162 magick_number_threads(source_image,destination_image,height,1)
1163#endif
1164 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
1165 {
1166 const int
1167 id = GetOpenMPThreadId();
1168
1169 MagickBooleanType
1170 sync;
1171
1172 const IndexPacket
1173 *magick_restrict indexes;
1174
1175 const PixelPacket
1176 *magick_restrict pixels;
1177
1178 IndexPacket
1179 *magick_restrict destination_indexes;
1180
1181 ssize_t
1182 x;
1183
1184 PixelPacket
1185 *magick_restrict destination_pixels;
1186
1187 if (status == MagickFalse)
1188 continue;
1189 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
1190 source->extent.width,1,source->exception);
1191 if (pixels == (const PixelPacket *) NULL)
1192 {
1193 status=MagickFalse;
1194 continue;
1195 }
1196 indexes=GetCacheViewVirtualIndexQueue(source->view);
1197 for (x=0; x < (ssize_t) source->extent.width; x++)
1198 PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
1199 if (source_image->colorspace == CMYKColorspace)
1200 for (x=0; x < (ssize_t) source->extent.width; x++)
1201 PixelSetBlackQuantum(source->pixel_wands[id][x],
1202 GetPixelBlack(indexes+x));
1203 if (source_image->storage_class == PseudoClass)
1204 for (x=0; x < (ssize_t) source->extent.width; x++)
1205 PixelSetIndex(source->pixel_wands[id][x],
1206 GetPixelIndex(indexes+x));
1207 destination_pixels=GetCacheViewAuthenticPixels(destination->view,
1208 destination->extent.x,y,destination->extent.width,1,exception);
1209 if (destination_pixels == (PixelPacket *) NULL)
1210 {
1211 status=MagickFalse;
1212 continue;
1213 }
1214 destination_indexes=GetCacheViewAuthenticIndexQueue(destination->view);
1215 for (x=0; x < (ssize_t) destination->extent.width; x++)
1216 PixelSetQuantumColor(destination->pixel_wands[id][x],pixels+x);
1217 if (destination_image->colorspace == CMYKColorspace)
1218 for (x=0; x < (ssize_t) destination->extent.width; x++)
1219 PixelSetBlackQuantum(destination->pixel_wands[id][x],
1220 GetPixelBlack(indexes+x));
1221 if (destination_image->storage_class == PseudoClass)
1222 for (x=0; x < (ssize_t) destination->extent.width; x++)
1223 PixelSetIndex(destination->pixel_wands[id][x],
1224 GetPixelIndex(indexes+x));
1225 if (transfer(source,destination,y,id,context) == MagickFalse)
1226 status=MagickFalse;
1227 for (x=0; x < (ssize_t) destination->extent.width; x++)
1228 PixelGetQuantumColor(destination->pixel_wands[id][x],
1229 destination_pixels+x);
1230 if (destination_image->colorspace == CMYKColorspace)
1231 for (x=0; x < (ssize_t) destination->extent.width; x++)
1232 SetPixelBlack(destination_indexes+x,PixelGetBlackQuantum(
1233 destination->pixel_wands[id][x]));
1234 sync=SyncCacheViewAuthenticPixels(destination->view,exception);
1235 if (sync == MagickFalse)
1236 {
1237 InheritException(destination->exception,GetCacheViewException(
1238 source->view));
1239 status=MagickFalse;
1240 }
1241 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1242 {
1243 MagickBooleanType
1244 proceed;
1245
1246#if defined(MAGICKCORE_OPENMP_SUPPORT)
1247 #pragma omp atomic
1248#endif
1249 progress++;
1250 proceed=SetImageProgress(source_image,source->description,progress,
1251 source->extent.height);
1252 if (proceed == MagickFalse)
1253 status=MagickFalse;
1254 }
1255 }
1256 return(status);
1257}
1258
1259/*
1260%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1261% %
1262% %
1263% %
1264% U p d a t e W a n d V i e w I t e r a t o r %
1265% %
1266% %
1267% %
1268%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1269%
1270% UpdateWandViewIterator() iterates over the wand view in parallel and calls
1271% your update method for each scanline of the view. The pixel extent is
1272% confined to the image canvas-- that is no negative offsets or widths or
1273% heights that exceed the image dimension are permitted. Updates to pixels
1274% in your callback are automagically synced back to the image.
1275%
1276% The callback signature is:
1277%
1278% MagickBooleanType UpdateImageViewMethod(WandView *source,const ssize_t y,
1279% const int thread_id,void *context)
1280%
1281% Use this pragma if the view is not single threaded:
1282%
1283% #pragma omp critical
1284%
1285% to define a section of code in your callback update method that must be
1286% executed by a single thread at a time.
1287%
1288% The format of the UpdateWandViewIterator method is:
1289%
1290% MagickBooleanType UpdateWandViewIterator(WandView *source,
1291% UpdateWandViewMethod update,void *context)
1292%
1293% A description of each parameter follows:
1294%
1295% o source: the source wand view.
1296%
1297% o update: the update callback method.
1298%
1299% o context: the user defined context.
1300%
1301*/
1302WandExport MagickBooleanType UpdateWandViewIterator(WandView *source,
1303 UpdateWandViewMethod update,void *context)
1304{
1305 ExceptionInfo
1306 *exception;
1307
1308 Image
1309 *source_image;
1310
1311 MagickBooleanType
1312 status;
1313
1314 MagickOffsetType
1315 progress;
1316
1317#if defined(MAGICKCORE_OPENMP_SUPPORT)
1318 size_t
1319 height;
1320#endif
1321
1322 ssize_t
1323 y;
1324
1325 assert(source != (WandView *) NULL);
1326 assert(source->signature == WandSignature);
1327 if (update == (UpdateWandViewMethod) NULL)
1328 return(MagickFalse);
1329 source_image=source->wand->images;
1330 if (SetImageStorageClass(source_image,DirectClass) == MagickFalse)
1331 return(MagickFalse);
1332 status=MagickTrue;
1333 progress=0;
1334 exception=source->exception;
1335#if defined(MAGICKCORE_OPENMP_SUPPORT)
1336 height=(size_t) (source->extent.height-source->extent.y);
1337 #pragma omp parallel for schedule(static) shared(progress,status) \
1338 magick_number_threads(source_image,source_image,height,1)
1339#endif
1340 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
1341 {
1342 const int
1343 id = GetOpenMPThreadId();
1344
1345 IndexPacket
1346 *magick_restrict indexes;
1347
1348 ssize_t
1349 x;
1350
1351 PixelPacket
1352 *magick_restrict pixels;
1353
1354 if (status == MagickFalse)
1355 continue;
1356 pixels=GetCacheViewAuthenticPixels(source->view,source->extent.x,y,
1357 source->extent.width,1,exception);
1358 if (pixels == (PixelPacket *) NULL)
1359 {
1360 InheritException(source->exception,GetCacheViewException(
1361 source->view));
1362 status=MagickFalse;
1363 continue;
1364 }
1365 indexes=GetCacheViewAuthenticIndexQueue(source->view);
1366 for (x=0; x < (ssize_t) source->extent.width; x++)
1367 PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
1368 if (source_image->colorspace == CMYKColorspace)
1369 for (x=0; x < (ssize_t) source->extent.width; x++)
1370 PixelSetBlackQuantum(source->pixel_wands[id][x],
1371 GetPixelBlack(indexes+x));
1372 if (update(source,y,id,context) == MagickFalse)
1373 status=MagickFalse;
1374 for (x=0; x < (ssize_t) source->extent.width; x++)
1375 PixelGetQuantumColor(source->pixel_wands[id][x],pixels+x);
1376 if (source_image->colorspace == CMYKColorspace)
1377 for (x=0; x < (ssize_t) source->extent.width; x++)
1378 SetPixelBlack(indexes+x,PixelGetBlackQuantum(
1379 source->pixel_wands[id][x]));
1380 if (SyncCacheViewAuthenticPixels(source->view,exception) == MagickFalse)
1381 {
1382 InheritException(source->exception,GetCacheViewException(source->view));
1383 status=MagickFalse;
1384 }
1385 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1386 {
1387 MagickBooleanType
1388 proceed;
1389
1390#if defined(MAGICKCORE_OPENMP_SUPPORT)
1391 #pragma omp atomic
1392#endif
1393 progress++;
1394 proceed=SetImageProgress(source_image,source->description,progress,
1395 source->extent.height);
1396 if (proceed == MagickFalse)
1397 status=MagickFalse;
1398 }
1399 }
1400 return(status);
1401}