blob: 41fc3b317c69538d382958fa141f0def1a04c42b [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
cristy58739472010-06-26 20:27:18 +00005% 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 %
cristy3ed852e2009-09-05 21:47:34 +000010% %
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% %
cristy7eb1b7a2010-06-26 15:47:49 +000018% MagickWand Wand View Methods %
cristy3ed852e2009-09-05 21:47:34 +000019% %
20% Software Design %
cristyde984cd2013-12-01 14:49:27 +000021% Cristy %
cristy3ed852e2009-09-05 21:47:34 +000022% March 2003 %
23% %
24% %
Cristy7ce65e72015-12-12 18:03:16 -050025% Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000026% 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% http://www.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*/
cristy4c08aed2011-07-01 19:47:50 +000048#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"
cristy3ed852e2009-09-05 21:47:34 +000054/*
55 Define declarations.
56*/
cristy7eb1b7a2010-06-26 15:47:49 +000057#define WandViewId "WandView"
cristy3ed852e2009-09-05 21:47:34 +000058
59/*
60 Typedef declarations.
61*/
cristy7eb1b7a2010-06-26 15:47:49 +000062struct _WandView
cristy3ed852e2009-09-05 21:47:34 +000063{
cristybb503372010-05-27 20:51:26 +000064 size_t
cristy3ed852e2009-09-05 21:47:34 +000065 id;
66
67 char
cristy151b66d2015-04-15 10:50:31 +000068 name[MagickPathExtent],
cristyc3ebda22010-06-27 17:11:57 +000069 *description;
cristy3ed852e2009-09-05 21:47:34 +000070
cristyc3ebda22010-06-27 17:11:57 +000071 RectangleInfo
72 extent;
cristy3ed852e2009-09-05 21:47:34 +000073
74 MagickWand
75 *wand;
76
cristy4c08aed2011-07-01 19:47:50 +000077 Image
78 *image;
79
cristy3ed852e2009-09-05 21:47:34 +000080 CacheView
81 *view;
82
cristy3ed852e2009-09-05 21:47:34 +000083 PixelWand
84 ***pixel_wands;
85
cristyc3ebda22010-06-27 17:11:57 +000086 ExceptionInfo
87 *exception;
88
cristy3ed852e2009-09-05 21:47:34 +000089 MagickBooleanType
90 debug;
91
cristybb503372010-05-27 20:51:26 +000092 size_t
cristy3ed852e2009-09-05 21:47:34 +000093 signature;
94};
95
96/*
97%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
98% %
99% %
100% %
cristy7eb1b7a2010-06-26 15:47:49 +0000101% C l o n e W a n d V i e w %
cristy3ed852e2009-09-05 21:47:34 +0000102% %
103% %
104% %
105%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
106%
cristy73b7d4c2010-06-27 00:31:00 +0000107% CloneWandView() makes a copy of the specified wand view.
cristy3ed852e2009-09-05 21:47:34 +0000108%
cristy7eb1b7a2010-06-26 15:47:49 +0000109% The format of the CloneWandView method is:
cristy3ed852e2009-09-05 21:47:34 +0000110%
cristy73b7d4c2010-06-27 00:31:00 +0000111% WandView *CloneWandView(const WandView *wand_view)
cristy3ed852e2009-09-05 21:47:34 +0000112%
113% A description of each parameter follows:
114%
cristy73b7d4c2010-06-27 00:31:00 +0000115% o wand_view: the wand view.
cristy3ed852e2009-09-05 21:47:34 +0000116%
117*/
cristy73b7d4c2010-06-27 00:31:00 +0000118WandExport WandView *CloneWandView(const WandView *wand_view)
cristy3ed852e2009-09-05 21:47:34 +0000119{
cristy7eb1b7a2010-06-26 15:47:49 +0000120 WandView
cristy3ed852e2009-09-05 21:47:34 +0000121 *clone_view;
122
cristybb503372010-05-27 20:51:26 +0000123 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000124 i;
125
cristy73b7d4c2010-06-27 00:31:00 +0000126 assert(wand_view != (WandView *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000127 assert(wand_view->signature == MagickWandSignature);
cristy73b7d4c2010-06-27 00:31:00 +0000128 if (wand_view->debug != MagickFalse)
129 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand_view->name);
cristy73bd4a52010-10-05 11:24:23 +0000130 clone_view=(WandView *) AcquireMagickMemory(sizeof(*clone_view));
cristy7eb1b7a2010-06-26 15:47:49 +0000131 if (clone_view == (WandView *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000132 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
cristy73b7d4c2010-06-27 00:31:00 +0000133 wand_view->name);
cristy3ed852e2009-09-05 21:47:34 +0000134 (void) ResetMagickMemory(clone_view,0,sizeof(*clone_view));
135 clone_view->id=AcquireWandId();
cristy151b66d2015-04-15 10:50:31 +0000136 (void) FormatLocaleString(clone_view->name,MagickPathExtent,"%s-%.20g",
cristy7eb1b7a2010-06-26 15:47:49 +0000137 WandViewId,(double) clone_view->id);
cristyc3ebda22010-06-27 17:11:57 +0000138 clone_view->description=ConstantString(wand_view->description);
cristy4c08aed2011-07-01 19:47:50 +0000139 clone_view->image=CloneImage(wand_view->image,0,0,MagickTrue,
140 wand_view->exception);
cristyc3ebda22010-06-27 17:11:57 +0000141 clone_view->view=CloneCacheView(wand_view->view);
142 clone_view->extent=wand_view->extent;
cristy3ed852e2009-09-05 21:47:34 +0000143 clone_view->exception=AcquireExceptionInfo();
cristy73b7d4c2010-06-27 00:31:00 +0000144 InheritException(clone_view->exception,wand_view->exception);
cristyac245f82012-05-05 17:13:57 +0000145 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
cristy3ed852e2009-09-05 21:47:34 +0000146 clone_view->pixel_wands[i]=ClonePixelWands((const PixelWand **)
cristyc3ebda22010-06-27 17:11:57 +0000147 wand_view->pixel_wands[i],wand_view->extent.width);
cristy73b7d4c2010-06-27 00:31:00 +0000148 clone_view->debug=wand_view->debug;
cristy3ed852e2009-09-05 21:47:34 +0000149 if (clone_view->debug != MagickFalse)
150 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",clone_view->name);
cristye1c94d92015-06-28 12:16:33 +0000151 clone_view->signature=MagickWandSignature;
cristy3ed852e2009-09-05 21:47:34 +0000152 return(clone_view);
153}
154
155/*
156%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
157% %
158% %
159% %
cristy7eb1b7a2010-06-26 15:47:49 +0000160% D e s t r o y W a n d V i e w %
cristy3ed852e2009-09-05 21:47:34 +0000161% %
162% %
163% %
164%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
165%
cristy73b7d4c2010-06-27 00:31:00 +0000166% DestroyWandView() deallocates memory associated with a wand view.
cristy3ed852e2009-09-05 21:47:34 +0000167%
cristy7eb1b7a2010-06-26 15:47:49 +0000168% The format of the DestroyWandView method is:
cristy3ed852e2009-09-05 21:47:34 +0000169%
cristy73b7d4c2010-06-27 00:31:00 +0000170% WandView *DestroyWandView(WandView *wand_view)
cristy3ed852e2009-09-05 21:47:34 +0000171%
172% A description of each parameter follows:
173%
cristy73b7d4c2010-06-27 00:31:00 +0000174% o wand_view: the wand view.
cristy3ed852e2009-09-05 21:47:34 +0000175%
176*/
177
178static PixelWand ***DestroyPixelsThreadSet(PixelWand ***pixel_wands,
cristyac245f82012-05-05 17:13:57 +0000179 const size_t number_wands)
cristy3ed852e2009-09-05 21:47:34 +0000180{
cristybb503372010-05-27 20:51:26 +0000181 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000182 i;
183
184 assert(pixel_wands != (PixelWand ***) NULL);
cristyac245f82012-05-05 17:13:57 +0000185 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
cristy3ed852e2009-09-05 21:47:34 +0000186 if (pixel_wands[i] != (PixelWand **) NULL)
187 pixel_wands[i]=DestroyPixelWands(pixel_wands[i],number_wands);
cristyb41ee102010-10-04 16:46:15 +0000188 pixel_wands=(PixelWand ***) RelinquishMagickMemory(pixel_wands);
cristy3ed852e2009-09-05 21:47:34 +0000189 return(pixel_wands);
190}
191
cristy73b7d4c2010-06-27 00:31:00 +0000192WandExport WandView *DestroyWandView(WandView *wand_view)
cristy3ed852e2009-09-05 21:47:34 +0000193{
cristy73b7d4c2010-06-27 00:31:00 +0000194 assert(wand_view != (WandView *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000195 assert(wand_view->signature == MagickWandSignature);
cristy73b7d4c2010-06-27 00:31:00 +0000196 wand_view->pixel_wands=DestroyPixelsThreadSet(wand_view->pixel_wands,
cristyac245f82012-05-05 17:13:57 +0000197 wand_view->extent.width);
cristy4c08aed2011-07-01 19:47:50 +0000198 wand_view->image=DestroyImage(wand_view->image);
cristy73b7d4c2010-06-27 00:31:00 +0000199 wand_view->view=DestroyCacheView(wand_view->view);
200 wand_view->exception=DestroyExceptionInfo(wand_view->exception);
cristye1c94d92015-06-28 12:16:33 +0000201 wand_view->signature=(~MagickWandSignature);
cristy73b7d4c2010-06-27 00:31:00 +0000202 RelinquishWandId(wand_view->id);
203 wand_view=(WandView *) RelinquishMagickMemory(wand_view);
204 return(wand_view);
cristy3ed852e2009-09-05 21:47:34 +0000205}
206
207/*
208%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
209% %
210% %
211% %
cristy7eb1b7a2010-06-26 15:47:49 +0000212% 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 %
cristy3ed852e2009-09-05 21:47:34 +0000213% %
214% %
215% %
216%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
217%
cristy73b7d4c2010-06-27 00:31:00 +0000218% DuplexTransferWandViewIterator() iterates over three wand views in
cristy3ed852e2009-09-05 21:47:34 +0000219% parallel and calls your transfer method for each scanline of the view. The
cristyc3ebda22010-06-27 17:11:57 +0000220% source and duplex pixel extent is not confined to the image canvas-- that is
cristy3ed852e2009-09-05 21:47:34 +0000221% you can include negative offsets or widths or heights that exceed the image
cristy73b7d4c2010-06-27 00:31:00 +0000222% dimension. However, the destination wand view is confined to the image
cristy3ed852e2009-09-05 21:47:34 +0000223% canvas-- that is no negative offsets or widths or heights that exceed the
224% image dimension are permitted.
225%
cristyd6dfc0d2010-06-27 19:30:49 +0000226% The callback signature is:
227%
228% MagickBooleanType DuplexTransferImageViewMethod(const WandView *source,
229% const WandView *duplex,WandView *destination,const ssize_t y,
230% const int thread_id,void *context)
231%
cristy58739472010-06-26 20:27:18 +0000232% Use this pragma if the view is not single threaded:
cristy3ed852e2009-09-05 21:47:34 +0000233%
234% #pragma omp critical
235%
236% to define a section of code in your callback transfer method that must be
237% executed by a single thread at a time.
238%
cristy7eb1b7a2010-06-26 15:47:49 +0000239% The format of the DuplexTransferWandViewIterator method is:
cristy3ed852e2009-09-05 21:47:34 +0000240%
cristy7eb1b7a2010-06-26 15:47:49 +0000241% MagickBooleanType DuplexTransferWandViewIterator(WandView *source,
242% WandView *duplex,WandView *destination,
243% DuplexTransferWandViewMethod transfer,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000244%
245% A description of each parameter follows:
246%
cristy73b7d4c2010-06-27 00:31:00 +0000247% o source: the source wand view.
cristy3ed852e2009-09-05 21:47:34 +0000248%
cristy73b7d4c2010-06-27 00:31:00 +0000249% o duplex: the duplex wand view.
cristy3ed852e2009-09-05 21:47:34 +0000250%
cristy73b7d4c2010-06-27 00:31:00 +0000251% o destination: the destination wand view.
cristy3ed852e2009-09-05 21:47:34 +0000252%
253% o transfer: the transfer callback method.
254%
255% o context: the user defined context.
256%
257*/
cristy58739472010-06-26 20:27:18 +0000258WandExport MagickBooleanType DuplexTransferWandViewIterator(WandView *source,
259 WandView *duplex,WandView *destination,DuplexTransferWandViewMethod transfer,
260 void *context)
cristy3ed852e2009-09-05 21:47:34 +0000261{
cristy3ed852e2009-09-05 21:47:34 +0000262 Image
263 *destination_image,
cristy3ed852e2009-09-05 21:47:34 +0000264 *source_image;
265
cristy3ed852e2009-09-05 21:47:34 +0000266 MagickBooleanType
267 status;
268
cristycee97112010-05-28 00:44:52 +0000269 MagickOffsetType
270 progress;
271
glennrpd30b3052012-09-26 12:17:18 +0000272#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +0000273 size_t
cristy26b64912012-12-16 18:20:09 +0000274 height;
glennrpd30b3052012-09-26 12:17:18 +0000275#endif
cristyac245f82012-05-05 17:13:57 +0000276
cristycee97112010-05-28 00:44:52 +0000277 ssize_t
278 y;
279
cristy7eb1b7a2010-06-26 15:47:49 +0000280 assert(source != (WandView *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000281 assert(source->signature == MagickWandSignature);
cristy7eb1b7a2010-06-26 15:47:49 +0000282 if (transfer == (DuplexTransferWandViewMethod) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000283 return(MagickFalse);
284 source_image=source->wand->images;
cristy3ed852e2009-09-05 21:47:34 +0000285 destination_image=destination->wand->images;
cristycad4e1b2011-10-16 14:58:39 +0000286 status=SetImageStorageClass(destination_image,DirectClass,
287 destination->exception);
288 if (status == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000289 return(MagickFalse);
290 status=MagickTrue;
291 progress=0;
glennrpd30b3052012-09-26 12:17:18 +0000292#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +0000293 height=source->extent.height-source->extent.y;
cristyd6432472013-01-06 16:56:13 +0000294 #pragma omp parallel for schedule(static,4) shared(progress,status) \
cristy5e6b2592012-12-19 14:08:11 +0000295 magick_threads(source_image,destination_image,height,1)
cristy3ed852e2009-09-05 21:47:34 +0000296#endif
cristyc3ebda22010-06-27 17:11:57 +0000297 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
cristy3ed852e2009-09-05 21:47:34 +0000298 {
cristy83e6d2a2010-09-17 17:35:13 +0000299 const int
300 id = GetOpenMPThreadId();
cristyad740052010-07-03 01:38:03 +0000301
cristy3ed852e2009-09-05 21:47:34 +0000302 MagickBooleanType
303 sync;
304
cristy4c08aed2011-07-01 19:47:50 +0000305 register const Quantum
dirk05d2ff72015-11-18 23:13:43 +0100306 *magick_restrict duplex_pixels,
307 *magick_restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000308
cristybb503372010-05-27 20:51:26 +0000309 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000310 x;
311
cristy4c08aed2011-07-01 19:47:50 +0000312 register Quantum
dirk05d2ff72015-11-18 23:13:43 +0100313 *magick_restrict destination_pixels;
cristy3ed852e2009-09-05 21:47:34 +0000314
315 if (status == MagickFalse)
316 continue;
cristyc3ebda22010-06-27 17:11:57 +0000317 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
318 source->extent.width,1,source->exception);
cristy4c08aed2011-07-01 19:47:50 +0000319 if (pixels == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000320 {
321 status=MagickFalse;
322 continue;
323 }
cristyc3ebda22010-06-27 17:11:57 +0000324 for (x=0; x < (ssize_t) source->extent.width; x++)
cristy4c08aed2011-07-01 19:47:50 +0000325 {
326 PixelSetQuantumPixel(source->image,pixels,source->pixel_wands[id][x]);
cristyed231572011-07-14 02:18:59 +0000327 pixels+=GetPixelChannels(source->image);
cristy4c08aed2011-07-01 19:47:50 +0000328 }
cristyc3ebda22010-06-27 17:11:57 +0000329 duplex_pixels=GetCacheViewVirtualPixels(duplex->view,duplex->extent.x,y,
330 duplex->extent.width,1,duplex->exception);
cristy4c08aed2011-07-01 19:47:50 +0000331 if (duplex_pixels == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000332 {
333 status=MagickFalse;
334 continue;
335 }
cristyc3ebda22010-06-27 17:11:57 +0000336 for (x=0; x < (ssize_t) duplex->extent.width; x++)
cristy4c08aed2011-07-01 19:47:50 +0000337 {
338 PixelSetQuantumPixel(duplex->image,duplex_pixels,
339 duplex->pixel_wands[id][x]);
cristyed231572011-07-14 02:18:59 +0000340 duplex_pixels+=GetPixelChannels(duplex->image);
cristy4c08aed2011-07-01 19:47:50 +0000341 }
cristy3ed852e2009-09-05 21:47:34 +0000342 destination_pixels=GetCacheViewAuthenticPixels(destination->view,
cristycad4e1b2011-10-16 14:58:39 +0000343 destination->extent.x,y,destination->extent.width,1,
344 destination->exception);
cristy4c08aed2011-07-01 19:47:50 +0000345 if (destination_pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000346 {
347 status=MagickFalse;
348 continue;
349 }
cristyc3ebda22010-06-27 17:11:57 +0000350 for (x=0; x < (ssize_t) destination->extent.width; x++)
cristy4c08aed2011-07-01 19:47:50 +0000351 {
352 PixelSetQuantumPixel(destination->image,destination_pixels,
353 destination->pixel_wands[id][x]);
cristyed231572011-07-14 02:18:59 +0000354 destination_pixels+=GetPixelChannels(destination->image);
cristy4c08aed2011-07-01 19:47:50 +0000355 }
cristyc3ebda22010-06-27 17:11:57 +0000356 if (transfer(source,duplex,destination,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000357 status=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +0000358 destination_pixels=GetCacheViewAuthenticPixels(destination->view,
cristycad4e1b2011-10-16 14:58:39 +0000359 destination->extent.x,y,destination->extent.width,1,
360 destination->exception);
cristyc3ebda22010-06-27 17:11:57 +0000361 for (x=0; x < (ssize_t) destination->extent.width; x++)
cristy4c08aed2011-07-01 19:47:50 +0000362 {
363 PixelGetQuantumPixel(destination->image,destination->pixel_wands[id][x],
364 destination_pixels);
cristyed231572011-07-14 02:18:59 +0000365 destination_pixels+=GetPixelChannels(destination->image);
cristy4c08aed2011-07-01 19:47:50 +0000366 }
cristycad4e1b2011-10-16 14:58:39 +0000367 sync=SyncCacheViewAuthenticPixels(destination->view,destination->exception);
cristy3ed852e2009-09-05 21:47:34 +0000368 if (sync == MagickFalse)
cristycad4e1b2011-10-16 14:58:39 +0000369 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000370 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
371 {
372 MagickBooleanType
373 proceed;
374
cristyb5d5f722009-11-04 03:03:49 +0000375#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy1500c3d2012-01-17 13:57:52 +0000376 #pragma omp critical (MagickWand_DuplexTransferWandViewIterator)
cristy3ed852e2009-09-05 21:47:34 +0000377#endif
cristyc3ebda22010-06-27 17:11:57 +0000378 proceed=SetImageProgress(source_image,source->description,progress++,
379 source->extent.height);
cristy3ed852e2009-09-05 21:47:34 +0000380 if (proceed == MagickFalse)
381 status=MagickFalse;
382 }
383 }
cristy220c4d52013-11-27 19:31:32 +0000384 return(status);
cristy3ed852e2009-09-05 21:47:34 +0000385}
386
387/*
388%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
389% %
390% %
391% %
cristy7eb1b7a2010-06-26 15:47:49 +0000392% G e t W a n d V i e w E x c e p t i o n %
cristy3ed852e2009-09-05 21:47:34 +0000393% %
394% %
395% %
396%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
397%
cristy7eb1b7a2010-06-26 15:47:49 +0000398% GetWandViewException() returns the severity, reason, and description of any
cristy73b7d4c2010-06-27 00:31:00 +0000399% error that occurs when utilizing a wand view.
cristy3ed852e2009-09-05 21:47:34 +0000400%
cristy7eb1b7a2010-06-26 15:47:49 +0000401% The format of the GetWandViewException method is:
cristy3ed852e2009-09-05 21:47:34 +0000402%
cristy76fa3142012-04-26 11:30:17 +0000403% char *GetWandViewException(const WandView *wand_view,
cristy3ed852e2009-09-05 21:47:34 +0000404% ExceptionType *severity)
405%
406% A description of each parameter follows:
407%
cristy73b7d4c2010-06-27 00:31:00 +0000408% o wand_view: the pixel wand_view.
cristy3ed852e2009-09-05 21:47:34 +0000409%
410% o severity: the severity of the error is returned here.
411%
412*/
cristy73b7d4c2010-06-27 00:31:00 +0000413WandExport char *GetWandViewException(const WandView *wand_view,
cristy3ed852e2009-09-05 21:47:34 +0000414 ExceptionType *severity)
415{
416 char
417 *description;
418
cristy73b7d4c2010-06-27 00:31:00 +0000419 assert(wand_view != (const WandView *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000420 assert(wand_view->signature == MagickWandSignature);
cristy73b7d4c2010-06-27 00:31:00 +0000421 if (wand_view->debug != MagickFalse)
422 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand_view->name);
cristy3ed852e2009-09-05 21:47:34 +0000423 assert(severity != (ExceptionType *) NULL);
cristy73b7d4c2010-06-27 00:31:00 +0000424 *severity=wand_view->exception->severity;
cristy151b66d2015-04-15 10:50:31 +0000425 description=(char *) AcquireQuantumMemory(2UL*MagickPathExtent,
cristy3ed852e2009-09-05 21:47:34 +0000426 sizeof(*description));
427 if (description == (char *) NULL)
428 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
cristy73b7d4c2010-06-27 00:31:00 +0000429 wand_view->name);
cristy3ed852e2009-09-05 21:47:34 +0000430 *description='\0';
cristy73b7d4c2010-06-27 00:31:00 +0000431 if (wand_view->exception->reason != (char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000432 (void) CopyMagickString(description,GetLocaleExceptionMessage(
cristy73b7d4c2010-06-27 00:31:00 +0000433 wand_view->exception->severity,wand_view->exception->reason),
cristy151b66d2015-04-15 10:50:31 +0000434 MagickPathExtent);
cristy73b7d4c2010-06-27 00:31:00 +0000435 if (wand_view->exception->description != (char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000436 {
cristy151b66d2015-04-15 10:50:31 +0000437 (void) ConcatenateMagickString(description," (",MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000438 (void) ConcatenateMagickString(description,GetLocaleExceptionMessage(
cristy73b7d4c2010-06-27 00:31:00 +0000439 wand_view->exception->severity,wand_view->exception->description),
cristy151b66d2015-04-15 10:50:31 +0000440 MagickPathExtent);
441 (void) ConcatenateMagickString(description,")",MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000442 }
443 return(description);
444}
445
446/*
447%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
448% %
449% %
450% %
cristyc3ebda22010-06-27 17:11:57 +0000451% G e t W a n d V i e w E x t e n t %
cristy3ed852e2009-09-05 21:47:34 +0000452% %
453% %
454% %
455%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
456%
cristyc3ebda22010-06-27 17:11:57 +0000457% GetWandViewExtent() returns the wand view extent.
cristy3ed852e2009-09-05 21:47:34 +0000458%
cristyc3ebda22010-06-27 17:11:57 +0000459% The format of the GetWandViewExtent method is:
cristy3ed852e2009-09-05 21:47:34 +0000460%
cristyc3ebda22010-06-27 17:11:57 +0000461% RectangleInfo GetWandViewExtent(const WandView *wand_view)
cristy3ed852e2009-09-05 21:47:34 +0000462%
463% A description of each parameter follows:
464%
cristy73b7d4c2010-06-27 00:31:00 +0000465% o wand_view: the wand view.
cristy3ed852e2009-09-05 21:47:34 +0000466%
467*/
cristyc3ebda22010-06-27 17:11:57 +0000468WandExport RectangleInfo GetWandViewExtent(const WandView *wand_view)
cristy3ed852e2009-09-05 21:47:34 +0000469{
cristy73b7d4c2010-06-27 00:31:00 +0000470 assert(wand_view != (WandView *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000471 assert(wand_view->signature == MagickWandSignature);
cristyc3ebda22010-06-27 17:11:57 +0000472 return(wand_view->extent);
cristy3ed852e2009-09-05 21:47:34 +0000473}
474
475/*
476%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
477% %
478% %
479% %
cristy7eb1b7a2010-06-26 15:47:49 +0000480% G e t W a n d V i e w I t e r a t o r %
cristy3ed852e2009-09-05 21:47:34 +0000481% %
482% %
483% %
484%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
485%
cristy73b7d4c2010-06-27 00:31:00 +0000486% GetWandViewIterator() iterates over the wand view in parallel and calls
cristyc3ebda22010-06-27 17:11:57 +0000487% your get method for each scanline of the view. The pixel extent is
cristy3ed852e2009-09-05 21:47:34 +0000488% not confined to the image canvas-- that is you can include negative offsets
489% or widths or heights that exceed the image dimension. Any updates to
490% the pixels in your callback are ignored.
491%
cristyd6dfc0d2010-06-27 19:30:49 +0000492% The callback signature is:
493%
494% MagickBooleanType GetImageViewMethod(const WandView *source,
495% const ssize_t y,const int thread_id,void *context)
496%
cristy58739472010-06-26 20:27:18 +0000497% Use this pragma if the view is not single threaded:
cristy3ed852e2009-09-05 21:47:34 +0000498%
499% #pragma omp critical
500%
501% to define a section of code in your callback get method that must be
502% executed by a single thread at a time.
503%
cristy7eb1b7a2010-06-26 15:47:49 +0000504% The format of the GetWandViewIterator method is:
cristy3ed852e2009-09-05 21:47:34 +0000505%
cristy7eb1b7a2010-06-26 15:47:49 +0000506% MagickBooleanType GetWandViewIterator(WandView *source,
507% GetWandViewMethod get,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000508%
509% A description of each parameter follows:
510%
cristy73b7d4c2010-06-27 00:31:00 +0000511% o source: the source wand view.
cristy3ed852e2009-09-05 21:47:34 +0000512%
513% o get: the get callback method.
514%
515% o context: the user defined context.
516%
517*/
cristy7eb1b7a2010-06-26 15:47:49 +0000518WandExport MagickBooleanType GetWandViewIterator(WandView *source,
519 GetWandViewMethod get,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000520{
cristy3ed852e2009-09-05 21:47:34 +0000521 Image
522 *source_image;
523
cristy3ed852e2009-09-05 21:47:34 +0000524 MagickBooleanType
525 status;
526
cristycee97112010-05-28 00:44:52 +0000527 MagickOffsetType
528 progress;
529
glennrpd30b3052012-09-26 12:17:18 +0000530#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +0000531 size_t
cristy26b64912012-12-16 18:20:09 +0000532 height;
glennrpd30b3052012-09-26 12:17:18 +0000533#endif
cristyac245f82012-05-05 17:13:57 +0000534
cristycee97112010-05-28 00:44:52 +0000535 ssize_t
536 y;
537
cristy7eb1b7a2010-06-26 15:47:49 +0000538 assert(source != (WandView *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000539 assert(source->signature == MagickWandSignature);
cristy7eb1b7a2010-06-26 15:47:49 +0000540 if (get == (GetWandViewMethod) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000541 return(MagickFalse);
542 source_image=source->wand->images;
543 status=MagickTrue;
544 progress=0;
glennrpd30b3052012-09-26 12:17:18 +0000545#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +0000546 height=source->extent.height-source->extent.y;
cristyd6432472013-01-06 16:56:13 +0000547 #pragma omp parallel for schedule(static,4) shared(progress,status) \
cristy5e6b2592012-12-19 14:08:11 +0000548 magick_threads(source_image,source_image,height,1)
cristy3ed852e2009-09-05 21:47:34 +0000549#endif
cristyc3ebda22010-06-27 17:11:57 +0000550 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
cristy3ed852e2009-09-05 21:47:34 +0000551 {
cristy83e6d2a2010-09-17 17:35:13 +0000552 const int
553 id = GetOpenMPThreadId();
cristyad740052010-07-03 01:38:03 +0000554
cristy4c08aed2011-07-01 19:47:50 +0000555 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000556 *pixels;
557
cristybb503372010-05-27 20:51:26 +0000558 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000559 x;
560
561 if (status == MagickFalse)
562 continue;
cristyc3ebda22010-06-27 17:11:57 +0000563 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
564 source->extent.width,1,source->exception);
cristy4c08aed2011-07-01 19:47:50 +0000565 if (pixels == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000566 {
567 status=MagickFalse;
568 continue;
569 }
cristyc3ebda22010-06-27 17:11:57 +0000570 for (x=0; x < (ssize_t) source->extent.width; x++)
cristy4c08aed2011-07-01 19:47:50 +0000571 {
572 PixelSetQuantumPixel(source->image,pixels,source->pixel_wands[id][x]);
cristyed231572011-07-14 02:18:59 +0000573 pixels+=GetPixelChannels(source->image);
cristy4c08aed2011-07-01 19:47:50 +0000574 }
cristyd6dfc0d2010-06-27 19:30:49 +0000575 if (get(source,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000576 status=MagickFalse;
577 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
578 {
579 MagickBooleanType
580 proceed;
581
cristyb5d5f722009-11-04 03:03:49 +0000582#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy1500c3d2012-01-17 13:57:52 +0000583 #pragma omp critical (MagickWand_GetWandViewIterator)
cristy3ed852e2009-09-05 21:47:34 +0000584#endif
cristyc3ebda22010-06-27 17:11:57 +0000585 proceed=SetImageProgress(source_image,source->description,progress++,
586 source->extent.height);
cristy3ed852e2009-09-05 21:47:34 +0000587 if (proceed == MagickFalse)
588 status=MagickFalse;
589 }
590 }
cristy220c4d52013-11-27 19:31:32 +0000591 return(status);
cristy3ed852e2009-09-05 21:47:34 +0000592}
593
594/*
595%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
596% %
597% %
598% %
cristy7eb1b7a2010-06-26 15:47:49 +0000599% G e t W a n d V i e w P i x e l s %
cristy3ed852e2009-09-05 21:47:34 +0000600% %
601% %
602% %
603%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
604%
cristy73b7d4c2010-06-27 00:31:00 +0000605% GetWandViewPixels() returns the wand view pixel_wands.
cristy3ed852e2009-09-05 21:47:34 +0000606%
cristy7eb1b7a2010-06-26 15:47:49 +0000607% The format of the GetWandViewPixels method is:
cristy3ed852e2009-09-05 21:47:34 +0000608%
cristy73b7d4c2010-06-27 00:31:00 +0000609% PixelWand *GetWandViewPixels(const WandView *wand_view)
cristy3ed852e2009-09-05 21:47:34 +0000610%
611% A description of each parameter follows:
612%
cristy73b7d4c2010-06-27 00:31:00 +0000613% o wand_view: the wand view.
cristy3ed852e2009-09-05 21:47:34 +0000614%
615*/
cristy73b7d4c2010-06-27 00:31:00 +0000616WandExport PixelWand **GetWandViewPixels(const WandView *wand_view)
cristy3ed852e2009-09-05 21:47:34 +0000617{
cristy83e6d2a2010-09-17 17:35:13 +0000618 const int
619 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +0000620
cristy73b7d4c2010-06-27 00:31:00 +0000621 assert(wand_view != (WandView *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000622 assert(wand_view->signature == MagickWandSignature);
cristy73b7d4c2010-06-27 00:31:00 +0000623 return(wand_view->pixel_wands[id]);
cristy3ed852e2009-09-05 21:47:34 +0000624}
625
626/*
627%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
628% %
629% %
630% %
cristy7eb1b7a2010-06-26 15:47:49 +0000631% G e t W a n d V i e w W a n d %
cristy3ed852e2009-09-05 21:47:34 +0000632% %
633% %
634% %
635%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
636%
cristy73b7d4c2010-06-27 00:31:00 +0000637% GetWandViewWand() returns the magick wand associated with the wand view.
cristy3ed852e2009-09-05 21:47:34 +0000638%
cristy7eb1b7a2010-06-26 15:47:49 +0000639% The format of the GetWandViewWand method is:
cristy3ed852e2009-09-05 21:47:34 +0000640%
cristy73b7d4c2010-06-27 00:31:00 +0000641% MagickWand *GetWandViewWand(const WandView *wand_view)
cristy3ed852e2009-09-05 21:47:34 +0000642%
643% A description of each parameter follows:
644%
cristy73b7d4c2010-06-27 00:31:00 +0000645% o wand_view: the wand view.
cristy3ed852e2009-09-05 21:47:34 +0000646%
647*/
cristy73b7d4c2010-06-27 00:31:00 +0000648WandExport MagickWand *GetWandViewWand(const WandView *wand_view)
cristy3ed852e2009-09-05 21:47:34 +0000649{
cristy73b7d4c2010-06-27 00:31:00 +0000650 assert(wand_view != (WandView *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000651 assert(wand_view->signature == MagickWandSignature);
cristy73b7d4c2010-06-27 00:31:00 +0000652 return(wand_view->wand);
cristy3ed852e2009-09-05 21:47:34 +0000653}
654
655/*
656%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
657% %
658% %
659% %
cristy7eb1b7a2010-06-26 15:47:49 +0000660% I s W a n d V i e w %
cristy3ed852e2009-09-05 21:47:34 +0000661% %
662% %
663% %
664%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
665%
cristy73b7d4c2010-06-27 00:31:00 +0000666% IsWandView() returns MagickTrue if the the parameter is verified as a wand
667% view object.
cristy3ed852e2009-09-05 21:47:34 +0000668%
cristy7eb1b7a2010-06-26 15:47:49 +0000669% The format of the IsWandView method is:
cristy3ed852e2009-09-05 21:47:34 +0000670%
cristy73b7d4c2010-06-27 00:31:00 +0000671% MagickBooleanType IsWandView(const WandView *wand_view)
cristy3ed852e2009-09-05 21:47:34 +0000672%
673% A description of each parameter follows:
674%
cristy73b7d4c2010-06-27 00:31:00 +0000675% o wand_view: the wand view.
cristy3ed852e2009-09-05 21:47:34 +0000676%
677*/
cristy73b7d4c2010-06-27 00:31:00 +0000678WandExport MagickBooleanType IsWandView(const WandView *wand_view)
cristy3ed852e2009-09-05 21:47:34 +0000679{
680 size_t
681 length;
682
cristy73b7d4c2010-06-27 00:31:00 +0000683 if (wand_view == (const WandView *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000684 return(MagickFalse);
cristye1c94d92015-06-28 12:16:33 +0000685 if (wand_view->signature != MagickWandSignature)
cristy3ed852e2009-09-05 21:47:34 +0000686 return(MagickFalse);
cristy7eb1b7a2010-06-26 15:47:49 +0000687 length=strlen(WandViewId);
cristy73b7d4c2010-06-27 00:31:00 +0000688 if (LocaleNCompare(wand_view->name,WandViewId,length) != 0)
cristy3ed852e2009-09-05 21:47:34 +0000689 return(MagickFalse);
690 return(MagickTrue);
691}
692
693/*
694%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
695% %
696% %
697% %
cristy7eb1b7a2010-06-26 15:47:49 +0000698% N e w W a n d V i e w %
cristy3ed852e2009-09-05 21:47:34 +0000699% %
700% %
701% %
702%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
703%
cristy73b7d4c2010-06-27 00:31:00 +0000704% NewWandView() returns a wand view required for all other methods in the
705% Wand View API.
cristy3ed852e2009-09-05 21:47:34 +0000706%
cristy7eb1b7a2010-06-26 15:47:49 +0000707% The format of the NewWandView method is:
cristy3ed852e2009-09-05 21:47:34 +0000708%
cristy7eb1b7a2010-06-26 15:47:49 +0000709% WandView *NewWandView(MagickWand *wand)
cristy3ed852e2009-09-05 21:47:34 +0000710%
711% A description of each parameter follows:
712%
713% o wand: the wand.
714%
715*/
716
cristyac245f82012-05-05 17:13:57 +0000717static PixelWand ***AcquirePixelsThreadSet(const size_t number_wands)
cristy3ed852e2009-09-05 21:47:34 +0000718{
719 PixelWand
720 ***pixel_wands;
721
cristybb503372010-05-27 20:51:26 +0000722 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000723 i;
724
cristyac245f82012-05-05 17:13:57 +0000725 size_t
726 number_threads;
727
cristyfeeb98d2012-05-09 16:32:12 +0000728 number_threads=GetOpenMPMaximumThreads();
cristyb41ee102010-10-04 16:46:15 +0000729 pixel_wands=(PixelWand ***) AcquireQuantumMemory(number_threads,
cristy3ed852e2009-09-05 21:47:34 +0000730 sizeof(*pixel_wands));
731 if (pixel_wands == (PixelWand ***) NULL)
732 return((PixelWand ***) NULL);
733 (void) ResetMagickMemory(pixel_wands,0,number_threads*sizeof(*pixel_wands));
cristybb503372010-05-27 20:51:26 +0000734 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000735 {
736 pixel_wands[i]=NewPixelWands(number_wands);
737 if (pixel_wands[i] == (PixelWand **) NULL)
cristyac245f82012-05-05 17:13:57 +0000738 return(DestroyPixelsThreadSet(pixel_wands,number_wands));
cristy3ed852e2009-09-05 21:47:34 +0000739 }
740 return(pixel_wands);
741}
742
cristy7eb1b7a2010-06-26 15:47:49 +0000743WandExport WandView *NewWandView(MagickWand *wand)
cristy3ed852e2009-09-05 21:47:34 +0000744{
cristydb070952012-04-20 14:33:00 +0000745 ExceptionInfo
746 *exception;
747
cristy7eb1b7a2010-06-26 15:47:49 +0000748 WandView
cristy73b7d4c2010-06-27 00:31:00 +0000749 *wand_view;
cristy3ed852e2009-09-05 21:47:34 +0000750
751 assert(wand != (MagickWand *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000752 assert(wand->signature == MagickWandSignature);
cristy73bd4a52010-10-05 11:24:23 +0000753 wand_view=(WandView *) AcquireMagickMemory(sizeof(*wand_view));
cristy73b7d4c2010-06-27 00:31:00 +0000754 if (wand_view == (WandView *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000755 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
756 GetExceptionMessage(errno));
cristy73b7d4c2010-06-27 00:31:00 +0000757 (void) ResetMagickMemory(wand_view,0,sizeof(*wand_view));
758 wand_view->id=AcquireWandId();
cristy151b66d2015-04-15 10:50:31 +0000759 (void) FormatLocaleString(wand_view->name,MagickPathExtent,"%s-%.20g",
cristy73b7d4c2010-06-27 00:31:00 +0000760 WandViewId,(double) wand_view->id);
cristyc3ebda22010-06-27 17:11:57 +0000761 wand_view->description=ConstantString("WandView");
cristy73b7d4c2010-06-27 00:31:00 +0000762 wand_view->wand=wand;
cristydb070952012-04-20 14:33:00 +0000763 exception=AcquireExceptionInfo();
cristy46ff2672012-12-14 15:32:26 +0000764 wand_view->view=AcquireVirtualCacheView(wand_view->wand->images,exception);
cristyc3ebda22010-06-27 17:11:57 +0000765 wand_view->extent.width=wand->images->columns;
766 wand_view->extent.height=wand->images->rows;
cristyac245f82012-05-05 17:13:57 +0000767 wand_view->pixel_wands=AcquirePixelsThreadSet(wand_view->extent.width);
cristydb070952012-04-20 14:33:00 +0000768 wand_view->exception=exception;
cristyc3ebda22010-06-27 17:11:57 +0000769 if (wand_view->pixel_wands == (PixelWand ***) NULL)
770 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
771 GetExceptionMessage(errno));
772 wand_view->debug=IsEventLogging();
cristye1c94d92015-06-28 12:16:33 +0000773 wand_view->signature=MagickWandSignature;
cristyc3ebda22010-06-27 17:11:57 +0000774 return(wand_view);
775}
776
777/*
778%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
779% %
780% %
781% %
782% N e w W a n d V i e w E x t e n t %
783% %
784% %
785% %
786%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
787%
788% NewWandViewExtent() returns a wand view required for all other methods
789% in the Wand View API.
790%
791% The format of the NewWandViewExtent method is:
792%
793% WandView *NewWandViewExtent(MagickWand *wand,const ssize_t x,
794% const ssize_t y,const size_t width,const size_t height)
795%
796% A description of each parameter follows:
797%
798% o wand: the magick wand.
799%
800% o x,y,columns,rows: These values define the perimeter of a extent of
801% pixel_wands view.
802%
803*/
804WandExport WandView *NewWandViewExtent(MagickWand *wand,const ssize_t x,
805 const ssize_t y,const size_t width,const size_t height)
806{
cristydb070952012-04-20 14:33:00 +0000807 ExceptionInfo
808 *exception;
809
cristyc3ebda22010-06-27 17:11:57 +0000810 WandView
811 *wand_view;
812
813 assert(wand != (MagickWand *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000814 assert(wand->signature == MagickWandSignature);
cristy73bd4a52010-10-05 11:24:23 +0000815 wand_view=(WandView *) AcquireMagickMemory(sizeof(*wand_view));
cristyc3ebda22010-06-27 17:11:57 +0000816 if (wand_view == (WandView *) NULL)
817 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
818 GetExceptionMessage(errno));
819 (void) ResetMagickMemory(wand_view,0,sizeof(*wand_view));
820 wand_view->id=AcquireWandId();
cristy151b66d2015-04-15 10:50:31 +0000821 (void) FormatLocaleString(wand_view->name,MagickPathExtent,"%s-%.20g",
cristyc3ebda22010-06-27 17:11:57 +0000822 WandViewId,(double) wand_view->id);
823 wand_view->description=ConstantString("WandView");
cristydb070952012-04-20 14:33:00 +0000824 exception=AcquireExceptionInfo();
cristy46ff2672012-12-14 15:32:26 +0000825 wand_view->view=AcquireVirtualCacheView(wand_view->wand->images,exception);
cristyc3ebda22010-06-27 17:11:57 +0000826 wand_view->wand=wand;
827 wand_view->extent.width=width;
828 wand_view->extent.height=height;
829 wand_view->extent.x=x;
830 wand_view->extent.y=y;
cristydb070952012-04-20 14:33:00 +0000831 wand_view->exception=exception;
cristyac245f82012-05-05 17:13:57 +0000832 wand_view->pixel_wands=AcquirePixelsThreadSet(wand_view->extent.width);
cristy73b7d4c2010-06-27 00:31:00 +0000833 if (wand_view->pixel_wands == (PixelWand ***) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000834 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
835 GetExceptionMessage(errno));
cristy73b7d4c2010-06-27 00:31:00 +0000836 wand_view->debug=IsEventLogging();
cristye1c94d92015-06-28 12:16:33 +0000837 wand_view->signature=MagickWandSignature;
cristy73b7d4c2010-06-27 00:31:00 +0000838 return(wand_view);
cristy3ed852e2009-09-05 21:47:34 +0000839}
840
841/*
842%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
843% %
844% %
845% %
cristyc3ebda22010-06-27 17:11:57 +0000846% S e t W a n d V i e w D e s c r i p t i o n %
cristy3ed852e2009-09-05 21:47:34 +0000847% %
848% %
849% %
850%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
851%
cristyc3ebda22010-06-27 17:11:57 +0000852% SetWandViewDescription() associates a description with an image view.
cristy3ed852e2009-09-05 21:47:34 +0000853%
cristyc3ebda22010-06-27 17:11:57 +0000854% The format of the SetWandViewDescription method is:
cristy3ed852e2009-09-05 21:47:34 +0000855%
cristyc3ebda22010-06-27 17:11:57 +0000856% void SetWandViewDescription(WandView *image_view,const char *description)
cristy3ed852e2009-09-05 21:47:34 +0000857%
858% A description of each parameter follows:
859%
cristyc3ebda22010-06-27 17:11:57 +0000860% o wand_view: the wand view.
cristy3ed852e2009-09-05 21:47:34 +0000861%
cristyc3ebda22010-06-27 17:11:57 +0000862% o description: the wand view description.
cristy3ed852e2009-09-05 21:47:34 +0000863%
864*/
cristyc3ebda22010-06-27 17:11:57 +0000865MagickExport void SetWandViewDescription(WandView *wand_view,
866 const char *description)
cristy3ed852e2009-09-05 21:47:34 +0000867{
cristyc3ebda22010-06-27 17:11:57 +0000868 assert(wand_view != (WandView *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000869 assert(wand_view->signature == MagickWandSignature);
cristyc3ebda22010-06-27 17:11:57 +0000870 wand_view->description=ConstantString(description);
cristy3ed852e2009-09-05 21:47:34 +0000871}
872
873/*
874%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
875% %
876% %
877% %
cristy7eb1b7a2010-06-26 15:47:49 +0000878% S e t W a n d V i e w I t e r a t o r %
cristy3ed852e2009-09-05 21:47:34 +0000879% %
880% %
881% %
882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
883%
cristy73b7d4c2010-06-27 00:31:00 +0000884% SetWandViewIterator() iterates over the wand view in parallel and calls
cristyc3ebda22010-06-27 17:11:57 +0000885% your set method for each scanline of the view. The pixel extent is
cristy3ed852e2009-09-05 21:47:34 +0000886% confined to the image canvas-- that is no negative offsets or widths or
887% heights that exceed the image dimension. The pixels are initiallly
888% undefined and any settings you make in the callback method are automagically
889% synced back to your image.
890%
cristyd6dfc0d2010-06-27 19:30:49 +0000891% The callback signature is:
892%
893% MagickBooleanType SetImageViewMethod(ImageView *destination,
894% const ssize_t y,const int thread_id,void *context)
895%
cristy58739472010-06-26 20:27:18 +0000896% Use this pragma if the view is not single threaded:
cristy3ed852e2009-09-05 21:47:34 +0000897%
898% #pragma omp critical
899%
900% to define a section of code in your callback set method that must be
901% executed by a single thread at a time.
902%
cristy7eb1b7a2010-06-26 15:47:49 +0000903% The format of the SetWandViewIterator method is:
cristy3ed852e2009-09-05 21:47:34 +0000904%
cristy7eb1b7a2010-06-26 15:47:49 +0000905% MagickBooleanType SetWandViewIterator(WandView *destination,
906% SetWandViewMethod set,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000907%
908% A description of each parameter follows:
909%
cristy73b7d4c2010-06-27 00:31:00 +0000910% o destination: the wand view.
cristy3ed852e2009-09-05 21:47:34 +0000911%
912% o set: the set callback method.
913%
914% o context: the user defined context.
915%
916*/
cristy7eb1b7a2010-06-26 15:47:49 +0000917WandExport MagickBooleanType SetWandViewIterator(WandView *destination,
918 SetWandViewMethod set,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000919{
cristy3ed852e2009-09-05 21:47:34 +0000920 Image
921 *destination_image;
922
cristy3ed852e2009-09-05 21:47:34 +0000923 MagickBooleanType
924 status;
925
cristycee97112010-05-28 00:44:52 +0000926 MagickOffsetType
927 progress;
928
glennrpd30b3052012-09-26 12:17:18 +0000929#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +0000930 size_t
cristy26b64912012-12-16 18:20:09 +0000931 height;
glennrpd30b3052012-09-26 12:17:18 +0000932#endif
cristyac245f82012-05-05 17:13:57 +0000933
cristycee97112010-05-28 00:44:52 +0000934 ssize_t
935 y;
936
cristy7eb1b7a2010-06-26 15:47:49 +0000937 assert(destination != (WandView *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000938 assert(destination->signature == MagickWandSignature);
cristy7eb1b7a2010-06-26 15:47:49 +0000939 if (set == (SetWandViewMethod) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000940 return(MagickFalse);
941 destination_image=destination->wand->images;
cristycad4e1b2011-10-16 14:58:39 +0000942 status=SetImageStorageClass(destination_image,DirectClass,
943 destination->exception);
944 if (status == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000945 return(MagickFalse);
946 status=MagickTrue;
947 progress=0;
glennrpd30b3052012-09-26 12:17:18 +0000948#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +0000949 height=destination->extent.height-destination->extent.y;
cristyd6432472013-01-06 16:56:13 +0000950 #pragma omp parallel for schedule(static,4) shared(progress,status) \
cristy5e6b2592012-12-19 14:08:11 +0000951 magick_threads(destination_image,destination_image,height,1)
cristy3ed852e2009-09-05 21:47:34 +0000952#endif
cristyc3ebda22010-06-27 17:11:57 +0000953 for (y=destination->extent.y; y < (ssize_t) destination->extent.height; y++)
cristy3ed852e2009-09-05 21:47:34 +0000954 {
cristy83e6d2a2010-09-17 17:35:13 +0000955 const int
956 id = GetOpenMPThreadId();
cristyad740052010-07-03 01:38:03 +0000957
cristy3ed852e2009-09-05 21:47:34 +0000958 MagickBooleanType
959 sync;
960
cristybb503372010-05-27 20:51:26 +0000961 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000962 x;
963
cristy4c08aed2011-07-01 19:47:50 +0000964 register Quantum
dirk05d2ff72015-11-18 23:13:43 +0100965 *magick_restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000966
967 if (status == MagickFalse)
968 continue;
cristyc3ebda22010-06-27 17:11:57 +0000969 pixels=GetCacheViewAuthenticPixels(destination->view,destination->extent.x,
cristycad4e1b2011-10-16 14:58:39 +0000970 y,destination->extent.width,1,destination->exception);
cristy4c08aed2011-07-01 19:47:50 +0000971 if (pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000972 {
cristy3ed852e2009-09-05 21:47:34 +0000973 status=MagickFalse;
974 continue;
975 }
cristyd6dfc0d2010-06-27 19:30:49 +0000976 if (set(destination,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000977 status=MagickFalse;
cristyc3ebda22010-06-27 17:11:57 +0000978 for (x=0; x < (ssize_t) destination->extent.width; x++)
cristy4c08aed2011-07-01 19:47:50 +0000979 {
980 PixelGetQuantumPixel(destination->image,destination->pixel_wands[id][x],
981 pixels);
cristyed231572011-07-14 02:18:59 +0000982 pixels+=GetPixelChannels(destination->image);
cristy4c08aed2011-07-01 19:47:50 +0000983 }
cristycad4e1b2011-10-16 14:58:39 +0000984 sync=SyncCacheViewAuthenticPixels(destination->view,destination->exception);
cristy3ed852e2009-09-05 21:47:34 +0000985 if (sync == MagickFalse)
cristycad4e1b2011-10-16 14:58:39 +0000986 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000987 if (destination_image->progress_monitor != (MagickProgressMonitor) NULL)
988 {
989 MagickBooleanType
990 proceed;
991
cristyb5d5f722009-11-04 03:03:49 +0000992#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy1500c3d2012-01-17 13:57:52 +0000993 #pragma omp critical (MagickWand_SetWandViewIterator)
cristy3ed852e2009-09-05 21:47:34 +0000994#endif
cristyc3ebda22010-06-27 17:11:57 +0000995 proceed=SetImageProgress(destination_image,destination->description,
996 progress++,destination->extent.height);
cristy3ed852e2009-09-05 21:47:34 +0000997 if (proceed == MagickFalse)
998 status=MagickFalse;
999 }
1000 }
cristy220c4d52013-11-27 19:31:32 +00001001 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001002}
1003
1004/*
1005%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1006% %
1007% %
1008% %
cristy7eb1b7a2010-06-26 15:47:49 +00001009% T r a n s f e r W a n d V i e w I t e r a t o r %
cristy3ed852e2009-09-05 21:47:34 +00001010% %
1011% %
1012% %
1013%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1014%
cristy73b7d4c2010-06-27 00:31:00 +00001015% TransferWandViewIterator() iterates over two wand views in parallel and
cristy3ed852e2009-09-05 21:47:34 +00001016% calls your transfer method for each scanline of the view. The source pixel
cristyc3ebda22010-06-27 17:11:57 +00001017% extent is not confined to the image canvas-- that is you can include
cristy3ed852e2009-09-05 21:47:34 +00001018% negative offsets or widths or heights that exceed the image dimension.
cristy73b7d4c2010-06-27 00:31:00 +00001019% However, the destination wand view is confined to the image canvas-- that
cristy3ed852e2009-09-05 21:47:34 +00001020% is no negative offsets or widths or heights that exceed the image dimension
1021% are permitted.
1022%
cristyd6dfc0d2010-06-27 19:30:49 +00001023% The callback signature is:
1024%
1025% MagickBooleanType TransferImageViewMethod(const WandView *source,
1026% WandView *destination,const ssize_t y,const int thread_id,
1027% void *context)
1028%
cristy58739472010-06-26 20:27:18 +00001029% Use this pragma if the view is not single threaded:
cristy3ed852e2009-09-05 21:47:34 +00001030%
1031% #pragma omp critical
1032%
1033% to define a section of code in your callback transfer method that must be
1034% executed by a single thread at a time.
1035%
cristy7eb1b7a2010-06-26 15:47:49 +00001036% The format of the TransferWandViewIterator method is:
cristy3ed852e2009-09-05 21:47:34 +00001037%
cristy7eb1b7a2010-06-26 15:47:49 +00001038% MagickBooleanType TransferWandViewIterator(WandView *source,
1039% WandView *destination,TransferWandViewMethod transfer,void *context)
cristy3ed852e2009-09-05 21:47:34 +00001040%
1041% A description of each parameter follows:
1042%
cristy73b7d4c2010-06-27 00:31:00 +00001043% o source: the source wand view.
cristy3ed852e2009-09-05 21:47:34 +00001044%
cristy73b7d4c2010-06-27 00:31:00 +00001045% o destination: the destination wand view.
cristy3ed852e2009-09-05 21:47:34 +00001046%
1047% o transfer: the transfer callback method.
1048%
1049% o context: the user defined context.
1050%
1051*/
cristy7eb1b7a2010-06-26 15:47:49 +00001052WandExport MagickBooleanType TransferWandViewIterator(WandView *source,
1053 WandView *destination,TransferWandViewMethod transfer,void *context)
cristy3ed852e2009-09-05 21:47:34 +00001054{
cristy3ed852e2009-09-05 21:47:34 +00001055 Image
1056 *destination_image,
1057 *source_image;
1058
cristy3ed852e2009-09-05 21:47:34 +00001059 MagickBooleanType
1060 status;
1061
cristycee97112010-05-28 00:44:52 +00001062 MagickOffsetType
1063 progress;
1064
glennrpd30b3052012-09-26 12:17:18 +00001065#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00001066 size_t
cristy26b64912012-12-16 18:20:09 +00001067 height;
glennrpd30b3052012-09-26 12:17:18 +00001068#endif
cristyac245f82012-05-05 17:13:57 +00001069
cristycee97112010-05-28 00:44:52 +00001070 ssize_t
1071 y;
1072
cristy7eb1b7a2010-06-26 15:47:49 +00001073 assert(source != (WandView *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001074 assert(source->signature == MagickWandSignature);
cristy7eb1b7a2010-06-26 15:47:49 +00001075 if (transfer == (TransferWandViewMethod) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001076 return(MagickFalse);
1077 source_image=source->wand->images;
1078 destination_image=destination->wand->images;
cristycad4e1b2011-10-16 14:58:39 +00001079 status=SetImageStorageClass(destination_image,DirectClass,
1080 destination->exception);
1081 if (status == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001082 return(MagickFalse);
1083 status=MagickTrue;
1084 progress=0;
glennrpd30b3052012-09-26 12:17:18 +00001085#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00001086 height=source->extent.height-source->extent.y;
cristyd6432472013-01-06 16:56:13 +00001087 #pragma omp parallel for schedule(static,4) shared(progress,status) \
cristy5e6b2592012-12-19 14:08:11 +00001088 magick_threads(source_image,destination_image,height,1)
cristy3ed852e2009-09-05 21:47:34 +00001089#endif
cristyc3ebda22010-06-27 17:11:57 +00001090 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
cristy3ed852e2009-09-05 21:47:34 +00001091 {
cristy83e6d2a2010-09-17 17:35:13 +00001092 const int
1093 id = GetOpenMPThreadId();
cristyad740052010-07-03 01:38:03 +00001094
cristy3ed852e2009-09-05 21:47:34 +00001095 MagickBooleanType
1096 sync;
1097
cristy4c08aed2011-07-01 19:47:50 +00001098 register const Quantum
dirk05d2ff72015-11-18 23:13:43 +01001099 *magick_restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001100
cristybb503372010-05-27 20:51:26 +00001101 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001102 x;
1103
cristy4c08aed2011-07-01 19:47:50 +00001104 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01001105 *magick_restrict destination_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001106
1107 if (status == MagickFalse)
1108 continue;
cristyc3ebda22010-06-27 17:11:57 +00001109 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
1110 source->extent.width,1,source->exception);
cristy4c08aed2011-07-01 19:47:50 +00001111 if (pixels == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001112 {
1113 status=MagickFalse;
1114 continue;
1115 }
cristyc3ebda22010-06-27 17:11:57 +00001116 for (x=0; x < (ssize_t) source->extent.width; x++)
cristy4c08aed2011-07-01 19:47:50 +00001117 {
1118 PixelSetQuantumPixel(source->image,pixels,source->pixel_wands[id][x]);
cristyed231572011-07-14 02:18:59 +00001119 pixels+=GetPixelChannels(source->image);
cristy4c08aed2011-07-01 19:47:50 +00001120 }
cristy3ed852e2009-09-05 21:47:34 +00001121 destination_pixels=GetCacheViewAuthenticPixels(destination->view,
cristycad4e1b2011-10-16 14:58:39 +00001122 destination->extent.x,y,destination->extent.width,1,
1123 destination->exception);
cristy4c08aed2011-07-01 19:47:50 +00001124 if (destination_pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001125 {
1126 status=MagickFalse;
1127 continue;
1128 }
cristyc3ebda22010-06-27 17:11:57 +00001129 for (x=0; x < (ssize_t) destination->extent.width; x++)
cristy4c08aed2011-07-01 19:47:50 +00001130 {
1131 PixelSetQuantumPixel(destination->image,destination_pixels,
1132 destination->pixel_wands[id][x]);
cristyed231572011-07-14 02:18:59 +00001133 destination_pixels+=GetPixelChannels(destination->image);
cristy4c08aed2011-07-01 19:47:50 +00001134 }
cristyc3ebda22010-06-27 17:11:57 +00001135 if (transfer(source,destination,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001136 status=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001137 destination_pixels=GetCacheViewAuthenticPixels(destination->view,
cristycad4e1b2011-10-16 14:58:39 +00001138 destination->extent.x,y,destination->extent.width,1,
1139 destination->exception);
cristyc3ebda22010-06-27 17:11:57 +00001140 for (x=0; x < (ssize_t) destination->extent.width; x++)
cristy4c08aed2011-07-01 19:47:50 +00001141 {
1142 PixelGetQuantumPixel(destination->image,destination->pixel_wands[id][x],
1143 destination_pixels);
cristyed231572011-07-14 02:18:59 +00001144 destination_pixels+=GetPixelChannels(destination->image);
cristy4c08aed2011-07-01 19:47:50 +00001145 }
cristycad4e1b2011-10-16 14:58:39 +00001146 sync=SyncCacheViewAuthenticPixels(destination->view,destination->exception);
cristy3ed852e2009-09-05 21:47:34 +00001147 if (sync == MagickFalse)
cristycad4e1b2011-10-16 14:58:39 +00001148 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00001149 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1150 {
1151 MagickBooleanType
1152 proceed;
1153
cristyb5d5f722009-11-04 03:03:49 +00001154#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy1500c3d2012-01-17 13:57:52 +00001155 #pragma omp critical (MagickWand_TransferWandViewIterator)
cristy3ed852e2009-09-05 21:47:34 +00001156#endif
cristyc3ebda22010-06-27 17:11:57 +00001157 proceed=SetImageProgress(source_image,source->description,progress++,
1158 source->extent.height);
cristy3ed852e2009-09-05 21:47:34 +00001159 if (proceed == MagickFalse)
1160 status=MagickFalse;
1161 }
1162 }
cristy220c4d52013-11-27 19:31:32 +00001163 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001164}
1165
1166/*
1167%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1168% %
1169% %
1170% %
cristy7eb1b7a2010-06-26 15:47:49 +00001171% U p d a t e W a n d V i e w I t e r a t o r %
cristy3ed852e2009-09-05 21:47:34 +00001172% %
1173% %
1174% %
1175%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1176%
cristy73b7d4c2010-06-27 00:31:00 +00001177% UpdateWandViewIterator() iterates over the wand view in parallel and calls
cristyc3ebda22010-06-27 17:11:57 +00001178% your update method for each scanline of the view. The pixel extent is
cristy3ed852e2009-09-05 21:47:34 +00001179% confined to the image canvas-- that is no negative offsets or widths or
1180% heights that exceed the image dimension are permitted. Updates to pixels
1181% in your callback are automagically synced back to the image.
1182%
cristyd6dfc0d2010-06-27 19:30:49 +00001183% The callback signature is:
1184%
1185% MagickBooleanType UpdateImageViewMethod(WandView *source,const ssize_t y,
1186% const int thread_id,void *context)
1187%
cristy58739472010-06-26 20:27:18 +00001188% Use this pragma if the view is not single threaded:
cristy3ed852e2009-09-05 21:47:34 +00001189%
1190% #pragma omp critical
1191%
1192% to define a section of code in your callback update method that must be
1193% executed by a single thread at a time.
1194%
cristy7eb1b7a2010-06-26 15:47:49 +00001195% The format of the UpdateWandViewIterator method is:
cristy3ed852e2009-09-05 21:47:34 +00001196%
cristy7eb1b7a2010-06-26 15:47:49 +00001197% MagickBooleanType UpdateWandViewIterator(WandView *source,
1198% UpdateWandViewMethod update,void *context)
cristy3ed852e2009-09-05 21:47:34 +00001199%
1200% A description of each parameter follows:
1201%
cristy73b7d4c2010-06-27 00:31:00 +00001202% o source: the source wand view.
cristy3ed852e2009-09-05 21:47:34 +00001203%
1204% o update: the update callback method.
1205%
1206% o context: the user defined context.
1207%
1208*/
cristy7eb1b7a2010-06-26 15:47:49 +00001209WandExport MagickBooleanType UpdateWandViewIterator(WandView *source,
1210 UpdateWandViewMethod update,void *context)
cristy3ed852e2009-09-05 21:47:34 +00001211{
cristy3ed852e2009-09-05 21:47:34 +00001212 Image
1213 *source_image;
1214
cristy3ed852e2009-09-05 21:47:34 +00001215 MagickBooleanType
1216 status;
1217
cristycee97112010-05-28 00:44:52 +00001218 MagickOffsetType
1219 progress;
1220
glennrpd30b3052012-09-26 12:17:18 +00001221#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00001222 size_t
cristy26b64912012-12-16 18:20:09 +00001223 height;
glennrpd30b3052012-09-26 12:17:18 +00001224#endif
cristyac245f82012-05-05 17:13:57 +00001225
cristycee97112010-05-28 00:44:52 +00001226 ssize_t
1227 y;
1228
cristy7eb1b7a2010-06-26 15:47:49 +00001229 assert(source != (WandView *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001230 assert(source->signature == MagickWandSignature);
cristy7eb1b7a2010-06-26 15:47:49 +00001231 if (update == (UpdateWandViewMethod) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001232 return(MagickFalse);
1233 source_image=source->wand->images;
cristycad4e1b2011-10-16 14:58:39 +00001234 status=SetImageStorageClass(source_image,DirectClass,source->exception);
1235 if (status == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001236 return(MagickFalse);
1237 status=MagickTrue;
1238 progress=0;
glennrpd30b3052012-09-26 12:17:18 +00001239#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00001240 height=source->extent.height-source->extent.y;
cristyd6432472013-01-06 16:56:13 +00001241 #pragma omp parallel for schedule(static,4) shared(progress,status) \
cristy5e6b2592012-12-19 14:08:11 +00001242 magick_threads(source_image,source_image,height,1)
cristy3ed852e2009-09-05 21:47:34 +00001243#endif
cristyc3ebda22010-06-27 17:11:57 +00001244 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
cristy3ed852e2009-09-05 21:47:34 +00001245 {
cristy83e6d2a2010-09-17 17:35:13 +00001246 const int
1247 id = GetOpenMPThreadId();
cristyad740052010-07-03 01:38:03 +00001248
cristycad4e1b2011-10-16 14:58:39 +00001249 MagickBooleanType
1250 sync;
1251
cristybb503372010-05-27 20:51:26 +00001252 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001253 x;
1254
cristy4c08aed2011-07-01 19:47:50 +00001255 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01001256 *magick_restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001257
1258 if (status == MagickFalse)
1259 continue;
cristyc3ebda22010-06-27 17:11:57 +00001260 pixels=GetCacheViewAuthenticPixels(source->view,source->extent.x,y,
cristycad4e1b2011-10-16 14:58:39 +00001261 source->extent.width,1,source->exception);
cristy4c08aed2011-07-01 19:47:50 +00001262 if (pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001263 {
cristy3ed852e2009-09-05 21:47:34 +00001264 status=MagickFalse;
1265 continue;
1266 }
cristyc3ebda22010-06-27 17:11:57 +00001267 for (x=0; x < (ssize_t) source->extent.width; x++)
cristy4c08aed2011-07-01 19:47:50 +00001268 {
1269 PixelSetQuantumPixel(source->image,pixels,source->pixel_wands[id][x]);
cristyed231572011-07-14 02:18:59 +00001270 pixels+=GetPixelChannels(source->image);
cristy4c08aed2011-07-01 19:47:50 +00001271 }
cristyc3ebda22010-06-27 17:11:57 +00001272 if (update(source,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001273 status=MagickFalse;
cristyc3ebda22010-06-27 17:11:57 +00001274 for (x=0; x < (ssize_t) source->extent.width; x++)
cristy4c08aed2011-07-01 19:47:50 +00001275 {
1276 PixelGetQuantumPixel(source->image,source->pixel_wands[id][x],pixels);
cristyed231572011-07-14 02:18:59 +00001277 pixels+=GetPixelChannels(source->image);
cristy4c08aed2011-07-01 19:47:50 +00001278 }
cristycad4e1b2011-10-16 14:58:39 +00001279 sync=SyncCacheViewAuthenticPixels(source->view,source->exception);
1280 if (sync == MagickFalse)
1281 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00001282 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1283 {
1284 MagickBooleanType
1285 proceed;
1286
cristyb5d5f722009-11-04 03:03:49 +00001287#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy1500c3d2012-01-17 13:57:52 +00001288 #pragma omp critical (MagickWand_UpdateWandViewIterator)
cristy3ed852e2009-09-05 21:47:34 +00001289#endif
cristyc3ebda22010-06-27 17:11:57 +00001290 proceed=SetImageProgress(source_image,source->description,progress++,
1291 source->extent.height);
cristy3ed852e2009-09-05 21:47:34 +00001292 if (proceed == MagickFalse)
1293 status=MagickFalse;
1294 }
1295 }
cristy220c4d52013-11-27 19:31:32 +00001296 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001297}