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