MagickWand  6.9.12-67
Convert, Edit, Or Compose Bitmap Images
 All Data Structures
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-2021 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 */
62 struct _WandView
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 
83  PixelWand
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 */
118 WandExport WandView *CloneWandView(const WandView *wand_view)
119 {
120  WandView
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 
174 static 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 
188 WandExport 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 */
253 WandExport 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 */
438 WandExport 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 */
493 WandExport 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 */
543 WandExport 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 */
651 WandExport 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 */
683 WandExport 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 */
713 WandExport 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 
752 static PixelWand ***AcquirePixelsTLS(const size_t number_wands,
753  const size_t number_threads)
754 {
755  PixelWand
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 
775 WandExport WandView *NewWandView(MagickWand *wand)
776 {
777  WandView
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 */
832 WandExport WandView *NewWandViewExtent(MagickWand *wand,const ssize_t x,
833  const ssize_t y,const size_t width,const size_t height)
834 {
835  WandView
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 */
889 MagickExport 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 initiallly
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 */
941 WandExport 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 */
1066 MagickExport 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 */
1124 WandExport 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 */
1302 WandExport 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 }