blob: 16f95022bf840d4a80e2b8cafde02f92482f78e2 [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 %
21% John Cristy %
22% March 2003 %
23% %
24% %
cristy7e41fe82010-12-04 23:12:08 +000025% Copyright 1999-2011 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*/
48#include "wand/studio.h"
49#include "wand/MagickWand.h"
50#include "wand/magick-wand-private.h"
51#include "wand/wand.h"
52#include "magick/monitor-private.h"
53#include "magick/thread-private.h"
54/*
55 Define declarations.
56*/
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
cristyc3ebda22010-06-27 17:11:57 +000068 name[MaxTextExtent],
69 *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
77 CacheView
78 *view;
79
cristybb503372010-05-27 20:51:26 +000080 size_t
cristy3ed852e2009-09-05 21:47:34 +000081 number_threads;
82
83 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);
127 assert(wand_view->signature == WandSignature);
128 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();
cristye8c25f92010-06-03 00:53:06 +0000136 (void) FormatMagickString(clone_view->name,MaxTextExtent,"%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);
139 clone_view->view=CloneCacheView(wand_view->view);
140 clone_view->extent=wand_view->extent;
141 clone_view->number_threads=wand_view->number_threads;
cristy3ed852e2009-09-05 21:47:34 +0000142 clone_view->exception=AcquireExceptionInfo();
cristy73b7d4c2010-06-27 00:31:00 +0000143 InheritException(clone_view->exception,wand_view->exception);
cristy73b7d4c2010-06-27 00:31:00 +0000144 for (i=0; i < (ssize_t) wand_view->number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000145 clone_view->pixel_wands[i]=ClonePixelWands((const PixelWand **)
cristyc3ebda22010-06-27 17:11:57 +0000146 wand_view->pixel_wands[i],wand_view->extent.width);
cristy73b7d4c2010-06-27 00:31:00 +0000147 clone_view->debug=wand_view->debug;
cristy3ed852e2009-09-05 21:47:34 +0000148 if (clone_view->debug != MagickFalse)
149 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",clone_view->name);
150 clone_view->signature=WandSignature;
151 return(clone_view);
152}
153
154/*
155%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
156% %
157% %
158% %
cristy7eb1b7a2010-06-26 15:47:49 +0000159% D e s t r o y W a n d V i e w %
cristy3ed852e2009-09-05 21:47:34 +0000160% %
161% %
162% %
163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
164%
cristy73b7d4c2010-06-27 00:31:00 +0000165% DestroyWandView() deallocates memory associated with a wand view.
cristy3ed852e2009-09-05 21:47:34 +0000166%
cristy7eb1b7a2010-06-26 15:47:49 +0000167% The format of the DestroyWandView method is:
cristy3ed852e2009-09-05 21:47:34 +0000168%
cristy73b7d4c2010-06-27 00:31:00 +0000169% WandView *DestroyWandView(WandView *wand_view)
cristy3ed852e2009-09-05 21:47:34 +0000170%
171% A description of each parameter follows:
172%
cristy73b7d4c2010-06-27 00:31:00 +0000173% o wand_view: the wand view.
cristy3ed852e2009-09-05 21:47:34 +0000174%
175*/
176
177static PixelWand ***DestroyPixelsThreadSet(PixelWand ***pixel_wands,
cristybb503372010-05-27 20:51:26 +0000178 const size_t number_wands,const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000179{
cristybb503372010-05-27 20:51:26 +0000180 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000181 i;
182
183 assert(pixel_wands != (PixelWand ***) NULL);
cristybb503372010-05-27 20:51:26 +0000184 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000185 if (pixel_wands[i] != (PixelWand **) NULL)
186 pixel_wands[i]=DestroyPixelWands(pixel_wands[i],number_wands);
cristyb41ee102010-10-04 16:46:15 +0000187 pixel_wands=(PixelWand ***) RelinquishMagickMemory(pixel_wands);
cristy3ed852e2009-09-05 21:47:34 +0000188 return(pixel_wands);
189}
190
cristy73b7d4c2010-06-27 00:31:00 +0000191WandExport WandView *DestroyWandView(WandView *wand_view)
cristy3ed852e2009-09-05 21:47:34 +0000192{
cristy73b7d4c2010-06-27 00:31:00 +0000193 assert(wand_view != (WandView *) NULL);
194 assert(wand_view->signature == WandSignature);
195 wand_view->pixel_wands=DestroyPixelsThreadSet(wand_view->pixel_wands,
cristyc3ebda22010-06-27 17:11:57 +0000196 wand_view->extent.width,wand_view->number_threads);
cristy73b7d4c2010-06-27 00:31:00 +0000197 wand_view->view=DestroyCacheView(wand_view->view);
198 wand_view->exception=DestroyExceptionInfo(wand_view->exception);
199 wand_view->signature=(~WandSignature);
200 RelinquishWandId(wand_view->id);
201 wand_view=(WandView *) RelinquishMagickMemory(wand_view);
202 return(wand_view);
cristy3ed852e2009-09-05 21:47:34 +0000203}
204
205/*
206%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
207% %
208% %
209% %
cristy7eb1b7a2010-06-26 15:47:49 +0000210% 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 +0000211% %
212% %
213% %
214%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
215%
cristy73b7d4c2010-06-27 00:31:00 +0000216% DuplexTransferWandViewIterator() iterates over three wand views in
cristy3ed852e2009-09-05 21:47:34 +0000217% parallel and calls your transfer method for each scanline of the view. The
cristyc3ebda22010-06-27 17:11:57 +0000218% source and duplex pixel extent is not confined to the image canvas-- that is
cristy3ed852e2009-09-05 21:47:34 +0000219% you can include negative offsets or widths or heights that exceed the image
cristy73b7d4c2010-06-27 00:31:00 +0000220% dimension. However, the destination wand view is confined to the image
cristy3ed852e2009-09-05 21:47:34 +0000221% canvas-- that is no negative offsets or widths or heights that exceed the
222% image dimension are permitted.
223%
cristyd6dfc0d2010-06-27 19:30:49 +0000224% The callback signature is:
225%
226% MagickBooleanType DuplexTransferImageViewMethod(const WandView *source,
227% const WandView *duplex,WandView *destination,const ssize_t y,
228% const int thread_id,void *context)
229%
cristy58739472010-06-26 20:27:18 +0000230% Use this pragma if the view is not single threaded:
cristy3ed852e2009-09-05 21:47:34 +0000231%
232% #pragma omp critical
233%
234% to define a section of code in your callback transfer method that must be
235% executed by a single thread at a time.
236%
cristy7eb1b7a2010-06-26 15:47:49 +0000237% The format of the DuplexTransferWandViewIterator method is:
cristy3ed852e2009-09-05 21:47:34 +0000238%
cristy7eb1b7a2010-06-26 15:47:49 +0000239% MagickBooleanType DuplexTransferWandViewIterator(WandView *source,
240% WandView *duplex,WandView *destination,
241% DuplexTransferWandViewMethod transfer,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000242%
243% A description of each parameter follows:
244%
cristy73b7d4c2010-06-27 00:31:00 +0000245% o source: the source wand view.
cristy3ed852e2009-09-05 21:47:34 +0000246%
cristy73b7d4c2010-06-27 00:31:00 +0000247% o duplex: the duplex wand view.
cristy3ed852e2009-09-05 21:47:34 +0000248%
cristy73b7d4c2010-06-27 00:31:00 +0000249% o destination: the destination wand view.
cristy3ed852e2009-09-05 21:47:34 +0000250%
251% o transfer: the transfer callback method.
252%
253% o context: the user defined context.
254%
255*/
cristy58739472010-06-26 20:27:18 +0000256WandExport MagickBooleanType DuplexTransferWandViewIterator(WandView *source,
257 WandView *duplex,WandView *destination,DuplexTransferWandViewMethod transfer,
258 void *context)
cristy3ed852e2009-09-05 21:47:34 +0000259{
cristy3ed852e2009-09-05 21:47:34 +0000260 ExceptionInfo
261 *exception;
262
263 Image
264 *destination_image,
265 *duplex_image,
266 *source_image;
267
cristy3ed852e2009-09-05 21:47:34 +0000268 MagickBooleanType
269 status;
270
cristycee97112010-05-28 00:44:52 +0000271 MagickOffsetType
272 progress;
273
274 ssize_t
275 y;
276
cristy7eb1b7a2010-06-26 15:47:49 +0000277 assert(source != (WandView *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000278 assert(source->signature == WandSignature);
cristy7eb1b7a2010-06-26 15:47:49 +0000279 if (transfer == (DuplexTransferWandViewMethod) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000280 return(MagickFalse);
281 source_image=source->wand->images;
282 duplex_image=duplex->wand->images;
283 destination_image=destination->wand->images;
284 if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
285 return(MagickFalse);
286 status=MagickTrue;
287 progress=0;
288 exception=destination->exception;
cristyb5d5f722009-11-04 03:03:49 +0000289#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy09d81172010-10-21 16:15:05 +0000290 #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(source->number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000291#endif
cristyc3ebda22010-06-27 17:11:57 +0000292 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
cristy3ed852e2009-09-05 21:47:34 +0000293 {
cristy83e6d2a2010-09-17 17:35:13 +0000294 const int
295 id = GetOpenMPThreadId();
cristyad740052010-07-03 01:38:03 +0000296
cristy3ed852e2009-09-05 21:47:34 +0000297 MagickBooleanType
298 sync;
299
300 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000301 *restrict duplex_indexes,
302 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +0000303
304 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000305 *restrict duplex_pixels,
306 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000307
308 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000309 *restrict destination_indexes;
cristy3ed852e2009-09-05 21:47:34 +0000310
cristybb503372010-05-27 20:51:26 +0000311 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000312 x;
313
314 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000315 *restrict destination_pixels;
cristy3ed852e2009-09-05 21:47:34 +0000316
317 if (status == MagickFalse)
318 continue;
cristyc3ebda22010-06-27 17:11:57 +0000319 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
320 source->extent.width,1,source->exception);
cristy3ed852e2009-09-05 21:47:34 +0000321 if (pixels == (const PixelPacket *) NULL)
322 {
323 status=MagickFalse;
324 continue;
325 }
326 indexes=GetCacheViewVirtualIndexQueue(source->view);
cristyc3ebda22010-06-27 17:11:57 +0000327 for (x=0; x < (ssize_t) source->extent.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000328 PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
329 if (source_image->colorspace == CMYKColorspace)
cristyc3ebda22010-06-27 17:11:57 +0000330 for (x=0; x < (ssize_t) source->extent.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000331 PixelSetBlackQuantum(source->pixel_wands[id][x],indexes[x]);
332 if (source_image->storage_class == PseudoClass)
cristyc3ebda22010-06-27 17:11:57 +0000333 for (x=0; x < (ssize_t) source->extent.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000334 PixelSetIndex(source->pixel_wands[id][x],indexes[x]);
cristyc3ebda22010-06-27 17:11:57 +0000335 duplex_pixels=GetCacheViewVirtualPixels(duplex->view,duplex->extent.x,y,
336 duplex->extent.width,1,duplex->exception);
cristy3ed852e2009-09-05 21:47:34 +0000337 if (duplex_pixels == (const PixelPacket *) NULL)
338 {
339 status=MagickFalse;
340 continue;
341 }
342 duplex_indexes=GetCacheViewVirtualIndexQueue(duplex->view);
cristyc3ebda22010-06-27 17:11:57 +0000343 for (x=0; x < (ssize_t) duplex->extent.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000344 PixelSetQuantumColor(duplex->pixel_wands[id][x],duplex_pixels+x);
345 if (duplex_image->colorspace == CMYKColorspace)
cristyc3ebda22010-06-27 17:11:57 +0000346 for (x=0; x < (ssize_t) duplex->extent.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000347 PixelSetBlackQuantum(duplex->pixel_wands[id][x],duplex_indexes[x]);
348 if (duplex_image->storage_class == PseudoClass)
cristyc3ebda22010-06-27 17:11:57 +0000349 for (x=0; x < (ssize_t) duplex->extent.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000350 PixelSetIndex(duplex->pixel_wands[id][x],duplex_indexes[x]);
351 destination_pixels=GetCacheViewAuthenticPixels(destination->view,
cristyc3ebda22010-06-27 17:11:57 +0000352 destination->extent.x,y,destination->extent.width,1,exception);
cristy3ed852e2009-09-05 21:47:34 +0000353 if (destination_pixels == (PixelPacket *) NULL)
354 {
355 status=MagickFalse;
356 continue;
357 }
358 destination_indexes=GetCacheViewAuthenticIndexQueue(destination->view);
cristyc3ebda22010-06-27 17:11:57 +0000359 for (x=0; x < (ssize_t) destination->extent.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000360 PixelSetQuantumColor(destination->pixel_wands[id][x],
361 destination_pixels+x);
362 if (destination_image->colorspace == CMYKColorspace)
cristyc3ebda22010-06-27 17:11:57 +0000363 for (x=0; x < (ssize_t) destination->extent.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000364 PixelSetBlackQuantum(destination->pixel_wands[id][x],
365 destination_indexes[x]);
366 if (destination_image->storage_class == PseudoClass)
cristyc3ebda22010-06-27 17:11:57 +0000367 for (x=0; x < (ssize_t) destination->extent.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000368 PixelSetIndex(destination->pixel_wands[id][x],destination_indexes[x]);
cristyc3ebda22010-06-27 17:11:57 +0000369 if (transfer(source,duplex,destination,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000370 status=MagickFalse;
cristyc3ebda22010-06-27 17:11:57 +0000371 for (x=0; x < (ssize_t) destination->extent.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000372 PixelGetQuantumColor(destination->pixel_wands[id][x],
373 destination_pixels+x);
374 if (destination_image->colorspace == CMYKColorspace)
cristyc3ebda22010-06-27 17:11:57 +0000375 for (x=0; x < (ssize_t) destination->extent.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000376 destination_indexes[x]=PixelGetBlackQuantum(
377 destination->pixel_wands[id][x]);
378 sync=SyncCacheViewAuthenticPixels(destination->view,exception);
379 if (sync == MagickFalse)
380 {
381 InheritException(destination->exception,GetCacheViewException(
382 source->view));
383 status=MagickFalse;
384 }
385 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
386 {
387 MagickBooleanType
388 proceed;
389
cristyb5d5f722009-11-04 03:03:49 +0000390#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy7eb1b7a2010-06-26 15:47:49 +0000391 #pragma omp critical (MagickWand_DuplexTransferWandViewIterator)
cristy3ed852e2009-09-05 21:47:34 +0000392#endif
cristyc3ebda22010-06-27 17:11:57 +0000393 proceed=SetImageProgress(source_image,source->description,progress++,
394 source->extent.height);
cristy3ed852e2009-09-05 21:47:34 +0000395 if (proceed == MagickFalse)
396 status=MagickFalse;
397 }
398 }
399 return(status);
400}
401
402/*
403%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
404% %
405% %
406% %
cristy7eb1b7a2010-06-26 15:47:49 +0000407% 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 +0000408% %
409% %
410% %
411%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
412%
cristy7eb1b7a2010-06-26 15:47:49 +0000413% GetWandViewException() returns the severity, reason, and description of any
cristy73b7d4c2010-06-27 00:31:00 +0000414% error that occurs when utilizing a wand view.
cristy3ed852e2009-09-05 21:47:34 +0000415%
cristy7eb1b7a2010-06-26 15:47:49 +0000416% The format of the GetWandViewException method is:
cristy3ed852e2009-09-05 21:47:34 +0000417%
cristy73b7d4c2010-06-27 00:31:00 +0000418% char *GetWandViewException(const PixelWand *wand_view,
cristy3ed852e2009-09-05 21:47:34 +0000419% ExceptionType *severity)
420%
421% A description of each parameter follows:
422%
cristy73b7d4c2010-06-27 00:31:00 +0000423% o wand_view: the pixel wand_view.
cristy3ed852e2009-09-05 21:47:34 +0000424%
425% o severity: the severity of the error is returned here.
426%
427*/
cristy73b7d4c2010-06-27 00:31:00 +0000428WandExport char *GetWandViewException(const WandView *wand_view,
cristy3ed852e2009-09-05 21:47:34 +0000429 ExceptionType *severity)
430{
431 char
432 *description;
433
cristy73b7d4c2010-06-27 00:31:00 +0000434 assert(wand_view != (const WandView *) NULL);
435 assert(wand_view->signature == WandSignature);
436 if (wand_view->debug != MagickFalse)
437 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand_view->name);
cristy3ed852e2009-09-05 21:47:34 +0000438 assert(severity != (ExceptionType *) NULL);
cristy73b7d4c2010-06-27 00:31:00 +0000439 *severity=wand_view->exception->severity;
cristy3ed852e2009-09-05 21:47:34 +0000440 description=(char *) AcquireQuantumMemory(2UL*MaxTextExtent,
441 sizeof(*description));
442 if (description == (char *) NULL)
443 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
cristy73b7d4c2010-06-27 00:31:00 +0000444 wand_view->name);
cristy3ed852e2009-09-05 21:47:34 +0000445 *description='\0';
cristy73b7d4c2010-06-27 00:31:00 +0000446 if (wand_view->exception->reason != (char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000447 (void) CopyMagickString(description,GetLocaleExceptionMessage(
cristy73b7d4c2010-06-27 00:31:00 +0000448 wand_view->exception->severity,wand_view->exception->reason),
cristy3ed852e2009-09-05 21:47:34 +0000449 MaxTextExtent);
cristy73b7d4c2010-06-27 00:31:00 +0000450 if (wand_view->exception->description != (char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000451 {
452 (void) ConcatenateMagickString(description," (",MaxTextExtent);
453 (void) ConcatenateMagickString(description,GetLocaleExceptionMessage(
cristy73b7d4c2010-06-27 00:31:00 +0000454 wand_view->exception->severity,wand_view->exception->description),
cristy3ed852e2009-09-05 21:47:34 +0000455 MaxTextExtent);
456 (void) ConcatenateMagickString(description,")",MaxTextExtent);
457 }
458 return(description);
459}
460
461/*
462%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
463% %
464% %
465% %
cristyc3ebda22010-06-27 17:11:57 +0000466% G e t W a n d V i e w E x t e n t %
cristy3ed852e2009-09-05 21:47:34 +0000467% %
468% %
469% %
470%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
471%
cristyc3ebda22010-06-27 17:11:57 +0000472% GetWandViewExtent() returns the wand view extent.
cristy3ed852e2009-09-05 21:47:34 +0000473%
cristyc3ebda22010-06-27 17:11:57 +0000474% The format of the GetWandViewExtent method is:
cristy3ed852e2009-09-05 21:47:34 +0000475%
cristyc3ebda22010-06-27 17:11:57 +0000476% RectangleInfo GetWandViewExtent(const WandView *wand_view)
cristy3ed852e2009-09-05 21:47:34 +0000477%
478% A description of each parameter follows:
479%
cristy73b7d4c2010-06-27 00:31:00 +0000480% o wand_view: the wand view.
cristy3ed852e2009-09-05 21:47:34 +0000481%
482*/
cristyc3ebda22010-06-27 17:11:57 +0000483WandExport RectangleInfo GetWandViewExtent(const WandView *wand_view)
cristy3ed852e2009-09-05 21:47:34 +0000484{
cristy73b7d4c2010-06-27 00:31:00 +0000485 assert(wand_view != (WandView *) NULL);
486 assert(wand_view->signature == WandSignature);
cristyc3ebda22010-06-27 17:11:57 +0000487 return(wand_view->extent);
cristy3ed852e2009-09-05 21:47:34 +0000488}
489
490/*
491%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
492% %
493% %
494% %
cristy7eb1b7a2010-06-26 15:47:49 +0000495% 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 +0000496% %
497% %
498% %
499%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
500%
cristy73b7d4c2010-06-27 00:31:00 +0000501% GetWandViewIterator() iterates over the wand view in parallel and calls
cristyc3ebda22010-06-27 17:11:57 +0000502% your get method for each scanline of the view. The pixel extent is
cristy3ed852e2009-09-05 21:47:34 +0000503% not confined to the image canvas-- that is you can include negative offsets
504% or widths or heights that exceed the image dimension. Any updates to
505% the pixels in your callback are ignored.
506%
cristyd6dfc0d2010-06-27 19:30:49 +0000507% The callback signature is:
508%
509% MagickBooleanType GetImageViewMethod(const WandView *source,
510% const ssize_t y,const int thread_id,void *context)
511%
cristy58739472010-06-26 20:27:18 +0000512% Use this pragma if the view is not single threaded:
cristy3ed852e2009-09-05 21:47:34 +0000513%
514% #pragma omp critical
515%
516% to define a section of code in your callback get method that must be
517% executed by a single thread at a time.
518%
cristy7eb1b7a2010-06-26 15:47:49 +0000519% The format of the GetWandViewIterator method is:
cristy3ed852e2009-09-05 21:47:34 +0000520%
cristy7eb1b7a2010-06-26 15:47:49 +0000521% MagickBooleanType GetWandViewIterator(WandView *source,
522% GetWandViewMethod get,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000523%
524% A description of each parameter follows:
525%
cristy73b7d4c2010-06-27 00:31:00 +0000526% o source: the source wand view.
cristy3ed852e2009-09-05 21:47:34 +0000527%
528% o get: the get callback method.
529%
530% o context: the user defined context.
531%
532*/
cristy7eb1b7a2010-06-26 15:47:49 +0000533WandExport MagickBooleanType GetWandViewIterator(WandView *source,
534 GetWandViewMethod get,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000535{
cristy3ed852e2009-09-05 21:47:34 +0000536 Image
537 *source_image;
538
cristy3ed852e2009-09-05 21:47:34 +0000539 MagickBooleanType
540 status;
541
cristycee97112010-05-28 00:44:52 +0000542 MagickOffsetType
543 progress;
544
545 ssize_t
546 y;
547
cristy7eb1b7a2010-06-26 15:47:49 +0000548 assert(source != (WandView *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000549 assert(source->signature == WandSignature);
cristy7eb1b7a2010-06-26 15:47:49 +0000550 if (get == (GetWandViewMethod) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000551 return(MagickFalse);
552 source_image=source->wand->images;
553 status=MagickTrue;
554 progress=0;
cristyb5d5f722009-11-04 03:03:49 +0000555#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy09d81172010-10-21 16:15:05 +0000556 #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(source->number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000557#endif
cristyc3ebda22010-06-27 17:11:57 +0000558 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
cristy3ed852e2009-09-05 21:47:34 +0000559 {
cristy83e6d2a2010-09-17 17:35:13 +0000560 const int
561 id = GetOpenMPThreadId();
cristyad740052010-07-03 01:38:03 +0000562
cristy3ed852e2009-09-05 21:47:34 +0000563 register const IndexPacket
564 *indexes;
565
566 register const PixelPacket
567 *pixels;
568
cristybb503372010-05-27 20:51:26 +0000569 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000570 x;
571
572 if (status == MagickFalse)
573 continue;
cristyc3ebda22010-06-27 17:11:57 +0000574 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
575 source->extent.width,1,source->exception);
cristy3ed852e2009-09-05 21:47:34 +0000576 if (pixels == (const PixelPacket *) NULL)
577 {
578 status=MagickFalse;
579 continue;
580 }
581 indexes=GetCacheViewVirtualIndexQueue(source->view);
cristyc3ebda22010-06-27 17:11:57 +0000582 for (x=0; x < (ssize_t) source->extent.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000583 PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
584 if (source_image->colorspace == CMYKColorspace)
cristyc3ebda22010-06-27 17:11:57 +0000585 for (x=0; x < (ssize_t) source->extent.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000586 PixelSetBlackQuantum(source->pixel_wands[id][x],indexes[x]);
587 if (source_image->storage_class == PseudoClass)
cristyc3ebda22010-06-27 17:11:57 +0000588 for (x=0; x < (ssize_t) source->extent.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000589 PixelSetIndex(source->pixel_wands[id][x],indexes[x]);
cristyd6dfc0d2010-06-27 19:30:49 +0000590 if (get(source,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000591 status=MagickFalse;
592 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
593 {
594 MagickBooleanType
595 proceed;
596
cristyb5d5f722009-11-04 03:03:49 +0000597#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy7eb1b7a2010-06-26 15:47:49 +0000598 #pragma omp critical (MagickWand_GetWandViewIterator)
cristy3ed852e2009-09-05 21:47:34 +0000599#endif
cristyc3ebda22010-06-27 17:11:57 +0000600 proceed=SetImageProgress(source_image,source->description,progress++,
601 source->extent.height);
cristy3ed852e2009-09-05 21:47:34 +0000602 if (proceed == MagickFalse)
603 status=MagickFalse;
604 }
605 }
606 return(status);
607}
608
609/*
610%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
611% %
612% %
613% %
cristy7eb1b7a2010-06-26 15:47:49 +0000614% G e t W a n d V i e w P i x e l s %
cristy3ed852e2009-09-05 21:47:34 +0000615% %
616% %
617% %
618%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
619%
cristy73b7d4c2010-06-27 00:31:00 +0000620% GetWandViewPixels() returns the wand view pixel_wands.
cristy3ed852e2009-09-05 21:47:34 +0000621%
cristy7eb1b7a2010-06-26 15:47:49 +0000622% The format of the GetWandViewPixels method is:
cristy3ed852e2009-09-05 21:47:34 +0000623%
cristy73b7d4c2010-06-27 00:31:00 +0000624% PixelWand *GetWandViewPixels(const WandView *wand_view)
cristy3ed852e2009-09-05 21:47:34 +0000625%
626% A description of each parameter follows:
627%
cristy73b7d4c2010-06-27 00:31:00 +0000628% o wand_view: the wand view.
cristy3ed852e2009-09-05 21:47:34 +0000629%
630*/
cristy73b7d4c2010-06-27 00:31:00 +0000631WandExport PixelWand **GetWandViewPixels(const WandView *wand_view)
cristy3ed852e2009-09-05 21:47:34 +0000632{
cristy83e6d2a2010-09-17 17:35:13 +0000633 const int
634 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +0000635
cristy73b7d4c2010-06-27 00:31:00 +0000636 assert(wand_view != (WandView *) NULL);
637 assert(wand_view->signature == WandSignature);
cristy73b7d4c2010-06-27 00:31:00 +0000638 return(wand_view->pixel_wands[id]);
cristy3ed852e2009-09-05 21:47:34 +0000639}
640
641/*
642%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
643% %
644% %
645% %
cristy7eb1b7a2010-06-26 15:47:49 +0000646% G e t W a n d V i e w W a n d %
cristy3ed852e2009-09-05 21:47:34 +0000647% %
648% %
649% %
650%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
651%
cristy73b7d4c2010-06-27 00:31:00 +0000652% GetWandViewWand() returns the magick wand associated with the wand view.
cristy3ed852e2009-09-05 21:47:34 +0000653%
cristy7eb1b7a2010-06-26 15:47:49 +0000654% The format of the GetWandViewWand method is:
cristy3ed852e2009-09-05 21:47:34 +0000655%
cristy73b7d4c2010-06-27 00:31:00 +0000656% MagickWand *GetWandViewWand(const WandView *wand_view)
cristy3ed852e2009-09-05 21:47:34 +0000657%
658% A description of each parameter follows:
659%
cristy73b7d4c2010-06-27 00:31:00 +0000660% o wand_view: the wand view.
cristy3ed852e2009-09-05 21:47:34 +0000661%
662*/
cristy73b7d4c2010-06-27 00:31:00 +0000663WandExport MagickWand *GetWandViewWand(const WandView *wand_view)
cristy3ed852e2009-09-05 21:47:34 +0000664{
cristy73b7d4c2010-06-27 00:31:00 +0000665 assert(wand_view != (WandView *) NULL);
666 assert(wand_view->signature == WandSignature);
667 return(wand_view->wand);
cristy3ed852e2009-09-05 21:47:34 +0000668}
669
670/*
671%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
672% %
673% %
674% %
cristy7eb1b7a2010-06-26 15:47:49 +0000675% I s W a n d V i e w %
cristy3ed852e2009-09-05 21:47:34 +0000676% %
677% %
678% %
679%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
680%
cristy73b7d4c2010-06-27 00:31:00 +0000681% IsWandView() returns MagickTrue if the the parameter is verified as a wand
682% view object.
cristy3ed852e2009-09-05 21:47:34 +0000683%
cristy7eb1b7a2010-06-26 15:47:49 +0000684% The format of the IsWandView method is:
cristy3ed852e2009-09-05 21:47:34 +0000685%
cristy73b7d4c2010-06-27 00:31:00 +0000686% MagickBooleanType IsWandView(const WandView *wand_view)
cristy3ed852e2009-09-05 21:47:34 +0000687%
688% A description of each parameter follows:
689%
cristy73b7d4c2010-06-27 00:31:00 +0000690% o wand_view: the wand view.
cristy3ed852e2009-09-05 21:47:34 +0000691%
692*/
cristy73b7d4c2010-06-27 00:31:00 +0000693WandExport MagickBooleanType IsWandView(const WandView *wand_view)
cristy3ed852e2009-09-05 21:47:34 +0000694{
695 size_t
696 length;
697
cristy73b7d4c2010-06-27 00:31:00 +0000698 if (wand_view == (const WandView *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000699 return(MagickFalse);
cristy73b7d4c2010-06-27 00:31:00 +0000700 if (wand_view->signature != WandSignature)
cristy3ed852e2009-09-05 21:47:34 +0000701 return(MagickFalse);
cristy7eb1b7a2010-06-26 15:47:49 +0000702 length=strlen(WandViewId);
cristy73b7d4c2010-06-27 00:31:00 +0000703 if (LocaleNCompare(wand_view->name,WandViewId,length) != 0)
cristy3ed852e2009-09-05 21:47:34 +0000704 return(MagickFalse);
705 return(MagickTrue);
706}
707
708/*
709%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
710% %
711% %
712% %
cristy7eb1b7a2010-06-26 15:47:49 +0000713% N e w W a n d V i e w %
cristy3ed852e2009-09-05 21:47:34 +0000714% %
715% %
716% %
717%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
718%
cristy73b7d4c2010-06-27 00:31:00 +0000719% NewWandView() returns a wand view required for all other methods in the
720% Wand View API.
cristy3ed852e2009-09-05 21:47:34 +0000721%
cristy7eb1b7a2010-06-26 15:47:49 +0000722% The format of the NewWandView method is:
cristy3ed852e2009-09-05 21:47:34 +0000723%
cristy7eb1b7a2010-06-26 15:47:49 +0000724% WandView *NewWandView(MagickWand *wand)
cristy3ed852e2009-09-05 21:47:34 +0000725%
726% A description of each parameter follows:
727%
728% o wand: the wand.
729%
730*/
731
cristybb503372010-05-27 20:51:26 +0000732static PixelWand ***AcquirePixelsThreadSet(const size_t number_wands,
733 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000734{
735 PixelWand
736 ***pixel_wands;
737
cristybb503372010-05-27 20:51:26 +0000738 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000739 i;
740
cristyb41ee102010-10-04 16:46:15 +0000741 pixel_wands=(PixelWand ***) AcquireQuantumMemory(number_threads,
cristy3ed852e2009-09-05 21:47:34 +0000742 sizeof(*pixel_wands));
743 if (pixel_wands == (PixelWand ***) NULL)
744 return((PixelWand ***) NULL);
745 (void) ResetMagickMemory(pixel_wands,0,number_threads*sizeof(*pixel_wands));
cristybb503372010-05-27 20:51:26 +0000746 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000747 {
748 pixel_wands[i]=NewPixelWands(number_wands);
749 if (pixel_wands[i] == (PixelWand **) NULL)
750 return(DestroyPixelsThreadSet(pixel_wands,number_wands,number_threads));
751 }
752 return(pixel_wands);
753}
754
cristy7eb1b7a2010-06-26 15:47:49 +0000755WandExport WandView *NewWandView(MagickWand *wand)
cristy3ed852e2009-09-05 21:47:34 +0000756{
cristy7eb1b7a2010-06-26 15:47:49 +0000757 WandView
cristy73b7d4c2010-06-27 00:31:00 +0000758 *wand_view;
cristy3ed852e2009-09-05 21:47:34 +0000759
760 assert(wand != (MagickWand *) NULL);
cristyc3ebda22010-06-27 17:11:57 +0000761 assert(wand->signature == WandSignature);
cristy73bd4a52010-10-05 11:24:23 +0000762 wand_view=(WandView *) AcquireMagickMemory(sizeof(*wand_view));
cristy73b7d4c2010-06-27 00:31:00 +0000763 if (wand_view == (WandView *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000764 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
765 GetExceptionMessage(errno));
cristy73b7d4c2010-06-27 00:31:00 +0000766 (void) ResetMagickMemory(wand_view,0,sizeof(*wand_view));
767 wand_view->id=AcquireWandId();
768 (void) FormatMagickString(wand_view->name,MaxTextExtent,"%s-%.20g",
769 WandViewId,(double) wand_view->id);
cristyc3ebda22010-06-27 17:11:57 +0000770 wand_view->description=ConstantString("WandView");
cristy73b7d4c2010-06-27 00:31:00 +0000771 wand_view->wand=wand;
772 wand_view->view=AcquireCacheView(wand_view->wand->images);
cristyc3ebda22010-06-27 17:11:57 +0000773 wand_view->extent.width=wand->images->columns;
774 wand_view->extent.height=wand->images->rows;
cristy73b7d4c2010-06-27 00:31:00 +0000775 wand_view->number_threads=GetOpenMPMaximumThreads();
cristyc3ebda22010-06-27 17:11:57 +0000776 wand_view->pixel_wands=AcquirePixelsThreadSet(wand_view->extent.width,
777 wand_view->number_threads);
778 wand_view->exception=AcquireExceptionInfo();
779 if (wand_view->pixel_wands == (PixelWand ***) NULL)
780 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
781 GetExceptionMessage(errno));
782 wand_view->debug=IsEventLogging();
783 wand_view->signature=WandSignature;
784 return(wand_view);
785}
786
787/*
788%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
789% %
790% %
791% %
792% N e w W a n d V i e w E x t e n t %
793% %
794% %
795% %
796%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
797%
798% NewWandViewExtent() returns a wand view required for all other methods
799% in the Wand View API.
800%
801% The format of the NewWandViewExtent method is:
802%
803% WandView *NewWandViewExtent(MagickWand *wand,const ssize_t x,
804% const ssize_t y,const size_t width,const size_t height)
805%
806% A description of each parameter follows:
807%
808% o wand: the magick wand.
809%
810% o x,y,columns,rows: These values define the perimeter of a extent of
811% pixel_wands view.
812%
813*/
814WandExport WandView *NewWandViewExtent(MagickWand *wand,const ssize_t x,
815 const ssize_t y,const size_t width,const size_t height)
816{
817 WandView
818 *wand_view;
819
820 assert(wand != (MagickWand *) NULL);
821 assert(wand->signature == WandSignature);
cristy73bd4a52010-10-05 11:24:23 +0000822 wand_view=(WandView *) AcquireMagickMemory(sizeof(*wand_view));
cristyc3ebda22010-06-27 17:11:57 +0000823 if (wand_view == (WandView *) NULL)
824 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
825 GetExceptionMessage(errno));
826 (void) ResetMagickMemory(wand_view,0,sizeof(*wand_view));
827 wand_view->id=AcquireWandId();
828 (void) FormatMagickString(wand_view->name,MaxTextExtent,"%s-%.20g",
829 WandViewId,(double) wand_view->id);
830 wand_view->description=ConstantString("WandView");
831 wand_view->view=AcquireCacheView(wand_view->wand->images);
832 wand_view->wand=wand;
833 wand_view->extent.width=width;
834 wand_view->extent.height=height;
835 wand_view->extent.x=x;
836 wand_view->extent.y=y;
837 wand_view->number_threads=GetOpenMPMaximumThreads();
838 wand_view->exception=AcquireExceptionInfo();
839 wand_view->pixel_wands=AcquirePixelsThreadSet(wand_view->extent.width,
cristy73b7d4c2010-06-27 00:31:00 +0000840 wand_view->number_threads);
841 if (wand_view->pixel_wands == (PixelWand ***) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000842 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
843 GetExceptionMessage(errno));
cristy73b7d4c2010-06-27 00:31:00 +0000844 wand_view->debug=IsEventLogging();
845 wand_view->signature=WandSignature;
846 return(wand_view);
cristy3ed852e2009-09-05 21:47:34 +0000847}
848
849/*
850%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
851% %
852% %
853% %
cristyc3ebda22010-06-27 17:11:57 +0000854% 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 +0000855% %
856% %
857% %
858%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
859%
cristyc3ebda22010-06-27 17:11:57 +0000860% SetWandViewDescription() associates a description with an image view.
cristy3ed852e2009-09-05 21:47:34 +0000861%
cristyc3ebda22010-06-27 17:11:57 +0000862% The format of the SetWandViewDescription method is:
cristy3ed852e2009-09-05 21:47:34 +0000863%
cristyc3ebda22010-06-27 17:11:57 +0000864% void SetWandViewDescription(WandView *image_view,const char *description)
cristy3ed852e2009-09-05 21:47:34 +0000865%
866% A description of each parameter follows:
867%
cristyc3ebda22010-06-27 17:11:57 +0000868% o wand_view: the wand view.
cristy3ed852e2009-09-05 21:47:34 +0000869%
cristyc3ebda22010-06-27 17:11:57 +0000870% o description: the wand view description.
cristy3ed852e2009-09-05 21:47:34 +0000871%
872*/
cristyc3ebda22010-06-27 17:11:57 +0000873MagickExport void SetWandViewDescription(WandView *wand_view,
874 const char *description)
cristy3ed852e2009-09-05 21:47:34 +0000875{
cristyc3ebda22010-06-27 17:11:57 +0000876 assert(wand_view != (WandView *) NULL);
877 assert(wand_view->signature == WandSignature);
878 wand_view->description=ConstantString(description);
cristy3ed852e2009-09-05 21:47:34 +0000879}
880
881/*
882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
883% %
884% %
885% %
cristy7eb1b7a2010-06-26 15:47:49 +0000886% 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 +0000887% %
888% %
889% %
890%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
891%
cristy73b7d4c2010-06-27 00:31:00 +0000892% SetWandViewIterator() iterates over the wand view in parallel and calls
cristyc3ebda22010-06-27 17:11:57 +0000893% your set method for each scanline of the view. The pixel extent is
cristy3ed852e2009-09-05 21:47:34 +0000894% confined to the image canvas-- that is no negative offsets or widths or
895% heights that exceed the image dimension. The pixels are initiallly
896% undefined and any settings you make in the callback method are automagically
897% synced back to your image.
898%
cristyd6dfc0d2010-06-27 19:30:49 +0000899% The callback signature is:
900%
901% MagickBooleanType SetImageViewMethod(ImageView *destination,
902% const ssize_t y,const int thread_id,void *context)
903%
cristy58739472010-06-26 20:27:18 +0000904% Use this pragma if the view is not single threaded:
cristy3ed852e2009-09-05 21:47:34 +0000905%
906% #pragma omp critical
907%
908% to define a section of code in your callback set method that must be
909% executed by a single thread at a time.
910%
cristy7eb1b7a2010-06-26 15:47:49 +0000911% The format of the SetWandViewIterator method is:
cristy3ed852e2009-09-05 21:47:34 +0000912%
cristy7eb1b7a2010-06-26 15:47:49 +0000913% MagickBooleanType SetWandViewIterator(WandView *destination,
914% SetWandViewMethod set,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000915%
916% A description of each parameter follows:
917%
cristy73b7d4c2010-06-27 00:31:00 +0000918% o destination: the wand view.
cristy3ed852e2009-09-05 21:47:34 +0000919%
920% o set: the set callback method.
921%
922% o context: the user defined context.
923%
924*/
cristy7eb1b7a2010-06-26 15:47:49 +0000925WandExport MagickBooleanType SetWandViewIterator(WandView *destination,
926 SetWandViewMethod set,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000927{
cristy3ed852e2009-09-05 21:47:34 +0000928 ExceptionInfo
929 *exception;
930
931 Image
932 *destination_image;
933
cristy3ed852e2009-09-05 21:47:34 +0000934 MagickBooleanType
935 status;
936
cristycee97112010-05-28 00:44:52 +0000937 MagickOffsetType
938 progress;
939
940 ssize_t
941 y;
942
cristy7eb1b7a2010-06-26 15:47:49 +0000943 assert(destination != (WandView *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000944 assert(destination->signature == WandSignature);
cristy7eb1b7a2010-06-26 15:47:49 +0000945 if (set == (SetWandViewMethod) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000946 return(MagickFalse);
947 destination_image=destination->wand->images;
948 if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
949 return(MagickFalse);
950 status=MagickTrue;
951 progress=0;
952 exception=destination->exception;
cristyb5d5f722009-11-04 03:03:49 +0000953#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy09d81172010-10-21 16:15:05 +0000954 #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(destination->number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000955#endif
cristyc3ebda22010-06-27 17:11:57 +0000956 for (y=destination->extent.y; y < (ssize_t) destination->extent.height; y++)
cristy3ed852e2009-09-05 21:47:34 +0000957 {
cristy83e6d2a2010-09-17 17:35:13 +0000958 const int
959 id = GetOpenMPThreadId();
cristyad740052010-07-03 01:38:03 +0000960
cristy3ed852e2009-09-05 21:47:34 +0000961 MagickBooleanType
962 sync;
963
964 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000965 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +0000966
cristybb503372010-05-27 20:51:26 +0000967 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000968 x;
969
970 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000971 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000972
973 if (status == MagickFalse)
974 continue;
cristyc3ebda22010-06-27 17:11:57 +0000975 pixels=GetCacheViewAuthenticPixels(destination->view,destination->extent.x,
976 y,destination->extent.width,1,exception);
cristy3ed852e2009-09-05 21:47:34 +0000977 if (pixels == (PixelPacket *) NULL)
978 {
979 InheritException(destination->exception,GetCacheViewException(
980 destination->view));
981 status=MagickFalse;
982 continue;
983 }
984 indexes=GetCacheViewAuthenticIndexQueue(destination->view);
cristyd6dfc0d2010-06-27 19:30:49 +0000985 if (set(destination,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000986 status=MagickFalse;
cristyc3ebda22010-06-27 17:11:57 +0000987 for (x=0; x < (ssize_t) destination->extent.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000988 PixelGetQuantumColor(destination->pixel_wands[id][x],pixels+x);
989 if (destination_image->colorspace == CMYKColorspace)
cristyc3ebda22010-06-27 17:11:57 +0000990 for (x=0; x < (ssize_t) destination->extent.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000991 indexes[x]=PixelGetBlackQuantum(destination->pixel_wands[id][x]);
992 sync=SyncCacheViewAuthenticPixels(destination->view,exception);
993 if (sync == MagickFalse)
994 {
995 InheritException(destination->exception,GetCacheViewException(
996 destination->view));
997 status=MagickFalse;
998 }
999 if (destination_image->progress_monitor != (MagickProgressMonitor) NULL)
1000 {
1001 MagickBooleanType
1002 proceed;
1003
cristyb5d5f722009-11-04 03:03:49 +00001004#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy7eb1b7a2010-06-26 15:47:49 +00001005 #pragma omp critical (MagickWand_SetWandViewIterator)
cristy3ed852e2009-09-05 21:47:34 +00001006#endif
cristyc3ebda22010-06-27 17:11:57 +00001007 proceed=SetImageProgress(destination_image,destination->description,
1008 progress++,destination->extent.height);
cristy3ed852e2009-09-05 21:47:34 +00001009 if (proceed == MagickFalse)
1010 status=MagickFalse;
1011 }
1012 }
1013 return(status);
1014}
1015
1016/*
1017%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1018% %
1019% %
1020% %
cristy09d81172010-10-21 16:15:05 +00001021% S e t W a n d V i e w T h r e a d s %
1022% %
1023% %
1024% %
1025%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1026%
1027% SetWandViewThreads() sets the number of threads in a thread team.
1028%
1029% The format of the SetWandViewDescription method is:
1030%
1031% void SetWandViewThreads(WandView *image_view,
1032% const size_t number_threads)
1033%
1034% A description of each parameter follows:
1035%
1036% o image_view: the image view.
1037%
1038% o number_threads: the number of threads in a thread team.
1039%
1040*/
1041MagickExport void SetWandViewThreads(WandView *image_view,
1042 const size_t number_threads)
1043{
1044 assert(image_view != (WandView *) NULL);
1045 assert(image_view->signature == MagickSignature);
1046 image_view->number_threads=number_threads;
1047 if (number_threads > GetOpenMPMaximumThreads())
1048 image_view->number_threads=GetOpenMPMaximumThreads();
1049}
1050
1051/*
1052%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1053% %
1054% %
1055% %
cristy7eb1b7a2010-06-26 15:47:49 +00001056% 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 +00001057% %
1058% %
1059% %
1060%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1061%
cristy73b7d4c2010-06-27 00:31:00 +00001062% TransferWandViewIterator() iterates over two wand views in parallel and
cristy3ed852e2009-09-05 21:47:34 +00001063% calls your transfer method for each scanline of the view. The source pixel
cristyc3ebda22010-06-27 17:11:57 +00001064% extent is not confined to the image canvas-- that is you can include
cristy3ed852e2009-09-05 21:47:34 +00001065% negative offsets or widths or heights that exceed the image dimension.
cristy73b7d4c2010-06-27 00:31:00 +00001066% However, the destination wand view is confined to the image canvas-- that
cristy3ed852e2009-09-05 21:47:34 +00001067% is no negative offsets or widths or heights that exceed the image dimension
1068% are permitted.
1069%
cristyd6dfc0d2010-06-27 19:30:49 +00001070% The callback signature is:
1071%
1072% MagickBooleanType TransferImageViewMethod(const WandView *source,
1073% WandView *destination,const ssize_t y,const int thread_id,
1074% void *context)
1075%
cristy58739472010-06-26 20:27:18 +00001076% Use this pragma if the view is not single threaded:
cristy3ed852e2009-09-05 21:47:34 +00001077%
1078% #pragma omp critical
1079%
1080% to define a section of code in your callback transfer method that must be
1081% executed by a single thread at a time.
1082%
cristy7eb1b7a2010-06-26 15:47:49 +00001083% The format of the TransferWandViewIterator method is:
cristy3ed852e2009-09-05 21:47:34 +00001084%
cristy7eb1b7a2010-06-26 15:47:49 +00001085% MagickBooleanType TransferWandViewIterator(WandView *source,
1086% WandView *destination,TransferWandViewMethod transfer,void *context)
cristy3ed852e2009-09-05 21:47:34 +00001087%
1088% A description of each parameter follows:
1089%
cristy73b7d4c2010-06-27 00:31:00 +00001090% o source: the source wand view.
cristy3ed852e2009-09-05 21:47:34 +00001091%
cristy73b7d4c2010-06-27 00:31:00 +00001092% o destination: the destination wand view.
cristy3ed852e2009-09-05 21:47:34 +00001093%
1094% o transfer: the transfer callback method.
1095%
1096% o context: the user defined context.
1097%
1098*/
cristy7eb1b7a2010-06-26 15:47:49 +00001099WandExport MagickBooleanType TransferWandViewIterator(WandView *source,
1100 WandView *destination,TransferWandViewMethod transfer,void *context)
cristy3ed852e2009-09-05 21:47:34 +00001101{
cristy3ed852e2009-09-05 21:47:34 +00001102 ExceptionInfo
1103 *exception;
1104
1105 Image
1106 *destination_image,
1107 *source_image;
1108
cristy3ed852e2009-09-05 21:47:34 +00001109 MagickBooleanType
1110 status;
1111
cristycee97112010-05-28 00:44:52 +00001112 MagickOffsetType
1113 progress;
1114
1115 ssize_t
1116 y;
1117
cristy7eb1b7a2010-06-26 15:47:49 +00001118 assert(source != (WandView *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001119 assert(source->signature == WandSignature);
cristy7eb1b7a2010-06-26 15:47:49 +00001120 if (transfer == (TransferWandViewMethod) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001121 return(MagickFalse);
1122 source_image=source->wand->images;
1123 destination_image=destination->wand->images;
1124 if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
1125 return(MagickFalse);
1126 status=MagickTrue;
1127 progress=0;
1128 exception=destination->exception;
cristyb5d5f722009-11-04 03:03:49 +00001129#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy09d81172010-10-21 16:15:05 +00001130 #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(source->number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001131#endif
cristyc3ebda22010-06-27 17:11:57 +00001132 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
cristy3ed852e2009-09-05 21:47:34 +00001133 {
cristy83e6d2a2010-09-17 17:35:13 +00001134 const int
1135 id = GetOpenMPThreadId();
cristyad740052010-07-03 01:38:03 +00001136
cristy3ed852e2009-09-05 21:47:34 +00001137 MagickBooleanType
1138 sync;
1139
1140 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00001141 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00001142
1143 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001144 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001145
1146 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00001147 *restrict destination_indexes;
cristy3ed852e2009-09-05 21:47:34 +00001148
cristybb503372010-05-27 20:51:26 +00001149 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001150 x;
1151
1152 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001153 *restrict destination_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001154
1155 if (status == MagickFalse)
1156 continue;
cristyc3ebda22010-06-27 17:11:57 +00001157 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
1158 source->extent.width,1,source->exception);
cristy3ed852e2009-09-05 21:47:34 +00001159 if (pixels == (const PixelPacket *) NULL)
1160 {
1161 status=MagickFalse;
1162 continue;
1163 }
1164 indexes=GetCacheViewVirtualIndexQueue(source->view);
cristyc3ebda22010-06-27 17:11:57 +00001165 for (x=0; x < (ssize_t) source->extent.width; x++)
cristy3ed852e2009-09-05 21:47:34 +00001166 PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
1167 if (source_image->colorspace == CMYKColorspace)
cristyc3ebda22010-06-27 17:11:57 +00001168 for (x=0; x < (ssize_t) source->extent.width; x++)
cristy3ed852e2009-09-05 21:47:34 +00001169 PixelSetBlackQuantum(source->pixel_wands[id][x],indexes[x]);
1170 if (source_image->storage_class == PseudoClass)
cristyc3ebda22010-06-27 17:11:57 +00001171 for (x=0; x < (ssize_t) source->extent.width; x++)
cristy3ed852e2009-09-05 21:47:34 +00001172 PixelSetIndex(source->pixel_wands[id][x],indexes[x]);
1173 destination_pixels=GetCacheViewAuthenticPixels(destination->view,
cristyc3ebda22010-06-27 17:11:57 +00001174 destination->extent.x,y,destination->extent.width,1,exception);
cristy3ed852e2009-09-05 21:47:34 +00001175 if (destination_pixels == (PixelPacket *) NULL)
1176 {
1177 status=MagickFalse;
1178 continue;
1179 }
1180 destination_indexes=GetCacheViewAuthenticIndexQueue(destination->view);
cristyc3ebda22010-06-27 17:11:57 +00001181 for (x=0; x < (ssize_t) destination->extent.width; x++)
cristy3ed852e2009-09-05 21:47:34 +00001182 PixelSetQuantumColor(destination->pixel_wands[id][x],pixels+x);
1183 if (destination_image->colorspace == CMYKColorspace)
cristyc3ebda22010-06-27 17:11:57 +00001184 for (x=0; x < (ssize_t) destination->extent.width; x++)
cristy3ed852e2009-09-05 21:47:34 +00001185 PixelSetBlackQuantum(destination->pixel_wands[id][x],indexes[x]);
1186 if (destination_image->storage_class == PseudoClass)
cristyc3ebda22010-06-27 17:11:57 +00001187 for (x=0; x < (ssize_t) destination->extent.width; x++)
cristy3ed852e2009-09-05 21:47:34 +00001188 PixelSetIndex(destination->pixel_wands[id][x],indexes[x]);
cristyc3ebda22010-06-27 17:11:57 +00001189 if (transfer(source,destination,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001190 status=MagickFalse;
cristyc3ebda22010-06-27 17:11:57 +00001191 for (x=0; x < (ssize_t) destination->extent.width; x++)
cristy3ed852e2009-09-05 21:47:34 +00001192 PixelGetQuantumColor(destination->pixel_wands[id][x],
1193 destination_pixels+x);
1194 if (destination_image->colorspace == CMYKColorspace)
cristyc3ebda22010-06-27 17:11:57 +00001195 for (x=0; x < (ssize_t) destination->extent.width; x++)
cristy3ed852e2009-09-05 21:47:34 +00001196 destination_indexes[x]=PixelGetBlackQuantum(
1197 destination->pixel_wands[id][x]);
1198 sync=SyncCacheViewAuthenticPixels(destination->view,exception);
1199 if (sync == MagickFalse)
1200 {
1201 InheritException(destination->exception,GetCacheViewException(
1202 source->view));
1203 status=MagickFalse;
1204 }
1205 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1206 {
1207 MagickBooleanType
1208 proceed;
1209
cristyb5d5f722009-11-04 03:03:49 +00001210#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy7eb1b7a2010-06-26 15:47:49 +00001211 #pragma omp critical (MagickWand_TransferWandViewIterator)
cristy3ed852e2009-09-05 21:47:34 +00001212#endif
cristyc3ebda22010-06-27 17:11:57 +00001213 proceed=SetImageProgress(source_image,source->description,progress++,
1214 source->extent.height);
cristy3ed852e2009-09-05 21:47:34 +00001215 if (proceed == MagickFalse)
1216 status=MagickFalse;
1217 }
1218 }
1219 return(status);
1220}
1221
1222/*
1223%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1224% %
1225% %
1226% %
cristy7eb1b7a2010-06-26 15:47:49 +00001227% 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 +00001228% %
1229% %
1230% %
1231%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1232%
cristy73b7d4c2010-06-27 00:31:00 +00001233% UpdateWandViewIterator() iterates over the wand view in parallel and calls
cristyc3ebda22010-06-27 17:11:57 +00001234% your update method for each scanline of the view. The pixel extent is
cristy3ed852e2009-09-05 21:47:34 +00001235% confined to the image canvas-- that is no negative offsets or widths or
1236% heights that exceed the image dimension are permitted. Updates to pixels
1237% in your callback are automagically synced back to the image.
1238%
cristyd6dfc0d2010-06-27 19:30:49 +00001239% The callback signature is:
1240%
1241% MagickBooleanType UpdateImageViewMethod(WandView *source,const ssize_t y,
1242% const int thread_id,void *context)
1243%
cristy58739472010-06-26 20:27:18 +00001244% Use this pragma if the view is not single threaded:
cristy3ed852e2009-09-05 21:47:34 +00001245%
1246% #pragma omp critical
1247%
1248% to define a section of code in your callback update method that must be
1249% executed by a single thread at a time.
1250%
cristy7eb1b7a2010-06-26 15:47:49 +00001251% The format of the UpdateWandViewIterator method is:
cristy3ed852e2009-09-05 21:47:34 +00001252%
cristy7eb1b7a2010-06-26 15:47:49 +00001253% MagickBooleanType UpdateWandViewIterator(WandView *source,
1254% UpdateWandViewMethod update,void *context)
cristy3ed852e2009-09-05 21:47:34 +00001255%
1256% A description of each parameter follows:
1257%
cristy73b7d4c2010-06-27 00:31:00 +00001258% o source: the source wand view.
cristy3ed852e2009-09-05 21:47:34 +00001259%
1260% o update: the update callback method.
1261%
1262% o context: the user defined context.
1263%
1264*/
cristy7eb1b7a2010-06-26 15:47:49 +00001265WandExport MagickBooleanType UpdateWandViewIterator(WandView *source,
1266 UpdateWandViewMethod update,void *context)
cristy3ed852e2009-09-05 21:47:34 +00001267{
cristy3ed852e2009-09-05 21:47:34 +00001268 ExceptionInfo
1269 *exception;
1270
1271 Image
1272 *source_image;
1273
cristy3ed852e2009-09-05 21:47:34 +00001274 MagickBooleanType
1275 status;
1276
cristycee97112010-05-28 00:44:52 +00001277 MagickOffsetType
1278 progress;
1279
1280 ssize_t
1281 y;
1282
cristy7eb1b7a2010-06-26 15:47:49 +00001283 assert(source != (WandView *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001284 assert(source->signature == WandSignature);
cristy7eb1b7a2010-06-26 15:47:49 +00001285 if (update == (UpdateWandViewMethod) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001286 return(MagickFalse);
1287 source_image=source->wand->images;
1288 if (SetImageStorageClass(source_image,DirectClass) == MagickFalse)
1289 return(MagickFalse);
1290 status=MagickTrue;
1291 progress=0;
1292 exception=source->exception;
cristyb5d5f722009-11-04 03:03:49 +00001293#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy09d81172010-10-21 16:15:05 +00001294 #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(source->number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001295#endif
cristyc3ebda22010-06-27 17:11:57 +00001296 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
cristy3ed852e2009-09-05 21:47:34 +00001297 {
cristy83e6d2a2010-09-17 17:35:13 +00001298 const int
1299 id = GetOpenMPThreadId();
cristyad740052010-07-03 01:38:03 +00001300
cristy3ed852e2009-09-05 21:47:34 +00001301 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00001302 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00001303
cristybb503372010-05-27 20:51:26 +00001304 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001305 x;
1306
1307 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001308 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001309
1310 if (status == MagickFalse)
1311 continue;
cristyc3ebda22010-06-27 17:11:57 +00001312 pixels=GetCacheViewAuthenticPixels(source->view,source->extent.x,y,
1313 source->extent.width,1,exception);
cristy3ed852e2009-09-05 21:47:34 +00001314 if (pixels == (PixelPacket *) NULL)
1315 {
1316 InheritException(source->exception,GetCacheViewException(
1317 source->view));
1318 status=MagickFalse;
1319 continue;
1320 }
1321 indexes=GetCacheViewAuthenticIndexQueue(source->view);
cristyc3ebda22010-06-27 17:11:57 +00001322 for (x=0; x < (ssize_t) source->extent.width; x++)
cristy3ed852e2009-09-05 21:47:34 +00001323 PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
1324 if (source_image->colorspace == CMYKColorspace)
cristyc3ebda22010-06-27 17:11:57 +00001325 for (x=0; x < (ssize_t) source->extent.width; x++)
cristy3ed852e2009-09-05 21:47:34 +00001326 PixelSetBlackQuantum(source->pixel_wands[id][x],indexes[x]);
cristyc3ebda22010-06-27 17:11:57 +00001327 if (update(source,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001328 status=MagickFalse;
cristyc3ebda22010-06-27 17:11:57 +00001329 for (x=0; x < (ssize_t) source->extent.width; x++)
cristy3ed852e2009-09-05 21:47:34 +00001330 PixelGetQuantumColor(source->pixel_wands[id][x],pixels+x);
1331 if (source_image->colorspace == CMYKColorspace)
cristyc3ebda22010-06-27 17:11:57 +00001332 for (x=0; x < (ssize_t) source->extent.width; x++)
cristy3ed852e2009-09-05 21:47:34 +00001333 indexes[x]=PixelGetBlackQuantum(source->pixel_wands[id][x]);
1334 if (SyncCacheViewAuthenticPixels(source->view,exception) == MagickFalse)
1335 {
1336 InheritException(source->exception,GetCacheViewException(source->view));
1337 status=MagickFalse;
1338 }
1339 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1340 {
1341 MagickBooleanType
1342 proceed;
1343
cristyb5d5f722009-11-04 03:03:49 +00001344#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy7eb1b7a2010-06-26 15:47:49 +00001345 #pragma omp critical (MagickWand_UpdateWandViewIterator)
cristy3ed852e2009-09-05 21:47:34 +00001346#endif
cristyc3ebda22010-06-27 17:11:57 +00001347 proceed=SetImageProgress(source_image,source->description,progress++,
1348 source->extent.height);
cristy3ed852e2009-09-05 21:47:34 +00001349 if (proceed == MagickFalse)
1350 status=MagickFalse;
1351 }
1352 }
1353 return(status);
1354}