blob: 80e88534c329181da6f44483d1899f35b51274a8 [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);
cristy7eb1b7a2010-06-26 15:47:49 +0000113 clone_view=(ImageView *) AcquireAlignedMemory(1,sizeof(*clone_view));
114 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 {
cristyad740052010-07-03 01:38:03 +0000252 int
253 id;
254
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;
274 id=GetOpenMPThreadId();
cristyc3ebda22010-06-27 17:11:57 +0000275 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
276 source->extent.width,1,source->exception);
cristy3ed852e2009-09-05 21:47:34 +0000277 if (pixels == (const PixelPacket *) NULL)
278 {
279 status=MagickFalse;
280 continue;
281 }
282 indexes=GetCacheViewVirtualIndexQueue(source->view);
cristyc3ebda22010-06-27 17:11:57 +0000283 duplex_pixels=GetCacheViewVirtualPixels(duplex->view,duplex->extent.x,y,
284 duplex->extent.width,1,duplex->exception);
cristy3ed852e2009-09-05 21:47:34 +0000285 if (duplex_pixels == (const PixelPacket *) NULL)
286 {
287 status=MagickFalse;
288 continue;
289 }
290 duplex_indexes=GetCacheViewVirtualIndexQueue(duplex->view);
cristy3ed852e2009-09-05 21:47:34 +0000291 destination_pixels=GetCacheViewAuthenticPixels(destination->view,
cristyc3ebda22010-06-27 17:11:57 +0000292 destination->extent.x,y,destination->extent.width,1,exception);
cristy3ed852e2009-09-05 21:47:34 +0000293 if (destination_pixels == (PixelPacket *) NULL)
294 {
295 status=MagickFalse;
296 continue;
297 }
298 destination_indexes=GetCacheViewAuthenticIndexQueue(destination->view);
cristyc3ebda22010-06-27 17:11:57 +0000299 if (transfer(source,duplex,destination,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000300 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000301 sync=SyncCacheViewAuthenticPixels(destination->view,exception);
302 if (sync == MagickFalse)
303 {
304 InheritException(destination->exception,GetCacheViewException(
305 source->view));
306 status=MagickFalse;
307 }
308 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
309 {
310 MagickBooleanType
311 proceed;
312
cristyb5d5f722009-11-04 03:03:49 +0000313#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy7eb1b7a2010-06-26 15:47:49 +0000314 #pragma omp critical (MagickCore_DuplexTransferImageViewIterator)
cristy3ed852e2009-09-05 21:47:34 +0000315#endif
cristyc3ebda22010-06-27 17:11:57 +0000316 proceed=SetImageProgress(source_image,source->description,progress++,
317 source->extent.height);
cristy3ed852e2009-09-05 21:47:34 +0000318 if (proceed == MagickFalse)
319 status=MagickFalse;
320 }
321 }
322 return(status);
323}
324
325/*
326%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
327% %
328% %
329% %
cristycc34c492010-06-26 23:49:12 +0000330% 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 %
331% %
332% %
333% %
334%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
335%
cristy73b7d4c2010-06-27 00:31:00 +0000336% GetImageViewAuthenticIndexes() returns the image view authentic indexes.
cristycc34c492010-06-26 23:49:12 +0000337%
338% The format of the GetImageViewAuthenticPixels method is:
339%
cristy73b7d4c2010-06-27 00:31:00 +0000340% IndexPacket *GetImageViewAuthenticIndexes(const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000341%
342% A description of each parameter follows:
343%
cristy73b7d4c2010-06-27 00:31:00 +0000344% o image_view: the image view.
cristycc34c492010-06-26 23:49:12 +0000345%
346*/
347MagickExport IndexPacket *GetImageViewAuthenticIndexes(
cristy73b7d4c2010-06-27 00:31:00 +0000348 const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000349{
cristy73b7d4c2010-06-27 00:31:00 +0000350 assert(image_view != (ImageView *) NULL);
351 assert(image_view->signature == MagickSignature);
352 return(GetCacheViewAuthenticIndexQueue(image_view->view));
cristycc34c492010-06-26 23:49:12 +0000353}
354
355/*
356%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
357% %
358% %
359% %
360% 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 %
361% %
362% %
363% %
364%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
365%
cristy73b7d4c2010-06-27 00:31:00 +0000366% GetImageViewAuthenticPixels() returns the image view authentic pixels.
cristycc34c492010-06-26 23:49:12 +0000367%
368% The format of the GetImageViewAuthenticPixels method is:
369%
cristy73b7d4c2010-06-27 00:31:00 +0000370% PixelPacket *GetImageViewAuthenticPixels(const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000371%
372% A description of each parameter follows:
373%
cristy73b7d4c2010-06-27 00:31:00 +0000374% o image_view: the image view.
cristycc34c492010-06-26 23:49:12 +0000375%
376*/
377MagickExport PixelPacket *GetImageViewAuthenticPixels(
cristy73b7d4c2010-06-27 00:31:00 +0000378 const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000379{
cristy73b7d4c2010-06-27 00:31:00 +0000380 assert(image_view != (ImageView *) NULL);
381 assert(image_view->signature == MagickSignature);
382 return(GetCacheViewAuthenticPixelQueue(image_view->view));
cristycc34c492010-06-26 23:49:12 +0000383}
384
385/*
386%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
387% %
388% %
389% %
cristy7eb1b7a2010-06-26 15:47:49 +0000390% 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 +0000391% %
392% %
393% %
394%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
395%
cristy7eb1b7a2010-06-26 15:47:49 +0000396% GetImageViewException() returns the severity, reason, and description of any
cristy73b7d4c2010-06-27 00:31:00 +0000397% error that occurs when utilizing a image view.
cristy3ed852e2009-09-05 21:47:34 +0000398%
cristy7eb1b7a2010-06-26 15:47:49 +0000399% The format of the GetImageViewException method is:
cristy3ed852e2009-09-05 21:47:34 +0000400%
cristy73b7d4c2010-06-27 00:31:00 +0000401% char *GetImageViewException(const PixelImage *image_view,
cristy3ed852e2009-09-05 21:47:34 +0000402% ExceptionType *severity)
403%
404% A description of each parameter follows:
405%
cristy73b7d4c2010-06-27 00:31:00 +0000406% o image_view: the pixel image_view.
cristy3ed852e2009-09-05 21:47:34 +0000407%
408% o severity: the severity of the error is returned here.
409%
410*/
cristy73b7d4c2010-06-27 00:31:00 +0000411MagickExport char *GetImageViewException(const ImageView *image_view,
cristy3ed852e2009-09-05 21:47:34 +0000412 ExceptionType *severity)
413{
414 char
415 *description;
416
cristy73b7d4c2010-06-27 00:31:00 +0000417 assert(image_view != (const ImageView *) NULL);
418 assert(image_view->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +0000419 assert(severity != (ExceptionType *) NULL);
cristy73b7d4c2010-06-27 00:31:00 +0000420 *severity=image_view->exception->severity;
cristy3ed852e2009-09-05 21:47:34 +0000421 description=(char *) AcquireQuantumMemory(2UL*MaxTextExtent,
422 sizeof(*description));
423 if (description == (char *) NULL)
cristy7eb1b7a2010-06-26 15:47:49 +0000424 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000425 *description='\0';
cristy73b7d4c2010-06-27 00:31:00 +0000426 if (image_view->exception->reason != (char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000427 (void) CopyMagickString(description,GetLocaleExceptionMessage(
cristy73b7d4c2010-06-27 00:31:00 +0000428 image_view->exception->severity,image_view->exception->reason),
cristy3ed852e2009-09-05 21:47:34 +0000429 MaxTextExtent);
cristy73b7d4c2010-06-27 00:31:00 +0000430 if (image_view->exception->description != (char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000431 {
432 (void) ConcatenateMagickString(description," (",MaxTextExtent);
433 (void) ConcatenateMagickString(description,GetLocaleExceptionMessage(
cristy73b7d4c2010-06-27 00:31:00 +0000434 image_view->exception->severity,image_view->exception->description),
cristy3ed852e2009-09-05 21:47:34 +0000435 MaxTextExtent);
436 (void) ConcatenateMagickString(description,")",MaxTextExtent);
437 }
438 return(description);
439}
440
441/*
442%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
443% %
444% %
445% %
cristyc3ebda22010-06-27 17:11:57 +0000446% G e t I m a g e V i e w E x t e n t %
cristy3ed852e2009-09-05 21:47:34 +0000447% %
448% %
449% %
450%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
451%
cristyc3ebda22010-06-27 17:11:57 +0000452% GetImageViewExtent() returns the image view extent.
cristy3ed852e2009-09-05 21:47:34 +0000453%
cristyc3ebda22010-06-27 17:11:57 +0000454% The format of the GetImageViewExtent method is:
cristy3ed852e2009-09-05 21:47:34 +0000455%
cristyc3ebda22010-06-27 17:11:57 +0000456% RectangleInfo GetImageViewExtent(const ImageView *image_view)
cristy3ed852e2009-09-05 21:47:34 +0000457%
458% A description of each parameter follows:
459%
cristy73b7d4c2010-06-27 00:31:00 +0000460% o image_view: the image view.
cristy3ed852e2009-09-05 21:47:34 +0000461%
462*/
cristyc3ebda22010-06-27 17:11:57 +0000463MagickExport RectangleInfo GetImageViewExtent(const ImageView *image_view)
cristy3ed852e2009-09-05 21:47:34 +0000464{
cristy73b7d4c2010-06-27 00:31:00 +0000465 assert(image_view != (ImageView *) NULL);
466 assert(image_view->signature == MagickSignature);
cristyc3ebda22010-06-27 17:11:57 +0000467 return(image_view->extent);
cristy73b7d4c2010-06-27 00:31:00 +0000468}
469
470/*
471%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
472% %
473% %
474% %
475% G e t I m a g e V i e w I m a g e %
476% %
477% %
478% %
479%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
480%
481% GetImageViewImage() returns the image associated with the image view.
482%
483% The format of the GetImageViewImage method is:
484%
485% MagickCore *GetImageViewImage(const ImageView *image_view)
486%
487% A description of each parameter follows:
488%
489% o image_view: the image view.
490%
491*/
492MagickExport Image *GetImageViewImage(const ImageView *image_view)
493{
494 assert(image_view != (ImageView *) NULL);
495 assert(image_view->signature == MagickSignature);
496 return(image_view->image);
cristy3ed852e2009-09-05 21:47:34 +0000497}
498
499/*
500%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
501% %
502% %
503% %
cristy7eb1b7a2010-06-26 15:47:49 +0000504% 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 +0000505% %
506% %
507% %
508%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
509%
cristy73b7d4c2010-06-27 00:31:00 +0000510% GetImageViewIterator() iterates over the image view in parallel and calls
cristyc3ebda22010-06-27 17:11:57 +0000511% your get method for each scanline of the view. The pixel extent is
cristy3ed852e2009-09-05 21:47:34 +0000512% not confined to the image canvas-- that is you can include negative offsets
513% or widths or heights that exceed the image dimension. Any updates to
514% the pixels in your callback are ignored.
515%
cristyd6dfc0d2010-06-27 19:30:49 +0000516% The callback signature is:
517%
518% MagickBooleanType GetImageViewMethod(const ImageView *source,
519% const ssize_t y,const int thread_id,void *context)
520%
cristy58739472010-06-26 20:27:18 +0000521% Use this pragma if the view is not single threaded:
cristy3ed852e2009-09-05 21:47:34 +0000522%
523% #pragma omp critical
524%
525% to define a section of code in your callback get method that must be
526% executed by a single thread at a time.
527%
cristy7eb1b7a2010-06-26 15:47:49 +0000528% The format of the GetImageViewIterator method is:
cristy3ed852e2009-09-05 21:47:34 +0000529%
cristy7eb1b7a2010-06-26 15:47:49 +0000530% MagickBooleanType GetImageViewIterator(ImageView *source,
531% GetImageViewMethod get,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000532%
533% A description of each parameter follows:
534%
cristy73b7d4c2010-06-27 00:31:00 +0000535% o source: the source image view.
cristy3ed852e2009-09-05 21:47:34 +0000536%
537% o get: the get callback method.
538%
539% o context: the user defined context.
540%
541*/
cristy7eb1b7a2010-06-26 15:47:49 +0000542MagickExport MagickBooleanType GetImageViewIterator(ImageView *source,
543 GetImageViewMethod get,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000544{
cristy3ed852e2009-09-05 21:47:34 +0000545 Image
546 *source_image;
547
cristy3ed852e2009-09-05 21:47:34 +0000548 MagickBooleanType
549 status;
550
cristycee97112010-05-28 00:44:52 +0000551 MagickOffsetType
552 progress;
553
554 ssize_t
555 y;
556
cristy7eb1b7a2010-06-26 15:47:49 +0000557 assert(source != (ImageView *) NULL);
558 assert(source->signature == MagickSignature);
559 if (get == (GetImageViewMethod) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000560 return(MagickFalse);
cristy7eb1b7a2010-06-26 15:47:49 +0000561 source_image=source->image;
cristy3ed852e2009-09-05 21:47:34 +0000562 status=MagickTrue;
563 progress=0;
cristyb5d5f722009-11-04 03:03:49 +0000564#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy309f6132010-06-07 13:19:01 +0000565 #pragma omp parallel for schedule(static,1) shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +0000566#endif
cristyc3ebda22010-06-27 17:11:57 +0000567 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
cristy3ed852e2009-09-05 21:47:34 +0000568 {
cristyad740052010-07-03 01:38:03 +0000569 int
570 id;
571
cristy3ed852e2009-09-05 21:47:34 +0000572 register const IndexPacket
573 *indexes;
574
575 register const PixelPacket
576 *pixels;
577
cristy3ed852e2009-09-05 21:47:34 +0000578 if (status == MagickFalse)
579 continue;
580 id=GetOpenMPThreadId();
cristyc3ebda22010-06-27 17:11:57 +0000581 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
582 source->extent.width,1,source->exception);
cristy3ed852e2009-09-05 21:47:34 +0000583 if (pixels == (const PixelPacket *) NULL)
584 {
585 status=MagickFalse;
586 continue;
587 }
588 indexes=GetCacheViewVirtualIndexQueue(source->view);
cristyd6dfc0d2010-06-27 19:30:49 +0000589 if (get(source,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000590 status=MagickFalse;
591 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
592 {
593 MagickBooleanType
594 proceed;
595
cristyb5d5f722009-11-04 03:03:49 +0000596#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy7eb1b7a2010-06-26 15:47:49 +0000597 #pragma omp critical (MagickCore_GetImageViewIterator)
cristy3ed852e2009-09-05 21:47:34 +0000598#endif
cristyc3ebda22010-06-27 17:11:57 +0000599 proceed=SetImageProgress(source_image,source->description,progress++,
600 source->extent.height);
cristy3ed852e2009-09-05 21:47:34 +0000601 if (proceed == MagickFalse)
602 status=MagickFalse;
603 }
604 }
605 return(status);
606}
607
608/*
609%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
610% %
611% %
612% %
cristycc34c492010-06-26 23:49:12 +0000613% 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 %
614% %
615% %
616% %
617%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
618%
cristy73b7d4c2010-06-27 00:31:00 +0000619% GetImageViewVirtualIndexes() returns the image view virtual indexes.
cristycc34c492010-06-26 23:49:12 +0000620%
cristy73b7d4c2010-06-27 00:31:00 +0000621% The format of the GetImageViewVirtualIndexes method is:
cristycc34c492010-06-26 23:49:12 +0000622%
623% const IndexPacket *GetImageViewVirtualIndexes(
cristy73b7d4c2010-06-27 00:31:00 +0000624% const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000625%
626% A description of each parameter follows:
627%
cristy73b7d4c2010-06-27 00:31:00 +0000628% o image_view: the image view.
cristycc34c492010-06-26 23:49:12 +0000629%
630*/
631MagickExport const IndexPacket *GetImageViewVirtualIndexes(
cristy73b7d4c2010-06-27 00:31:00 +0000632 const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000633{
cristy73b7d4c2010-06-27 00:31:00 +0000634 assert(image_view != (ImageView *) NULL);
635 assert(image_view->signature == MagickSignature);
636 return(GetCacheViewVirtualIndexQueue(image_view->view));
cristycc34c492010-06-26 23:49:12 +0000637}
638
639/*
640%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
641% %
642% %
643% %
644% 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 %
645% %
646% %
647% %
648%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
649%
cristy73b7d4c2010-06-27 00:31:00 +0000650% GetImageViewVirtualPixels() returns the image view virtual pixels.
cristycc34c492010-06-26 23:49:12 +0000651%
652% The format of the GetImageViewVirtualPixels method is:
653%
cristy73b7d4c2010-06-27 00:31:00 +0000654% const PixelPacket *GetImageViewVirtualPixels(const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000655%
656% A description of each parameter follows:
657%
cristy73b7d4c2010-06-27 00:31:00 +0000658% o image_view: the image view.
cristycc34c492010-06-26 23:49:12 +0000659%
660*/
661MagickExport const PixelPacket *GetImageViewVirtualPixels(
cristy73b7d4c2010-06-27 00:31:00 +0000662 const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000663{
cristy73b7d4c2010-06-27 00:31:00 +0000664 assert(image_view != (ImageView *) NULL);
665 assert(image_view->signature == MagickSignature);
666 return(GetCacheViewVirtualPixelQueue(image_view->view));
cristycc34c492010-06-26 23:49:12 +0000667}
668
669/*
670%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
671% %
672% %
673% %
cristy7eb1b7a2010-06-26 15:47:49 +0000674% I s I m a g e V i e w %
cristy3ed852e2009-09-05 21:47:34 +0000675% %
676% %
677% %
678%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
679%
cristy73b7d4c2010-06-27 00:31:00 +0000680% IsImageView() returns MagickTrue if the the parameter is verified as a image
681% view object.
cristy3ed852e2009-09-05 21:47:34 +0000682%
cristy7eb1b7a2010-06-26 15:47:49 +0000683% The format of the IsImageView method is:
cristy3ed852e2009-09-05 21:47:34 +0000684%
cristy73b7d4c2010-06-27 00:31:00 +0000685% MagickBooleanType IsImageView(const ImageView *image_view)
cristy3ed852e2009-09-05 21:47:34 +0000686%
687% A description of each parameter follows:
688%
cristy73b7d4c2010-06-27 00:31:00 +0000689% o image_view: the image view.
cristy3ed852e2009-09-05 21:47:34 +0000690%
691*/
cristy73b7d4c2010-06-27 00:31:00 +0000692MagickExport MagickBooleanType IsImageView(const ImageView *image_view)
cristy3ed852e2009-09-05 21:47:34 +0000693{
cristy73b7d4c2010-06-27 00:31:00 +0000694 if (image_view == (const ImageView *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000695 return(MagickFalse);
cristy73b7d4c2010-06-27 00:31:00 +0000696 if (image_view->signature != MagickSignature)
cristy3ed852e2009-09-05 21:47:34 +0000697 return(MagickFalse);
698 return(MagickTrue);
699}
700
701/*
702%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
703% %
704% %
705% %
cristy7eb1b7a2010-06-26 15:47:49 +0000706% N e w I m a g e V i e w %
cristy3ed852e2009-09-05 21:47:34 +0000707% %
708% %
709% %
710%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
711%
cristy73b7d4c2010-06-27 00:31:00 +0000712% NewImageView() returns a image view required for all other methods in the
713% Image View API.
cristy3ed852e2009-09-05 21:47:34 +0000714%
cristy7eb1b7a2010-06-26 15:47:49 +0000715% The format of the NewImageView method is:
cristy3ed852e2009-09-05 21:47:34 +0000716%
cristy7eb1b7a2010-06-26 15:47:49 +0000717% ImageView *NewImageView(MagickCore *wand)
cristy3ed852e2009-09-05 21:47:34 +0000718%
719% A description of each parameter follows:
720%
721% o wand: the wand.
722%
723*/
cristy7eb1b7a2010-06-26 15:47:49 +0000724MagickExport ImageView *NewImageView(Image *image)
cristy3ed852e2009-09-05 21:47:34 +0000725{
cristy7eb1b7a2010-06-26 15:47:49 +0000726 ImageView
cristy73b7d4c2010-06-27 00:31:00 +0000727 *image_view;
cristy3ed852e2009-09-05 21:47:34 +0000728
cristy7eb1b7a2010-06-26 15:47:49 +0000729 assert(image != (Image *) NULL);
730 assert(image->signature == MagickSignature);
cristy73b7d4c2010-06-27 00:31:00 +0000731 image_view=(ImageView *) AcquireAlignedMemory(1,sizeof(*image_view));
732 if (image_view == (ImageView *) NULL)
cristy7eb1b7a2010-06-26 15:47:49 +0000733 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy73b7d4c2010-06-27 00:31:00 +0000734 (void) ResetMagickMemory(image_view,0,sizeof(*image_view));
cristyc3ebda22010-06-27 17:11:57 +0000735 image_view->description=ConstantString("ImageView");
cristy73b7d4c2010-06-27 00:31:00 +0000736 image_view->image=image;
737 image_view->view=AcquireCacheView(image_view->image);
cristyc3ebda22010-06-27 17:11:57 +0000738 image_view->extent.width=image->columns;
739 image_view->extent.height=image->rows;
740 image_view->extent.x=0;
741 image_view->extent.y=0;
cristy73b7d4c2010-06-27 00:31:00 +0000742 image_view->number_threads=GetOpenMPMaximumThreads();
cristyc3ebda22010-06-27 17:11:57 +0000743 image_view->exception=AcquireExceptionInfo();
cristy73b7d4c2010-06-27 00:31:00 +0000744 image_view->debug=IsEventLogging();
745 image_view->signature=MagickSignature;
746 return(image_view);
cristy3ed852e2009-09-05 21:47:34 +0000747}
748
749/*
750%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
751% %
752% %
753% %
cristy7eb1b7a2010-06-26 15:47:49 +0000754% N e w I m a g e V i e w R e g i o n %
cristy3ed852e2009-09-05 21:47:34 +0000755% %
756% %
757% %
758%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
759%
cristy73b7d4c2010-06-27 00:31:00 +0000760% NewImageViewRegion() returns a image view required for all other methods
761% in the Image View API.
cristy3ed852e2009-09-05 21:47:34 +0000762%
cristy7eb1b7a2010-06-26 15:47:49 +0000763% The format of the NewImageViewRegion method is:
cristy3ed852e2009-09-05 21:47:34 +0000764%
cristy7eb1b7a2010-06-26 15:47:49 +0000765% ImageView *NewImageViewRegion(MagickCore *wand,const ssize_t x,
cristybb503372010-05-27 20:51:26 +0000766% const ssize_t y,const size_t width,const size_t height)
cristy3ed852e2009-09-05 21:47:34 +0000767%
768% A description of each parameter follows:
769%
770% o wand: the magick wand.
771%
cristyc3ebda22010-06-27 17:11:57 +0000772% o x,y,columns,rows: These values define the perimeter of a extent of
cristy3ed852e2009-09-05 21:47:34 +0000773% pixel_wands view.
774%
775*/
cristy7eb1b7a2010-06-26 15:47:49 +0000776MagickExport ImageView *NewImageViewRegion(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +0000777 const ssize_t y,const size_t width,const size_t height)
cristy3ed852e2009-09-05 21:47:34 +0000778{
cristy7eb1b7a2010-06-26 15:47:49 +0000779 ImageView
cristy73b7d4c2010-06-27 00:31:00 +0000780 *image_view;
cristy3ed852e2009-09-05 21:47:34 +0000781
cristy7eb1b7a2010-06-26 15:47:49 +0000782 assert(image != (Image *) NULL);
783 assert(image->signature == MagickSignature);
cristy73b7d4c2010-06-27 00:31:00 +0000784 image_view=(ImageView *) AcquireAlignedMemory(1,sizeof(*image_view));
785 if (image_view == (ImageView *) NULL)
cristy7eb1b7a2010-06-26 15:47:49 +0000786 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy73b7d4c2010-06-27 00:31:00 +0000787 (void) ResetMagickMemory(image_view,0,sizeof(*image_view));
cristyc3ebda22010-06-27 17:11:57 +0000788 image_view->description=ConstantString("ImageView");
cristy73b7d4c2010-06-27 00:31:00 +0000789 image_view->view=AcquireCacheView(image_view->image);
790 image_view->image=image;
cristyc3ebda22010-06-27 17:11:57 +0000791 image_view->extent.width=width;
792 image_view->extent.height=height;
793 image_view->extent.x=x;
794 image_view->extent.y=y;
cristy73b7d4c2010-06-27 00:31:00 +0000795 image_view->number_threads=GetOpenMPMaximumThreads();
cristyc3ebda22010-06-27 17:11:57 +0000796 image_view->exception=AcquireExceptionInfo();
cristy73b7d4c2010-06-27 00:31:00 +0000797 image_view->debug=IsEventLogging();
798 image_view->signature=MagickSignature;
799 return(image_view);
cristy3ed852e2009-09-05 21:47:34 +0000800}
801
802/*
803%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
804% %
805% %
806% %
cristyc3ebda22010-06-27 17:11:57 +0000807% S e t I m a g e V i e w D e s c r i p t i o n %
808% %
809% %
810% %
811%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
812%
813% SetImageViewDescription() associates a description with an image view.
814%
815% The format of the SetImageViewDescription method is:
816%
817% void SetImageViewDescription(ImageView *image_view,
818% const char *description)
819%
820% A description of each parameter follows:
821%
822% o image_view: the image view.
823%
824% o description: the image view description.
825%
826*/
827MagickExport void SetImageViewDescription(ImageView *image_view,
828 const char *description)
829{
830 assert(image_view != (ImageView *) NULL);
831 assert(image_view->signature == MagickSignature);
832 image_view->description=ConstantString(description);
833}
834
835/*
836%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
837% %
838% %
839% %
cristy7eb1b7a2010-06-26 15:47:49 +0000840% 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 +0000841% %
842% %
843% %
844%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
845%
cristy73b7d4c2010-06-27 00:31:00 +0000846% SetImageViewIterator() iterates over the image view in parallel and calls
cristyc3ebda22010-06-27 17:11:57 +0000847% your set method for each scanline of the view. The pixel extent is
cristy3ed852e2009-09-05 21:47:34 +0000848% confined to the image canvas-- that is no negative offsets or widths or
849% heights that exceed the image dimension. The pixels are initiallly
850% undefined and any settings you make in the callback method are automagically
851% synced back to your image.
852%
cristyd6dfc0d2010-06-27 19:30:49 +0000853% The callback signature is:
854%
855% MagickBooleanType SetImageViewMethod(ImageView *destination,
856% const ssize_t y,const int thread_id,void *context)
857%
cristy58739472010-06-26 20:27:18 +0000858% Use this pragma if the view is not single threaded:
cristy3ed852e2009-09-05 21:47:34 +0000859%
860% #pragma omp critical
861%
862% to define a section of code in your callback set method that must be
863% executed by a single thread at a time.
864%
cristy7eb1b7a2010-06-26 15:47:49 +0000865% The format of the SetImageViewIterator method is:
cristy3ed852e2009-09-05 21:47:34 +0000866%
cristy7eb1b7a2010-06-26 15:47:49 +0000867% MagickBooleanType SetImageViewIterator(ImageView *destination,
868% SetImageViewMethod set,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000869%
870% A description of each parameter follows:
871%
cristy73b7d4c2010-06-27 00:31:00 +0000872% o destination: the image view.
cristy3ed852e2009-09-05 21:47:34 +0000873%
874% o set: the set callback method.
875%
876% o context: the user defined context.
877%
878*/
cristy7eb1b7a2010-06-26 15:47:49 +0000879MagickExport MagickBooleanType SetImageViewIterator(ImageView *destination,
880 SetImageViewMethod set,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000881{
cristy3ed852e2009-09-05 21:47:34 +0000882 ExceptionInfo
883 *exception;
884
885 Image
886 *destination_image;
887
cristy3ed852e2009-09-05 21:47:34 +0000888 MagickBooleanType
889 status;
890
cristycee97112010-05-28 00:44:52 +0000891 MagickOffsetType
892 progress;
893
894 ssize_t
895 y;
896
cristy7eb1b7a2010-06-26 15:47:49 +0000897 assert(destination != (ImageView *) NULL);
898 assert(destination->signature == MagickSignature);
899 if (set == (SetImageViewMethod) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000900 return(MagickFalse);
cristy7eb1b7a2010-06-26 15:47:49 +0000901 destination_image=destination->image;
cristy3ed852e2009-09-05 21:47:34 +0000902 if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
903 return(MagickFalse);
904 status=MagickTrue;
905 progress=0;
906 exception=destination->exception;
cristyb5d5f722009-11-04 03:03:49 +0000907#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy309f6132010-06-07 13:19:01 +0000908 #pragma omp parallel for schedule(static,1) shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +0000909#endif
cristyc3ebda22010-06-27 17:11:57 +0000910 for (y=destination->extent.y; y < (ssize_t) destination->extent.height; y++)
cristy3ed852e2009-09-05 21:47:34 +0000911 {
cristyad740052010-07-03 01:38:03 +0000912 int
913 id;
914
cristy3ed852e2009-09-05 21:47:34 +0000915 MagickBooleanType
916 sync;
917
918 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000919 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +0000920
cristy3ed852e2009-09-05 21:47:34 +0000921 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000922 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000923
924 if (status == MagickFalse)
925 continue;
926 id=GetOpenMPThreadId();
cristyc3ebda22010-06-27 17:11:57 +0000927 pixels=GetCacheViewAuthenticPixels(destination->view,destination->extent.x,
928 y,destination->extent.width,1,exception);
cristy3ed852e2009-09-05 21:47:34 +0000929 if (pixels == (PixelPacket *) NULL)
930 {
931 InheritException(destination->exception,GetCacheViewException(
932 destination->view));
933 status=MagickFalse;
934 continue;
935 }
936 indexes=GetCacheViewAuthenticIndexQueue(destination->view);
cristyd6dfc0d2010-06-27 19:30:49 +0000937 if (set(destination,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000938 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000939 sync=SyncCacheViewAuthenticPixels(destination->view,exception);
940 if (sync == MagickFalse)
941 {
942 InheritException(destination->exception,GetCacheViewException(
943 destination->view));
944 status=MagickFalse;
945 }
946 if (destination_image->progress_monitor != (MagickProgressMonitor) NULL)
947 {
948 MagickBooleanType
949 proceed;
950
cristyb5d5f722009-11-04 03:03:49 +0000951#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy7eb1b7a2010-06-26 15:47:49 +0000952 #pragma omp critical (MagickCore_SetImageViewIterator)
cristy3ed852e2009-09-05 21:47:34 +0000953#endif
cristyc3ebda22010-06-27 17:11:57 +0000954 proceed=SetImageProgress(destination_image,destination->description,
955 progress++,destination->extent.height);
cristy3ed852e2009-09-05 21:47:34 +0000956 if (proceed == MagickFalse)
957 status=MagickFalse;
958 }
959 }
960 return(status);
961}
962
963/*
964%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
965% %
966% %
967% %
cristy7eb1b7a2010-06-26 15:47:49 +0000968% 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 +0000969% %
970% %
971% %
972%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
973%
cristy73b7d4c2010-06-27 00:31:00 +0000974% TransferImageViewIterator() iterates over two image views in parallel and
cristy3ed852e2009-09-05 21:47:34 +0000975% calls your transfer method for each scanline of the view. The source pixel
cristyc3ebda22010-06-27 17:11:57 +0000976% extent is not confined to the image canvas-- that is you can include
cristy3ed852e2009-09-05 21:47:34 +0000977% negative offsets or widths or heights that exceed the image dimension.
cristy73b7d4c2010-06-27 00:31:00 +0000978% However, the destination image view is confined to the image canvas-- that
cristy3ed852e2009-09-05 21:47:34 +0000979% is no negative offsets or widths or heights that exceed the image dimension
980% are permitted.
981%
cristyd6dfc0d2010-06-27 19:30:49 +0000982% The callback signature is:
983%
984% MagickBooleanType TransferImageViewMethod(const ImageView *source,
985% ImageView *destination,const ssize_t y,const int thread_id,
986% void *context)
987%
cristy58739472010-06-26 20:27:18 +0000988% Use this pragma if the view is not single threaded:
cristy3ed852e2009-09-05 21:47:34 +0000989%
990% #pragma omp critical
991%
992% to define a section of code in your callback transfer method that must be
993% executed by a single thread at a time.
994%
cristy7eb1b7a2010-06-26 15:47:49 +0000995% The format of the TransferImageViewIterator method is:
cristy3ed852e2009-09-05 21:47:34 +0000996%
cristy7eb1b7a2010-06-26 15:47:49 +0000997% MagickBooleanType TransferImageViewIterator(ImageView *source,
998% ImageView *destination,TransferImageViewMethod transfer,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000999%
1000% A description of each parameter follows:
1001%
cristy73b7d4c2010-06-27 00:31:00 +00001002% o source: the source image view.
cristy3ed852e2009-09-05 21:47:34 +00001003%
cristy73b7d4c2010-06-27 00:31:00 +00001004% o destination: the destination image view.
cristy3ed852e2009-09-05 21:47:34 +00001005%
1006% o transfer: the transfer callback method.
1007%
1008% o context: the user defined context.
1009%
1010*/
cristy7eb1b7a2010-06-26 15:47:49 +00001011MagickExport MagickBooleanType TransferImageViewIterator(ImageView *source,
1012 ImageView *destination,TransferImageViewMethod transfer,void *context)
cristy3ed852e2009-09-05 21:47:34 +00001013{
cristy3ed852e2009-09-05 21:47:34 +00001014 ExceptionInfo
1015 *exception;
1016
1017 Image
1018 *destination_image,
1019 *source_image;
1020
cristy3ed852e2009-09-05 21:47:34 +00001021 MagickBooleanType
1022 status;
1023
cristycee97112010-05-28 00:44:52 +00001024 MagickOffsetType
1025 progress;
1026
1027 ssize_t
1028 y;
1029
cristy7eb1b7a2010-06-26 15:47:49 +00001030 assert(source != (ImageView *) NULL);
1031 assert(source->signature == MagickSignature);
1032 if (transfer == (TransferImageViewMethod) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001033 return(MagickFalse);
cristy7eb1b7a2010-06-26 15:47:49 +00001034 source_image=source->image;
1035 destination_image=destination->image;
cristy3ed852e2009-09-05 21:47:34 +00001036 if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
1037 return(MagickFalse);
1038 status=MagickTrue;
1039 progress=0;
1040 exception=destination->exception;
cristyb5d5f722009-11-04 03:03:49 +00001041#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy309f6132010-06-07 13:19:01 +00001042 #pragma omp parallel for schedule(static,1) shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +00001043#endif
cristyc3ebda22010-06-27 17:11:57 +00001044 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
cristy3ed852e2009-09-05 21:47:34 +00001045 {
cristyad740052010-07-03 01:38:03 +00001046 int
1047 id;
1048
cristy3ed852e2009-09-05 21:47:34 +00001049 MagickBooleanType
1050 sync;
1051
1052 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00001053 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00001054
1055 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001056 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001057
1058 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00001059 *restrict destination_indexes;
cristy3ed852e2009-09-05 21:47:34 +00001060
cristy3ed852e2009-09-05 21:47:34 +00001061 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001062 *restrict destination_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001063
1064 if (status == MagickFalse)
1065 continue;
1066 id=GetOpenMPThreadId();
cristyc3ebda22010-06-27 17:11:57 +00001067 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
1068 source->extent.width,1,source->exception);
cristy3ed852e2009-09-05 21:47:34 +00001069 if (pixels == (const PixelPacket *) NULL)
1070 {
1071 status=MagickFalse;
1072 continue;
1073 }
1074 indexes=GetCacheViewVirtualIndexQueue(source->view);
cristy3ed852e2009-09-05 21:47:34 +00001075 destination_pixels=GetCacheViewAuthenticPixels(destination->view,
cristyc3ebda22010-06-27 17:11:57 +00001076 destination->extent.x,y,destination->extent.width,1,exception);
cristy3ed852e2009-09-05 21:47:34 +00001077 if (destination_pixels == (PixelPacket *) NULL)
1078 {
1079 status=MagickFalse;
1080 continue;
1081 }
1082 destination_indexes=GetCacheViewAuthenticIndexQueue(destination->view);
cristyc3ebda22010-06-27 17:11:57 +00001083 if (transfer(source,destination,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001084 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00001085 sync=SyncCacheViewAuthenticPixels(destination->view,exception);
1086 if (sync == MagickFalse)
1087 {
1088 InheritException(destination->exception,GetCacheViewException(
1089 source->view));
1090 status=MagickFalse;
1091 }
1092 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1093 {
1094 MagickBooleanType
1095 proceed;
1096
cristyb5d5f722009-11-04 03:03:49 +00001097#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy7eb1b7a2010-06-26 15:47:49 +00001098 #pragma omp critical (MagickCore_TransferImageViewIterator)
cristy3ed852e2009-09-05 21:47:34 +00001099#endif
cristyc3ebda22010-06-27 17:11:57 +00001100 proceed=SetImageProgress(source_image,source->description,progress++,
1101 source->extent.height);
cristy3ed852e2009-09-05 21:47:34 +00001102 if (proceed == MagickFalse)
1103 status=MagickFalse;
1104 }
1105 }
1106 return(status);
1107}
1108
1109/*
1110%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1111% %
1112% %
1113% %
cristy7eb1b7a2010-06-26 15:47:49 +00001114% 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 +00001115% %
1116% %
1117% %
1118%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1119%
cristy73b7d4c2010-06-27 00:31:00 +00001120% UpdateImageViewIterator() iterates over the image view in parallel and calls
cristyc3ebda22010-06-27 17:11:57 +00001121% your update method for each scanline of the view. The pixel extent is
cristy3ed852e2009-09-05 21:47:34 +00001122% confined to the image canvas-- that is no negative offsets or widths or
1123% heights that exceed the image dimension are permitted. Updates to pixels
1124% in your callback are automagically synced back to the image.
1125%
cristyd6dfc0d2010-06-27 19:30:49 +00001126% The callback signature is:
1127%
1128% MagickBooleanType UpdateImageViewMethod(ImageView *source,
1129% const ssize_t y,const int thread_id,void *context)
1130%
cristy58739472010-06-26 20:27:18 +00001131% Use this pragma if the view is not single threaded:
cristy3ed852e2009-09-05 21:47:34 +00001132%
1133% #pragma omp critical
1134%
1135% to define a section of code in your callback update method that must be
1136% executed by a single thread at a time.
1137%
cristy7eb1b7a2010-06-26 15:47:49 +00001138% The format of the UpdateImageViewIterator method is:
cristy3ed852e2009-09-05 21:47:34 +00001139%
cristy7eb1b7a2010-06-26 15:47:49 +00001140% MagickBooleanType UpdateImageViewIterator(ImageView *source,
1141% UpdateImageViewMethod update,void *context)
cristy3ed852e2009-09-05 21:47:34 +00001142%
1143% A description of each parameter follows:
1144%
cristy73b7d4c2010-06-27 00:31:00 +00001145% o source: the source image view.
cristy3ed852e2009-09-05 21:47:34 +00001146%
1147% o update: the update callback method.
1148%
1149% o context: the user defined context.
1150%
1151*/
cristy7eb1b7a2010-06-26 15:47:49 +00001152MagickExport MagickBooleanType UpdateImageViewIterator(ImageView *source,
1153 UpdateImageViewMethod update,void *context)
cristy3ed852e2009-09-05 21:47:34 +00001154{
cristy3ed852e2009-09-05 21:47:34 +00001155 ExceptionInfo
1156 *exception;
1157
1158 Image
1159 *source_image;
1160
cristy3ed852e2009-09-05 21:47:34 +00001161 MagickBooleanType
1162 status;
1163
cristycee97112010-05-28 00:44:52 +00001164 MagickOffsetType
1165 progress;
1166
1167 ssize_t
1168 y;
1169
cristy7eb1b7a2010-06-26 15:47:49 +00001170 assert(source != (ImageView *) NULL);
1171 assert(source->signature == MagickSignature);
1172 if (update == (UpdateImageViewMethod) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001173 return(MagickFalse);
cristy7eb1b7a2010-06-26 15:47:49 +00001174 source_image=source->image;
cristy3ed852e2009-09-05 21:47:34 +00001175 if (SetImageStorageClass(source_image,DirectClass) == MagickFalse)
1176 return(MagickFalse);
1177 status=MagickTrue;
1178 progress=0;
1179 exception=source->exception;
cristyb5d5f722009-11-04 03:03:49 +00001180#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy309f6132010-06-07 13:19:01 +00001181 #pragma omp parallel for schedule(static,1) shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +00001182#endif
cristyc3ebda22010-06-27 17:11:57 +00001183 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
cristy3ed852e2009-09-05 21:47:34 +00001184 {
cristyad740052010-07-03 01:38:03 +00001185 int
1186 id;
1187
cristy3ed852e2009-09-05 21:47:34 +00001188 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00001189 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00001190
cristy3ed852e2009-09-05 21:47:34 +00001191 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001192 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001193
1194 if (status == MagickFalse)
1195 continue;
1196 id=GetOpenMPThreadId();
cristyc3ebda22010-06-27 17:11:57 +00001197 pixels=GetCacheViewAuthenticPixels(source->view,source->extent.x,y,
1198 source->extent.width,1,exception);
cristy3ed852e2009-09-05 21:47:34 +00001199 if (pixels == (PixelPacket *) NULL)
1200 {
cristy73b7d4c2010-06-27 00:31:00 +00001201 InheritException(source->exception,GetCacheViewException(source->view));
cristy3ed852e2009-09-05 21:47:34 +00001202 status=MagickFalse;
1203 continue;
1204 }
1205 indexes=GetCacheViewAuthenticIndexQueue(source->view);
cristyc3ebda22010-06-27 17:11:57 +00001206 if (update(source,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001207 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00001208 if (SyncCacheViewAuthenticPixels(source->view,exception) == MagickFalse)
1209 {
1210 InheritException(source->exception,GetCacheViewException(source->view));
1211 status=MagickFalse;
1212 }
1213 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1214 {
1215 MagickBooleanType
1216 proceed;
1217
cristyb5d5f722009-11-04 03:03:49 +00001218#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy7eb1b7a2010-06-26 15:47:49 +00001219 #pragma omp critical (MagickCore_UpdateImageViewIterator)
cristy3ed852e2009-09-05 21:47:34 +00001220#endif
cristyc3ebda22010-06-27 17:11:57 +00001221 proceed=SetImageProgress(source_image,source->description,progress++,
1222 source->extent.height);
cristy3ed852e2009-09-05 21:47:34 +00001223 if (proceed == MagickFalse)
1224 status=MagickFalse;
1225 }
1226 }
1227 return(status);
1228}