blob: 7553ad8fd758bf12854cfdef0f16867f33161d61 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
cristy7eb1b7a2010-06-26 15:47:49 +00005% IIIII M M AAA GGGG EEEEE %
6% I MM MM A A G E %
7% I M M M AAAAA G GG EEE %
8% I M M A A G G E %
9% IIIII M M A A GGGG EEEEE %
cristy3ed852e2009-09-05 21:47:34 +000010% %
cristycc34c492010-06-26 23:49:12 +000011% 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 %
cristy3ed852e2009-09-05 21:47:34 +000016% %
17% %
cristy7eb1b7a2010-06-26 15:47:49 +000018% MagickCore Image View Methods %
cristy3ed852e2009-09-05 21:47:34 +000019% %
20% Software Design %
21% John Cristy %
22% March 2003 %
23% %
24% %
cristy16af1cb2009-12-11 21:38:29 +000025% Copyright 1999-2010 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*/
cristy7eb1b7a2010-06-26 15:47:49 +000048#include "magick/studio.h"
49#include "magick/MagickCore.h"
50#include "magick/exception-private.h"
cristy3ed852e2009-09-05 21:47:34 +000051#include "magick/monitor-private.h"
52#include "magick/thread-private.h"
cristy3ed852e2009-09-05 21:47:34 +000053
54/*
55 Typedef declarations.
56*/
cristy7eb1b7a2010-06-26 15:47:49 +000057struct _ImageView
cristy3ed852e2009-09-05 21:47:34 +000058{
cristyc3ebda22010-06-27 17:11:57 +000059 char
60 *description;
61
62 RectangleInfo
63 extent;
cristy3ed852e2009-09-05 21:47:34 +000064
cristy7eb1b7a2010-06-26 15:47:49 +000065 Image
66 *image;
cristy3ed852e2009-09-05 21:47:34 +000067
68 CacheView
69 *view;
70
cristybb503372010-05-27 20:51:26 +000071 size_t
cristy3ed852e2009-09-05 21:47:34 +000072 number_threads;
73
cristyc3ebda22010-06-27 17:11:57 +000074 ExceptionInfo
75 *exception;
76
cristy3ed852e2009-09-05 21:47:34 +000077 MagickBooleanType
78 debug;
79
cristybb503372010-05-27 20:51:26 +000080 size_t
cristy3ed852e2009-09-05 21:47:34 +000081 signature;
82};
83
84/*
85%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
86% %
87% %
88% %
cristy7eb1b7a2010-06-26 15:47:49 +000089% C l o n e I m a g e V i e w %
cristy3ed852e2009-09-05 21:47:34 +000090% %
91% %
92% %
93%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
94%
cristy73b7d4c2010-06-27 00:31:00 +000095% CloneImageView() makes a copy of the specified image view.
cristy3ed852e2009-09-05 21:47:34 +000096%
cristy7eb1b7a2010-06-26 15:47:49 +000097% The format of the CloneImageView method is:
cristy3ed852e2009-09-05 21:47:34 +000098%
cristy73b7d4c2010-06-27 00:31:00 +000099% ImageView *CloneImageView(const ImageView *image_view)
cristy3ed852e2009-09-05 21:47:34 +0000100%
101% A description of each parameter follows:
102%
cristy73b7d4c2010-06-27 00:31:00 +0000103% o image_view: the image view.
cristy3ed852e2009-09-05 21:47:34 +0000104%
105*/
cristy73b7d4c2010-06-27 00:31:00 +0000106MagickExport ImageView *CloneImageView(const ImageView *image_view)
cristy3ed852e2009-09-05 21:47:34 +0000107{
cristy7eb1b7a2010-06-26 15:47:49 +0000108 ImageView
cristy3ed852e2009-09-05 21:47:34 +0000109 *clone_view;
110
cristy73b7d4c2010-06-27 00:31:00 +0000111 assert(image_view != (ImageView *) NULL);
112 assert(image_view->signature == MagickSignature);
cristy73bd4a52010-10-05 11:24:23 +0000113 clone_view=(ImageView *) AcquireMagickMemory(sizeof(*clone_view));
cristy7eb1b7a2010-06-26 15:47:49 +0000114 if (clone_view == (ImageView *) NULL)
115 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000116 (void) ResetMagickMemory(clone_view,0,sizeof(*clone_view));
cristyc3ebda22010-06-27 17:11:57 +0000117 clone_view->description=ConstantString(image_view->description);
118 clone_view->extent=image_view->extent;
119 clone_view->view=CloneCacheView(image_view->view);
120 clone_view->number_threads=image_view->number_threads;
cristy3ed852e2009-09-05 21:47:34 +0000121 clone_view->exception=AcquireExceptionInfo();
cristy73b7d4c2010-06-27 00:31:00 +0000122 InheritException(clone_view->exception,image_view->exception);
cristy73b7d4c2010-06-27 00:31:00 +0000123 clone_view->debug=image_view->debug;
cristy7eb1b7a2010-06-26 15:47:49 +0000124 clone_view->signature=MagickSignature;
cristy3ed852e2009-09-05 21:47:34 +0000125 return(clone_view);
126}
127
128/*
129%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
130% %
131% %
132% %
cristy7eb1b7a2010-06-26 15:47:49 +0000133% D e s t r o y I m a g e V i e w %
cristy3ed852e2009-09-05 21:47:34 +0000134% %
135% %
136% %
137%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
138%
cristy73b7d4c2010-06-27 00:31:00 +0000139% DestroyImageView() deallocates memory associated with a image view.
cristy3ed852e2009-09-05 21:47:34 +0000140%
cristy7eb1b7a2010-06-26 15:47:49 +0000141% The format of the DestroyImageView method is:
cristy3ed852e2009-09-05 21:47:34 +0000142%
cristy73b7d4c2010-06-27 00:31:00 +0000143% ImageView *DestroyImageView(ImageView *image_view)
cristy3ed852e2009-09-05 21:47:34 +0000144%
145% A description of each parameter follows:
146%
cristy73b7d4c2010-06-27 00:31:00 +0000147% o image_view: the image view.
cristy3ed852e2009-09-05 21:47:34 +0000148%
149*/
cristy73b7d4c2010-06-27 00:31:00 +0000150MagickExport ImageView *DestroyImageView(ImageView *image_view)
cristy3ed852e2009-09-05 21:47:34 +0000151{
cristy73b7d4c2010-06-27 00:31:00 +0000152 assert(image_view != (ImageView *) NULL);
153 assert(image_view->signature == MagickSignature);
cristyc3ebda22010-06-27 17:11:57 +0000154 if (image_view->description != (char *) NULL)
155 image_view->description=DestroyString(image_view->description);
cristy73b7d4c2010-06-27 00:31:00 +0000156 image_view->view=DestroyCacheView(image_view->view);
157 image_view->exception=DestroyExceptionInfo(image_view->exception);
158 image_view->signature=(~MagickSignature);
159 image_view=(ImageView *) RelinquishMagickMemory(image_view);
160 return(image_view);
cristy3ed852e2009-09-05 21:47:34 +0000161}
162
163/*
164%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
165% %
166% %
167% %
cristy7eb1b7a2010-06-26 15:47:49 +0000168% D u p l e x T r a n s f e r I m a g e V i e w I t e r a t o r %
cristy3ed852e2009-09-05 21:47:34 +0000169% %
170% %
171% %
172%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
173%
cristy73b7d4c2010-06-27 00:31:00 +0000174% DuplexTransferImageViewIterator() iterates over three image views in
cristy3ed852e2009-09-05 21:47:34 +0000175% parallel and calls your transfer method for each scanline of the view. The
cristyc3ebda22010-06-27 17:11:57 +0000176% source and duplex pixel extent is not confined to the image canvas-- that is
cristy3ed852e2009-09-05 21:47:34 +0000177% you can include negative offsets or widths or heights that exceed the image
cristy73b7d4c2010-06-27 00:31:00 +0000178% dimension. However, the destination image view is confined to the image
cristy3ed852e2009-09-05 21:47:34 +0000179% canvas-- that is no negative offsets or widths or heights that exceed the
180% image dimension are permitted.
181%
cristyd6dfc0d2010-06-27 19:30:49 +0000182% The callback signature is:
183%
184% MagickBooleanType DuplexTransferImageViewMethod(const ImageView *source,
185% const ImageView *duplex,ImageView *destination,const ssize_t y,
186% const int thread_id,void *context)
187%
cristy58739472010-06-26 20:27:18 +0000188% Use this pragma if the view is not single threaded:
cristy3ed852e2009-09-05 21:47:34 +0000189%
190% #pragma omp critical
191%
192% to define a section of code in your callback transfer method that must be
193% executed by a single thread at a time.
194%
cristy7eb1b7a2010-06-26 15:47:49 +0000195% The format of the DuplexTransferImageViewIterator method is:
cristy3ed852e2009-09-05 21:47:34 +0000196%
cristy7eb1b7a2010-06-26 15:47:49 +0000197% MagickBooleanType DuplexTransferImageViewIterator(ImageView *source,
198% ImageView *duplex,ImageView *destination,
199% DuplexTransferImageViewMethod transfer,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000200%
201% A description of each parameter follows:
202%
cristy73b7d4c2010-06-27 00:31:00 +0000203% o source: the source image view.
cristy3ed852e2009-09-05 21:47:34 +0000204%
cristy73b7d4c2010-06-27 00:31:00 +0000205% o duplex: the duplex image view.
cristy3ed852e2009-09-05 21:47:34 +0000206%
cristy73b7d4c2010-06-27 00:31:00 +0000207% o destination: the destination image view.
cristy3ed852e2009-09-05 21:47:34 +0000208%
209% o transfer: the transfer callback method.
210%
211% o context: the user defined context.
212%
213*/
cristy7eb1b7a2010-06-26 15:47:49 +0000214MagickExport MagickBooleanType DuplexTransferImageViewIterator(
215 ImageView *source,ImageView *duplex,ImageView *destination,
216 DuplexTransferImageViewMethod transfer,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000217{
cristy3ed852e2009-09-05 21:47:34 +0000218 ExceptionInfo
219 *exception;
220
221 Image
222 *destination_image,
223 *duplex_image,
224 *source_image;
225
cristy3ed852e2009-09-05 21:47:34 +0000226 MagickBooleanType
227 status;
228
cristycee97112010-05-28 00:44:52 +0000229 MagickOffsetType
230 progress;
231
232 ssize_t
233 y;
234
cristy7eb1b7a2010-06-26 15:47:49 +0000235 assert(source != (ImageView *) NULL);
236 assert(source->signature == MagickSignature);
237 if (transfer == (DuplexTransferImageViewMethod) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000238 return(MagickFalse);
cristy7eb1b7a2010-06-26 15:47:49 +0000239 source_image=source->image;
240 duplex_image=duplex->image;
241 destination_image=destination->image;
cristy3ed852e2009-09-05 21:47:34 +0000242 if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
243 return(MagickFalse);
244 status=MagickTrue;
245 progress=0;
246 exception=destination->exception;
cristyb5d5f722009-11-04 03:03:49 +0000247#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristycde47d32009-11-04 03:05:18 +0000248 #pragma omp parallel for schedule(static,1) shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +0000249#endif
cristyc3ebda22010-06-27 17:11:57 +0000250 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
cristy3ed852e2009-09-05 21:47:34 +0000251 {
cristy5c9e6f22010-09-17 17:31:01 +0000252 const int
253 id = GetOpenMPThreadId();
cristyad740052010-07-03 01:38:03 +0000254
cristy3ed852e2009-09-05 21:47:34 +0000255 MagickBooleanType
256 sync;
257
258 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000259 *restrict duplex_indexes,
260 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +0000261
262 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000263 *restrict duplex_pixels,
264 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000265
266 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000267 *restrict destination_indexes;
cristy3ed852e2009-09-05 21:47:34 +0000268
cristy3ed852e2009-09-05 21:47:34 +0000269 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000270 *restrict destination_pixels;
cristy3ed852e2009-09-05 21:47:34 +0000271
272 if (status == MagickFalse)
273 continue;
cristyc3ebda22010-06-27 17:11:57 +0000274 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
275 source->extent.width,1,source->exception);
cristy3ed852e2009-09-05 21:47:34 +0000276 if (pixels == (const PixelPacket *) NULL)
277 {
278 status=MagickFalse;
279 continue;
280 }
281 indexes=GetCacheViewVirtualIndexQueue(source->view);
cristyc3ebda22010-06-27 17:11:57 +0000282 duplex_pixels=GetCacheViewVirtualPixels(duplex->view,duplex->extent.x,y,
283 duplex->extent.width,1,duplex->exception);
cristy3ed852e2009-09-05 21:47:34 +0000284 if (duplex_pixels == (const PixelPacket *) NULL)
285 {
286 status=MagickFalse;
287 continue;
288 }
289 duplex_indexes=GetCacheViewVirtualIndexQueue(duplex->view);
cristy3ed852e2009-09-05 21:47:34 +0000290 destination_pixels=GetCacheViewAuthenticPixels(destination->view,
cristyc3ebda22010-06-27 17:11:57 +0000291 destination->extent.x,y,destination->extent.width,1,exception);
cristy3ed852e2009-09-05 21:47:34 +0000292 if (destination_pixels == (PixelPacket *) NULL)
293 {
294 status=MagickFalse;
295 continue;
296 }
297 destination_indexes=GetCacheViewAuthenticIndexQueue(destination->view);
cristyc3ebda22010-06-27 17:11:57 +0000298 if (transfer(source,duplex,destination,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000299 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000300 sync=SyncCacheViewAuthenticPixels(destination->view,exception);
301 if (sync == MagickFalse)
302 {
303 InheritException(destination->exception,GetCacheViewException(
304 source->view));
305 status=MagickFalse;
306 }
307 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
308 {
309 MagickBooleanType
310 proceed;
311
cristyb5d5f722009-11-04 03:03:49 +0000312#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy7eb1b7a2010-06-26 15:47:49 +0000313 #pragma omp critical (MagickCore_DuplexTransferImageViewIterator)
cristy3ed852e2009-09-05 21:47:34 +0000314#endif
cristyc3ebda22010-06-27 17:11:57 +0000315 proceed=SetImageProgress(source_image,source->description,progress++,
316 source->extent.height);
cristy3ed852e2009-09-05 21:47:34 +0000317 if (proceed == MagickFalse)
318 status=MagickFalse;
319 }
320 }
321 return(status);
322}
323
324/*
325%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
326% %
327% %
328% %
cristycc34c492010-06-26 23:49:12 +0000329% G e t I m a g e V i e w A u t h e n t i c I n d e x e s %
330% %
331% %
332% %
333%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
334%
cristy73b7d4c2010-06-27 00:31:00 +0000335% GetImageViewAuthenticIndexes() returns the image view authentic indexes.
cristycc34c492010-06-26 23:49:12 +0000336%
337% The format of the GetImageViewAuthenticPixels method is:
338%
cristy73b7d4c2010-06-27 00:31:00 +0000339% IndexPacket *GetImageViewAuthenticIndexes(const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000340%
341% A description of each parameter follows:
342%
cristy73b7d4c2010-06-27 00:31:00 +0000343% o image_view: the image view.
cristycc34c492010-06-26 23:49:12 +0000344%
345*/
346MagickExport IndexPacket *GetImageViewAuthenticIndexes(
cristy73b7d4c2010-06-27 00:31:00 +0000347 const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000348{
cristy73b7d4c2010-06-27 00:31:00 +0000349 assert(image_view != (ImageView *) NULL);
350 assert(image_view->signature == MagickSignature);
351 return(GetCacheViewAuthenticIndexQueue(image_view->view));
cristycc34c492010-06-26 23:49:12 +0000352}
353
354/*
355%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
356% %
357% %
358% %
359% G e t I m a g e V i e w A u t h e n t i c P i x e l s %
360% %
361% %
362% %
363%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
364%
cristy73b7d4c2010-06-27 00:31:00 +0000365% GetImageViewAuthenticPixels() returns the image view authentic pixels.
cristycc34c492010-06-26 23:49:12 +0000366%
367% The format of the GetImageViewAuthenticPixels method is:
368%
cristy73b7d4c2010-06-27 00:31:00 +0000369% PixelPacket *GetImageViewAuthenticPixels(const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000370%
371% A description of each parameter follows:
372%
cristy73b7d4c2010-06-27 00:31:00 +0000373% o image_view: the image view.
cristycc34c492010-06-26 23:49:12 +0000374%
375*/
376MagickExport PixelPacket *GetImageViewAuthenticPixels(
cristy73b7d4c2010-06-27 00:31:00 +0000377 const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000378{
cristy73b7d4c2010-06-27 00:31:00 +0000379 assert(image_view != (ImageView *) NULL);
380 assert(image_view->signature == MagickSignature);
381 return(GetCacheViewAuthenticPixelQueue(image_view->view));
cristycc34c492010-06-26 23:49:12 +0000382}
383
384/*
385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
386% %
387% %
388% %
cristy7eb1b7a2010-06-26 15:47:49 +0000389% G e t I m a g e V i e w E x c e p t i o n %
cristy3ed852e2009-09-05 21:47:34 +0000390% %
391% %
392% %
393%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
394%
cristy7eb1b7a2010-06-26 15:47:49 +0000395% GetImageViewException() returns the severity, reason, and description of any
cristy73b7d4c2010-06-27 00:31:00 +0000396% error that occurs when utilizing a image view.
cristy3ed852e2009-09-05 21:47:34 +0000397%
cristy7eb1b7a2010-06-26 15:47:49 +0000398% The format of the GetImageViewException method is:
cristy3ed852e2009-09-05 21:47:34 +0000399%
cristy73b7d4c2010-06-27 00:31:00 +0000400% char *GetImageViewException(const PixelImage *image_view,
cristy3ed852e2009-09-05 21:47:34 +0000401% ExceptionType *severity)
402%
403% A description of each parameter follows:
404%
cristy73b7d4c2010-06-27 00:31:00 +0000405% o image_view: the pixel image_view.
cristy3ed852e2009-09-05 21:47:34 +0000406%
407% o severity: the severity of the error is returned here.
408%
409*/
cristy73b7d4c2010-06-27 00:31:00 +0000410MagickExport char *GetImageViewException(const ImageView *image_view,
cristy3ed852e2009-09-05 21:47:34 +0000411 ExceptionType *severity)
412{
413 char
414 *description;
415
cristy73b7d4c2010-06-27 00:31:00 +0000416 assert(image_view != (const ImageView *) NULL);
417 assert(image_view->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +0000418 assert(severity != (ExceptionType *) NULL);
cristy73b7d4c2010-06-27 00:31:00 +0000419 *severity=image_view->exception->severity;
cristy3ed852e2009-09-05 21:47:34 +0000420 description=(char *) AcquireQuantumMemory(2UL*MaxTextExtent,
421 sizeof(*description));
422 if (description == (char *) NULL)
cristy7eb1b7a2010-06-26 15:47:49 +0000423 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000424 *description='\0';
cristy73b7d4c2010-06-27 00:31:00 +0000425 if (image_view->exception->reason != (char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000426 (void) CopyMagickString(description,GetLocaleExceptionMessage(
cristy73b7d4c2010-06-27 00:31:00 +0000427 image_view->exception->severity,image_view->exception->reason),
cristy3ed852e2009-09-05 21:47:34 +0000428 MaxTextExtent);
cristy73b7d4c2010-06-27 00:31:00 +0000429 if (image_view->exception->description != (char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000430 {
431 (void) ConcatenateMagickString(description," (",MaxTextExtent);
432 (void) ConcatenateMagickString(description,GetLocaleExceptionMessage(
cristy73b7d4c2010-06-27 00:31:00 +0000433 image_view->exception->severity,image_view->exception->description),
cristy3ed852e2009-09-05 21:47:34 +0000434 MaxTextExtent);
435 (void) ConcatenateMagickString(description,")",MaxTextExtent);
436 }
437 return(description);
438}
439
440/*
441%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
442% %
443% %
444% %
cristyc3ebda22010-06-27 17:11:57 +0000445% G e t I m a g e V i e w E x t e n t %
cristy3ed852e2009-09-05 21:47:34 +0000446% %
447% %
448% %
449%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
450%
cristyc3ebda22010-06-27 17:11:57 +0000451% GetImageViewExtent() returns the image view extent.
cristy3ed852e2009-09-05 21:47:34 +0000452%
cristyc3ebda22010-06-27 17:11:57 +0000453% The format of the GetImageViewExtent method is:
cristy3ed852e2009-09-05 21:47:34 +0000454%
cristyc3ebda22010-06-27 17:11:57 +0000455% RectangleInfo GetImageViewExtent(const ImageView *image_view)
cristy3ed852e2009-09-05 21:47:34 +0000456%
457% A description of each parameter follows:
458%
cristy73b7d4c2010-06-27 00:31:00 +0000459% o image_view: the image view.
cristy3ed852e2009-09-05 21:47:34 +0000460%
461*/
cristyc3ebda22010-06-27 17:11:57 +0000462MagickExport RectangleInfo GetImageViewExtent(const ImageView *image_view)
cristy3ed852e2009-09-05 21:47:34 +0000463{
cristy73b7d4c2010-06-27 00:31:00 +0000464 assert(image_view != (ImageView *) NULL);
465 assert(image_view->signature == MagickSignature);
cristyc3ebda22010-06-27 17:11:57 +0000466 return(image_view->extent);
cristy73b7d4c2010-06-27 00:31:00 +0000467}
468
469/*
470%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
471% %
472% %
473% %
474% G e t I m a g e V i e w I m a g e %
475% %
476% %
477% %
478%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
479%
480% GetImageViewImage() returns the image associated with the image view.
481%
482% The format of the GetImageViewImage method is:
483%
484% MagickCore *GetImageViewImage(const ImageView *image_view)
485%
486% A description of each parameter follows:
487%
488% o image_view: the image view.
489%
490*/
491MagickExport Image *GetImageViewImage(const ImageView *image_view)
492{
493 assert(image_view != (ImageView *) NULL);
494 assert(image_view->signature == MagickSignature);
495 return(image_view->image);
cristy3ed852e2009-09-05 21:47:34 +0000496}
497
498/*
499%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
500% %
501% %
502% %
cristy7eb1b7a2010-06-26 15:47:49 +0000503% G e t I m a g e V i e w I t e r a t o r %
cristy3ed852e2009-09-05 21:47:34 +0000504% %
505% %
506% %
507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
508%
cristy73b7d4c2010-06-27 00:31:00 +0000509% GetImageViewIterator() iterates over the image view in parallel and calls
cristyc3ebda22010-06-27 17:11:57 +0000510% your get method for each scanline of the view. The pixel extent is
cristy3ed852e2009-09-05 21:47:34 +0000511% not confined to the image canvas-- that is you can include negative offsets
512% or widths or heights that exceed the image dimension. Any updates to
513% the pixels in your callback are ignored.
514%
cristyd6dfc0d2010-06-27 19:30:49 +0000515% The callback signature is:
516%
517% MagickBooleanType GetImageViewMethod(const ImageView *source,
518% const ssize_t y,const int thread_id,void *context)
519%
cristy58739472010-06-26 20:27:18 +0000520% Use this pragma if the view is not single threaded:
cristy3ed852e2009-09-05 21:47:34 +0000521%
522% #pragma omp critical
523%
524% to define a section of code in your callback get method that must be
525% executed by a single thread at a time.
526%
cristy7eb1b7a2010-06-26 15:47:49 +0000527% The format of the GetImageViewIterator method is:
cristy3ed852e2009-09-05 21:47:34 +0000528%
cristy7eb1b7a2010-06-26 15:47:49 +0000529% MagickBooleanType GetImageViewIterator(ImageView *source,
530% GetImageViewMethod get,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000531%
532% A description of each parameter follows:
533%
cristy73b7d4c2010-06-27 00:31:00 +0000534% o source: the source image view.
cristy3ed852e2009-09-05 21:47:34 +0000535%
536% o get: the get callback method.
537%
538% o context: the user defined context.
539%
540*/
cristy7eb1b7a2010-06-26 15:47:49 +0000541MagickExport MagickBooleanType GetImageViewIterator(ImageView *source,
542 GetImageViewMethod get,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000543{
cristy3ed852e2009-09-05 21:47:34 +0000544 Image
545 *source_image;
546
cristy3ed852e2009-09-05 21:47:34 +0000547 MagickBooleanType
548 status;
549
cristycee97112010-05-28 00:44:52 +0000550 MagickOffsetType
551 progress;
552
553 ssize_t
554 y;
555
cristy7eb1b7a2010-06-26 15:47:49 +0000556 assert(source != (ImageView *) NULL);
557 assert(source->signature == MagickSignature);
558 if (get == (GetImageViewMethod) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000559 return(MagickFalse);
cristy7eb1b7a2010-06-26 15:47:49 +0000560 source_image=source->image;
cristy3ed852e2009-09-05 21:47:34 +0000561 status=MagickTrue;
562 progress=0;
cristyb5d5f722009-11-04 03:03:49 +0000563#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy309f6132010-06-07 13:19:01 +0000564 #pragma omp parallel for schedule(static,1) shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +0000565#endif
cristyc3ebda22010-06-27 17:11:57 +0000566 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
cristy3ed852e2009-09-05 21:47:34 +0000567 {
cristy5c9e6f22010-09-17 17:31:01 +0000568 const int
569 id = GetOpenMPThreadId();
cristyad740052010-07-03 01:38:03 +0000570
cristy3ed852e2009-09-05 21:47:34 +0000571 register const IndexPacket
572 *indexes;
573
574 register const PixelPacket
575 *pixels;
576
cristy3ed852e2009-09-05 21:47:34 +0000577 if (status == MagickFalse)
578 continue;
cristyc3ebda22010-06-27 17:11:57 +0000579 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
580 source->extent.width,1,source->exception);
cristy3ed852e2009-09-05 21:47:34 +0000581 if (pixels == (const PixelPacket *) NULL)
582 {
583 status=MagickFalse;
584 continue;
585 }
586 indexes=GetCacheViewVirtualIndexQueue(source->view);
cristyd6dfc0d2010-06-27 19:30:49 +0000587 if (get(source,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000588 status=MagickFalse;
589 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
590 {
591 MagickBooleanType
592 proceed;
593
cristyb5d5f722009-11-04 03:03:49 +0000594#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy7eb1b7a2010-06-26 15:47:49 +0000595 #pragma omp critical (MagickCore_GetImageViewIterator)
cristy3ed852e2009-09-05 21:47:34 +0000596#endif
cristyc3ebda22010-06-27 17:11:57 +0000597 proceed=SetImageProgress(source_image,source->description,progress++,
598 source->extent.height);
cristy3ed852e2009-09-05 21:47:34 +0000599 if (proceed == MagickFalse)
600 status=MagickFalse;
601 }
602 }
603 return(status);
604}
605
606/*
607%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
608% %
609% %
610% %
cristycc34c492010-06-26 23:49:12 +0000611% G e t I m a g e V i e w V i r t u a l I n d e x e s %
612% %
613% %
614% %
615%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
616%
cristy73b7d4c2010-06-27 00:31:00 +0000617% GetImageViewVirtualIndexes() returns the image view virtual indexes.
cristycc34c492010-06-26 23:49:12 +0000618%
cristy73b7d4c2010-06-27 00:31:00 +0000619% The format of the GetImageViewVirtualIndexes method is:
cristycc34c492010-06-26 23:49:12 +0000620%
621% const IndexPacket *GetImageViewVirtualIndexes(
cristy73b7d4c2010-06-27 00:31:00 +0000622% const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000623%
624% A description of each parameter follows:
625%
cristy73b7d4c2010-06-27 00:31:00 +0000626% o image_view: the image view.
cristycc34c492010-06-26 23:49:12 +0000627%
628*/
629MagickExport const IndexPacket *GetImageViewVirtualIndexes(
cristy73b7d4c2010-06-27 00:31:00 +0000630 const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000631{
cristy73b7d4c2010-06-27 00:31:00 +0000632 assert(image_view != (ImageView *) NULL);
633 assert(image_view->signature == MagickSignature);
634 return(GetCacheViewVirtualIndexQueue(image_view->view));
cristycc34c492010-06-26 23:49:12 +0000635}
636
637/*
638%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
639% %
640% %
641% %
642% G e t I m a g e V i e w V i r t u a l P i x e l s %
643% %
644% %
645% %
646%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
647%
cristy73b7d4c2010-06-27 00:31:00 +0000648% GetImageViewVirtualPixels() returns the image view virtual pixels.
cristycc34c492010-06-26 23:49:12 +0000649%
650% The format of the GetImageViewVirtualPixels method is:
651%
cristy73b7d4c2010-06-27 00:31:00 +0000652% const PixelPacket *GetImageViewVirtualPixels(const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000653%
654% A description of each parameter follows:
655%
cristy73b7d4c2010-06-27 00:31:00 +0000656% o image_view: the image view.
cristycc34c492010-06-26 23:49:12 +0000657%
658*/
659MagickExport const PixelPacket *GetImageViewVirtualPixels(
cristy73b7d4c2010-06-27 00:31:00 +0000660 const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000661{
cristy73b7d4c2010-06-27 00:31:00 +0000662 assert(image_view != (ImageView *) NULL);
663 assert(image_view->signature == MagickSignature);
664 return(GetCacheViewVirtualPixelQueue(image_view->view));
cristycc34c492010-06-26 23:49:12 +0000665}
666
667/*
668%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
669% %
670% %
671% %
cristy7eb1b7a2010-06-26 15:47:49 +0000672% I s I m a g e V i e w %
cristy3ed852e2009-09-05 21:47:34 +0000673% %
674% %
675% %
676%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
677%
cristy73b7d4c2010-06-27 00:31:00 +0000678% IsImageView() returns MagickTrue if the the parameter is verified as a image
679% view object.
cristy3ed852e2009-09-05 21:47:34 +0000680%
cristy7eb1b7a2010-06-26 15:47:49 +0000681% The format of the IsImageView method is:
cristy3ed852e2009-09-05 21:47:34 +0000682%
cristy73b7d4c2010-06-27 00:31:00 +0000683% MagickBooleanType IsImageView(const ImageView *image_view)
cristy3ed852e2009-09-05 21:47:34 +0000684%
685% A description of each parameter follows:
686%
cristy73b7d4c2010-06-27 00:31:00 +0000687% o image_view: the image view.
cristy3ed852e2009-09-05 21:47:34 +0000688%
689*/
cristy73b7d4c2010-06-27 00:31:00 +0000690MagickExport MagickBooleanType IsImageView(const ImageView *image_view)
cristy3ed852e2009-09-05 21:47:34 +0000691{
cristy73b7d4c2010-06-27 00:31:00 +0000692 if (image_view == (const ImageView *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000693 return(MagickFalse);
cristy73b7d4c2010-06-27 00:31:00 +0000694 if (image_view->signature != MagickSignature)
cristy3ed852e2009-09-05 21:47:34 +0000695 return(MagickFalse);
696 return(MagickTrue);
697}
698
699/*
700%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
701% %
702% %
703% %
cristy7eb1b7a2010-06-26 15:47:49 +0000704% N e w I m a g e V i e w %
cristy3ed852e2009-09-05 21:47:34 +0000705% %
706% %
707% %
708%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
709%
cristy73b7d4c2010-06-27 00:31:00 +0000710% NewImageView() returns a image view required for all other methods in the
711% Image View API.
cristy3ed852e2009-09-05 21:47:34 +0000712%
cristy7eb1b7a2010-06-26 15:47:49 +0000713% The format of the NewImageView method is:
cristy3ed852e2009-09-05 21:47:34 +0000714%
cristy7eb1b7a2010-06-26 15:47:49 +0000715% ImageView *NewImageView(MagickCore *wand)
cristy3ed852e2009-09-05 21:47:34 +0000716%
717% A description of each parameter follows:
718%
719% o wand: the wand.
720%
721*/
cristy7eb1b7a2010-06-26 15:47:49 +0000722MagickExport ImageView *NewImageView(Image *image)
cristy3ed852e2009-09-05 21:47:34 +0000723{
cristy7eb1b7a2010-06-26 15:47:49 +0000724 ImageView
cristy73b7d4c2010-06-27 00:31:00 +0000725 *image_view;
cristy3ed852e2009-09-05 21:47:34 +0000726
cristy7eb1b7a2010-06-26 15:47:49 +0000727 assert(image != (Image *) NULL);
728 assert(image->signature == MagickSignature);
cristy73bd4a52010-10-05 11:24:23 +0000729 image_view=(ImageView *) AcquireMagickMemory(sizeof(*image_view));
cristy73b7d4c2010-06-27 00:31:00 +0000730 if (image_view == (ImageView *) NULL)
cristy7eb1b7a2010-06-26 15:47:49 +0000731 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy73b7d4c2010-06-27 00:31:00 +0000732 (void) ResetMagickMemory(image_view,0,sizeof(*image_view));
cristyc3ebda22010-06-27 17:11:57 +0000733 image_view->description=ConstantString("ImageView");
cristy73b7d4c2010-06-27 00:31:00 +0000734 image_view->image=image;
735 image_view->view=AcquireCacheView(image_view->image);
cristyc3ebda22010-06-27 17:11:57 +0000736 image_view->extent.width=image->columns;
737 image_view->extent.height=image->rows;
738 image_view->extent.x=0;
739 image_view->extent.y=0;
cristy73b7d4c2010-06-27 00:31:00 +0000740 image_view->number_threads=GetOpenMPMaximumThreads();
cristyc3ebda22010-06-27 17:11:57 +0000741 image_view->exception=AcquireExceptionInfo();
cristy73b7d4c2010-06-27 00:31:00 +0000742 image_view->debug=IsEventLogging();
743 image_view->signature=MagickSignature;
744 return(image_view);
cristy3ed852e2009-09-05 21:47:34 +0000745}
746
747/*
748%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
749% %
750% %
751% %
cristy7eb1b7a2010-06-26 15:47:49 +0000752% N e w I m a g e V i e w R e g i o n %
cristy3ed852e2009-09-05 21:47:34 +0000753% %
754% %
755% %
756%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
757%
cristy73b7d4c2010-06-27 00:31:00 +0000758% NewImageViewRegion() returns a image view required for all other methods
759% in the Image View API.
cristy3ed852e2009-09-05 21:47:34 +0000760%
cristy7eb1b7a2010-06-26 15:47:49 +0000761% The format of the NewImageViewRegion method is:
cristy3ed852e2009-09-05 21:47:34 +0000762%
cristy7eb1b7a2010-06-26 15:47:49 +0000763% ImageView *NewImageViewRegion(MagickCore *wand,const ssize_t x,
cristybb503372010-05-27 20:51:26 +0000764% const ssize_t y,const size_t width,const size_t height)
cristy3ed852e2009-09-05 21:47:34 +0000765%
766% A description of each parameter follows:
767%
768% o wand: the magick wand.
769%
cristyc3ebda22010-06-27 17:11:57 +0000770% o x,y,columns,rows: These values define the perimeter of a extent of
cristy3ed852e2009-09-05 21:47:34 +0000771% pixel_wands view.
772%
773*/
cristy7eb1b7a2010-06-26 15:47:49 +0000774MagickExport ImageView *NewImageViewRegion(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +0000775 const ssize_t y,const size_t width,const size_t height)
cristy3ed852e2009-09-05 21:47:34 +0000776{
cristy7eb1b7a2010-06-26 15:47:49 +0000777 ImageView
cristy73b7d4c2010-06-27 00:31:00 +0000778 *image_view;
cristy3ed852e2009-09-05 21:47:34 +0000779
cristy7eb1b7a2010-06-26 15:47:49 +0000780 assert(image != (Image *) NULL);
781 assert(image->signature == MagickSignature);
cristy73bd4a52010-10-05 11:24:23 +0000782 image_view=(ImageView *) AcquireMagickMemory(sizeof(*image_view));
cristy73b7d4c2010-06-27 00:31:00 +0000783 if (image_view == (ImageView *) NULL)
cristy7eb1b7a2010-06-26 15:47:49 +0000784 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy73b7d4c2010-06-27 00:31:00 +0000785 (void) ResetMagickMemory(image_view,0,sizeof(*image_view));
cristyc3ebda22010-06-27 17:11:57 +0000786 image_view->description=ConstantString("ImageView");
cristy73b7d4c2010-06-27 00:31:00 +0000787 image_view->view=AcquireCacheView(image_view->image);
788 image_view->image=image;
cristyc3ebda22010-06-27 17:11:57 +0000789 image_view->extent.width=width;
790 image_view->extent.height=height;
791 image_view->extent.x=x;
792 image_view->extent.y=y;
cristy73b7d4c2010-06-27 00:31:00 +0000793 image_view->number_threads=GetOpenMPMaximumThreads();
cristyc3ebda22010-06-27 17:11:57 +0000794 image_view->exception=AcquireExceptionInfo();
cristy73b7d4c2010-06-27 00:31:00 +0000795 image_view->debug=IsEventLogging();
796 image_view->signature=MagickSignature;
797 return(image_view);
cristy3ed852e2009-09-05 21:47:34 +0000798}
799
800/*
801%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
802% %
803% %
804% %
cristyc3ebda22010-06-27 17:11:57 +0000805% S e t I m a g e V i e w D e s c r i p t i o n %
806% %
807% %
808% %
809%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
810%
811% SetImageViewDescription() associates a description with an image view.
812%
813% The format of the SetImageViewDescription method is:
814%
815% void SetImageViewDescription(ImageView *image_view,
816% const char *description)
817%
818% A description of each parameter follows:
819%
820% o image_view: the image view.
821%
822% o description: the image view description.
823%
824*/
825MagickExport void SetImageViewDescription(ImageView *image_view,
826 const char *description)
827{
828 assert(image_view != (ImageView *) NULL);
829 assert(image_view->signature == MagickSignature);
830 image_view->description=ConstantString(description);
831}
832
833/*
834%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
835% %
836% %
837% %
cristy7eb1b7a2010-06-26 15:47:49 +0000838% S e t I m a g e V i e w I t e r a t o r %
cristy3ed852e2009-09-05 21:47:34 +0000839% %
840% %
841% %
842%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
843%
cristy73b7d4c2010-06-27 00:31:00 +0000844% SetImageViewIterator() iterates over the image view in parallel and calls
cristyc3ebda22010-06-27 17:11:57 +0000845% your set method for each scanline of the view. The pixel extent is
cristy3ed852e2009-09-05 21:47:34 +0000846% confined to the image canvas-- that is no negative offsets or widths or
847% heights that exceed the image dimension. The pixels are initiallly
848% undefined and any settings you make in the callback method are automagically
849% synced back to your image.
850%
cristyd6dfc0d2010-06-27 19:30:49 +0000851% The callback signature is:
852%
853% MagickBooleanType SetImageViewMethod(ImageView *destination,
854% const ssize_t y,const int thread_id,void *context)
855%
cristy58739472010-06-26 20:27:18 +0000856% Use this pragma if the view is not single threaded:
cristy3ed852e2009-09-05 21:47:34 +0000857%
858% #pragma omp critical
859%
860% to define a section of code in your callback set method that must be
861% executed by a single thread at a time.
862%
cristy7eb1b7a2010-06-26 15:47:49 +0000863% The format of the SetImageViewIterator method is:
cristy3ed852e2009-09-05 21:47:34 +0000864%
cristy7eb1b7a2010-06-26 15:47:49 +0000865% MagickBooleanType SetImageViewIterator(ImageView *destination,
866% SetImageViewMethod set,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000867%
868% A description of each parameter follows:
869%
cristy73b7d4c2010-06-27 00:31:00 +0000870% o destination: the image view.
cristy3ed852e2009-09-05 21:47:34 +0000871%
872% o set: the set callback method.
873%
874% o context: the user defined context.
875%
876*/
cristy7eb1b7a2010-06-26 15:47:49 +0000877MagickExport MagickBooleanType SetImageViewIterator(ImageView *destination,
878 SetImageViewMethod set,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000879{
cristy3ed852e2009-09-05 21:47:34 +0000880 ExceptionInfo
881 *exception;
882
883 Image
884 *destination_image;
885
cristy3ed852e2009-09-05 21:47:34 +0000886 MagickBooleanType
887 status;
888
cristycee97112010-05-28 00:44:52 +0000889 MagickOffsetType
890 progress;
891
892 ssize_t
893 y;
894
cristy7eb1b7a2010-06-26 15:47:49 +0000895 assert(destination != (ImageView *) NULL);
896 assert(destination->signature == MagickSignature);
897 if (set == (SetImageViewMethod) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000898 return(MagickFalse);
cristy7eb1b7a2010-06-26 15:47:49 +0000899 destination_image=destination->image;
cristy3ed852e2009-09-05 21:47:34 +0000900 if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
901 return(MagickFalse);
902 status=MagickTrue;
903 progress=0;
904 exception=destination->exception;
cristyb5d5f722009-11-04 03:03:49 +0000905#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy309f6132010-06-07 13:19:01 +0000906 #pragma omp parallel for schedule(static,1) shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +0000907#endif
cristyc3ebda22010-06-27 17:11:57 +0000908 for (y=destination->extent.y; y < (ssize_t) destination->extent.height; y++)
cristy3ed852e2009-09-05 21:47:34 +0000909 {
cristy5c9e6f22010-09-17 17:31:01 +0000910 const int
911 id = GetOpenMPThreadId();
cristyad740052010-07-03 01:38:03 +0000912
cristy3ed852e2009-09-05 21:47:34 +0000913 MagickBooleanType
914 sync;
915
916 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000917 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +0000918
cristy3ed852e2009-09-05 21:47:34 +0000919 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000920 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000921
922 if (status == MagickFalse)
923 continue;
cristyc3ebda22010-06-27 17:11:57 +0000924 pixels=GetCacheViewAuthenticPixels(destination->view,destination->extent.x,
925 y,destination->extent.width,1,exception);
cristy3ed852e2009-09-05 21:47:34 +0000926 if (pixels == (PixelPacket *) NULL)
927 {
928 InheritException(destination->exception,GetCacheViewException(
929 destination->view));
930 status=MagickFalse;
931 continue;
932 }
933 indexes=GetCacheViewAuthenticIndexQueue(destination->view);
cristyd6dfc0d2010-06-27 19:30:49 +0000934 if (set(destination,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000935 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000936 sync=SyncCacheViewAuthenticPixels(destination->view,exception);
937 if (sync == MagickFalse)
938 {
939 InheritException(destination->exception,GetCacheViewException(
940 destination->view));
941 status=MagickFalse;
942 }
943 if (destination_image->progress_monitor != (MagickProgressMonitor) NULL)
944 {
945 MagickBooleanType
946 proceed;
947
cristyb5d5f722009-11-04 03:03:49 +0000948#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy7eb1b7a2010-06-26 15:47:49 +0000949 #pragma omp critical (MagickCore_SetImageViewIterator)
cristy3ed852e2009-09-05 21:47:34 +0000950#endif
cristyc3ebda22010-06-27 17:11:57 +0000951 proceed=SetImageProgress(destination_image,destination->description,
952 progress++,destination->extent.height);
cristy3ed852e2009-09-05 21:47:34 +0000953 if (proceed == MagickFalse)
954 status=MagickFalse;
955 }
956 }
957 return(status);
958}
959
960/*
961%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
962% %
963% %
964% %
cristy7eb1b7a2010-06-26 15:47:49 +0000965% T r a n s f e r I m a g e V i e w I t e r a t o r %
cristy3ed852e2009-09-05 21:47:34 +0000966% %
967% %
968% %
969%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
970%
cristy73b7d4c2010-06-27 00:31:00 +0000971% TransferImageViewIterator() iterates over two image views in parallel and
cristy3ed852e2009-09-05 21:47:34 +0000972% calls your transfer method for each scanline of the view. The source pixel
cristyc3ebda22010-06-27 17:11:57 +0000973% extent is not confined to the image canvas-- that is you can include
cristy3ed852e2009-09-05 21:47:34 +0000974% negative offsets or widths or heights that exceed the image dimension.
cristy73b7d4c2010-06-27 00:31:00 +0000975% However, the destination image view is confined to the image canvas-- that
cristy3ed852e2009-09-05 21:47:34 +0000976% is no negative offsets or widths or heights that exceed the image dimension
977% are permitted.
978%
cristyd6dfc0d2010-06-27 19:30:49 +0000979% The callback signature is:
980%
981% MagickBooleanType TransferImageViewMethod(const ImageView *source,
982% ImageView *destination,const ssize_t y,const int thread_id,
983% void *context)
984%
cristy58739472010-06-26 20:27:18 +0000985% Use this pragma if the view is not single threaded:
cristy3ed852e2009-09-05 21:47:34 +0000986%
987% #pragma omp critical
988%
989% to define a section of code in your callback transfer method that must be
990% executed by a single thread at a time.
991%
cristy7eb1b7a2010-06-26 15:47:49 +0000992% The format of the TransferImageViewIterator method is:
cristy3ed852e2009-09-05 21:47:34 +0000993%
cristy7eb1b7a2010-06-26 15:47:49 +0000994% MagickBooleanType TransferImageViewIterator(ImageView *source,
995% ImageView *destination,TransferImageViewMethod transfer,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000996%
997% A description of each parameter follows:
998%
cristy73b7d4c2010-06-27 00:31:00 +0000999% o source: the source image view.
cristy3ed852e2009-09-05 21:47:34 +00001000%
cristy73b7d4c2010-06-27 00:31:00 +00001001% o destination: the destination image view.
cristy3ed852e2009-09-05 21:47:34 +00001002%
1003% o transfer: the transfer callback method.
1004%
1005% o context: the user defined context.
1006%
1007*/
cristy7eb1b7a2010-06-26 15:47:49 +00001008MagickExport MagickBooleanType TransferImageViewIterator(ImageView *source,
1009 ImageView *destination,TransferImageViewMethod transfer,void *context)
cristy3ed852e2009-09-05 21:47:34 +00001010{
cristy3ed852e2009-09-05 21:47:34 +00001011 ExceptionInfo
1012 *exception;
1013
1014 Image
1015 *destination_image,
1016 *source_image;
1017
cristy3ed852e2009-09-05 21:47:34 +00001018 MagickBooleanType
1019 status;
1020
cristycee97112010-05-28 00:44:52 +00001021 MagickOffsetType
1022 progress;
1023
1024 ssize_t
1025 y;
1026
cristy7eb1b7a2010-06-26 15:47:49 +00001027 assert(source != (ImageView *) NULL);
1028 assert(source->signature == MagickSignature);
1029 if (transfer == (TransferImageViewMethod) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001030 return(MagickFalse);
cristy7eb1b7a2010-06-26 15:47:49 +00001031 source_image=source->image;
1032 destination_image=destination->image;
cristy3ed852e2009-09-05 21:47:34 +00001033 if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
1034 return(MagickFalse);
1035 status=MagickTrue;
1036 progress=0;
1037 exception=destination->exception;
cristyb5d5f722009-11-04 03:03:49 +00001038#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy309f6132010-06-07 13:19:01 +00001039 #pragma omp parallel for schedule(static,1) shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +00001040#endif
cristyc3ebda22010-06-27 17:11:57 +00001041 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
cristy3ed852e2009-09-05 21:47:34 +00001042 {
cristy5c9e6f22010-09-17 17:31:01 +00001043 const int
1044 id = GetOpenMPThreadId();
cristyad740052010-07-03 01:38:03 +00001045
cristy3ed852e2009-09-05 21:47:34 +00001046 MagickBooleanType
1047 sync;
1048
1049 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00001050 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00001051
1052 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001053 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001054
1055 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00001056 *restrict destination_indexes;
cristy3ed852e2009-09-05 21:47:34 +00001057
cristy3ed852e2009-09-05 21:47:34 +00001058 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001059 *restrict destination_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001060
1061 if (status == MagickFalse)
1062 continue;
cristyc3ebda22010-06-27 17:11:57 +00001063 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
1064 source->extent.width,1,source->exception);
cristy3ed852e2009-09-05 21:47:34 +00001065 if (pixels == (const PixelPacket *) NULL)
1066 {
1067 status=MagickFalse;
1068 continue;
1069 }
1070 indexes=GetCacheViewVirtualIndexQueue(source->view);
cristy3ed852e2009-09-05 21:47:34 +00001071 destination_pixels=GetCacheViewAuthenticPixels(destination->view,
cristyc3ebda22010-06-27 17:11:57 +00001072 destination->extent.x,y,destination->extent.width,1,exception);
cristy3ed852e2009-09-05 21:47:34 +00001073 if (destination_pixels == (PixelPacket *) NULL)
1074 {
1075 status=MagickFalse;
1076 continue;
1077 }
1078 destination_indexes=GetCacheViewAuthenticIndexQueue(destination->view);
cristyc3ebda22010-06-27 17:11:57 +00001079 if (transfer(source,destination,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001080 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00001081 sync=SyncCacheViewAuthenticPixels(destination->view,exception);
1082 if (sync == MagickFalse)
1083 {
1084 InheritException(destination->exception,GetCacheViewException(
1085 source->view));
1086 status=MagickFalse;
1087 }
1088 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1089 {
1090 MagickBooleanType
1091 proceed;
1092
cristyb5d5f722009-11-04 03:03:49 +00001093#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy7eb1b7a2010-06-26 15:47:49 +00001094 #pragma omp critical (MagickCore_TransferImageViewIterator)
cristy3ed852e2009-09-05 21:47:34 +00001095#endif
cristyc3ebda22010-06-27 17:11:57 +00001096 proceed=SetImageProgress(source_image,source->description,progress++,
1097 source->extent.height);
cristy3ed852e2009-09-05 21:47:34 +00001098 if (proceed == MagickFalse)
1099 status=MagickFalse;
1100 }
1101 }
1102 return(status);
1103}
1104
1105/*
1106%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1107% %
1108% %
1109% %
cristy7eb1b7a2010-06-26 15:47:49 +00001110% U p d a t e I m a g e V i e w I t e r a t o r %
cristy3ed852e2009-09-05 21:47:34 +00001111% %
1112% %
1113% %
1114%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1115%
cristy73b7d4c2010-06-27 00:31:00 +00001116% UpdateImageViewIterator() iterates over the image view in parallel and calls
cristyc3ebda22010-06-27 17:11:57 +00001117% your update method for each scanline of the view. The pixel extent is
cristy3ed852e2009-09-05 21:47:34 +00001118% confined to the image canvas-- that is no negative offsets or widths or
1119% heights that exceed the image dimension are permitted. Updates to pixels
1120% in your callback are automagically synced back to the image.
1121%
cristyd6dfc0d2010-06-27 19:30:49 +00001122% The callback signature is:
1123%
1124% MagickBooleanType UpdateImageViewMethod(ImageView *source,
1125% const ssize_t y,const int thread_id,void *context)
1126%
cristy58739472010-06-26 20:27:18 +00001127% Use this pragma if the view is not single threaded:
cristy3ed852e2009-09-05 21:47:34 +00001128%
1129% #pragma omp critical
1130%
1131% to define a section of code in your callback update method that must be
1132% executed by a single thread at a time.
1133%
cristy7eb1b7a2010-06-26 15:47:49 +00001134% The format of the UpdateImageViewIterator method is:
cristy3ed852e2009-09-05 21:47:34 +00001135%
cristy7eb1b7a2010-06-26 15:47:49 +00001136% MagickBooleanType UpdateImageViewIterator(ImageView *source,
1137% UpdateImageViewMethod update,void *context)
cristy3ed852e2009-09-05 21:47:34 +00001138%
1139% A description of each parameter follows:
1140%
cristy73b7d4c2010-06-27 00:31:00 +00001141% o source: the source image view.
cristy3ed852e2009-09-05 21:47:34 +00001142%
1143% o update: the update callback method.
1144%
1145% o context: the user defined context.
1146%
1147*/
cristy7eb1b7a2010-06-26 15:47:49 +00001148MagickExport MagickBooleanType UpdateImageViewIterator(ImageView *source,
1149 UpdateImageViewMethod update,void *context)
cristy3ed852e2009-09-05 21:47:34 +00001150{
cristy3ed852e2009-09-05 21:47:34 +00001151 ExceptionInfo
1152 *exception;
1153
1154 Image
1155 *source_image;
1156
cristy3ed852e2009-09-05 21:47:34 +00001157 MagickBooleanType
1158 status;
1159
cristycee97112010-05-28 00:44:52 +00001160 MagickOffsetType
1161 progress;
1162
1163 ssize_t
1164 y;
1165
cristy7eb1b7a2010-06-26 15:47:49 +00001166 assert(source != (ImageView *) NULL);
1167 assert(source->signature == MagickSignature);
1168 if (update == (UpdateImageViewMethod) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001169 return(MagickFalse);
cristy7eb1b7a2010-06-26 15:47:49 +00001170 source_image=source->image;
cristy3ed852e2009-09-05 21:47:34 +00001171 if (SetImageStorageClass(source_image,DirectClass) == MagickFalse)
1172 return(MagickFalse);
1173 status=MagickTrue;
1174 progress=0;
1175 exception=source->exception;
cristyb5d5f722009-11-04 03:03:49 +00001176#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy309f6132010-06-07 13:19:01 +00001177 #pragma omp parallel for schedule(static,1) shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +00001178#endif
cristyc3ebda22010-06-27 17:11:57 +00001179 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
cristy3ed852e2009-09-05 21:47:34 +00001180 {
cristy5c9e6f22010-09-17 17:31:01 +00001181 const int
1182 id = GetOpenMPThreadId();
cristyad740052010-07-03 01:38:03 +00001183
cristy3ed852e2009-09-05 21:47:34 +00001184 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00001185 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00001186
cristy3ed852e2009-09-05 21:47:34 +00001187 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001188 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001189
1190 if (status == MagickFalse)
1191 continue;
cristyc3ebda22010-06-27 17:11:57 +00001192 pixels=GetCacheViewAuthenticPixels(source->view,source->extent.x,y,
1193 source->extent.width,1,exception);
cristy3ed852e2009-09-05 21:47:34 +00001194 if (pixels == (PixelPacket *) NULL)
1195 {
cristy73b7d4c2010-06-27 00:31:00 +00001196 InheritException(source->exception,GetCacheViewException(source->view));
cristy3ed852e2009-09-05 21:47:34 +00001197 status=MagickFalse;
1198 continue;
1199 }
1200 indexes=GetCacheViewAuthenticIndexQueue(source->view);
cristyc3ebda22010-06-27 17:11:57 +00001201 if (update(source,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001202 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00001203 if (SyncCacheViewAuthenticPixels(source->view,exception) == MagickFalse)
1204 {
1205 InheritException(source->exception,GetCacheViewException(source->view));
1206 status=MagickFalse;
1207 }
1208 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1209 {
1210 MagickBooleanType
1211 proceed;
1212
cristyb5d5f722009-11-04 03:03:49 +00001213#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy7eb1b7a2010-06-26 15:47:49 +00001214 #pragma omp critical (MagickCore_UpdateImageViewIterator)
cristy3ed852e2009-09-05 21:47:34 +00001215#endif
cristyc3ebda22010-06-27 17:11:57 +00001216 proceed=SetImageProgress(source_image,source->description,progress++,
1217 source->extent.height);
cristy3ed852e2009-09-05 21:47:34 +00001218 if (proceed == MagickFalse)
1219 status=MagickFalse;
1220 }
1221 }
1222 return(status);
1223}