blob: edfa608f3477254a205f8bc3c00844fefa0360e2 [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% %
cristy7e41fe82010-12-04 23:12:08 +000025% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000026% dedicated to making software imaging solutions freely available. %
27% %
28% You may not use this file except in compliance with the License. You may %
29% obtain a copy of the License at %
30% %
31% http://www.imagemagick.org/script/license.php %
32% %
33% Unless required by applicable law or agreed to in writing, software %
34% distributed under the License is distributed on an "AS IS" BASIS, %
35% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
36% See the License for the specific language governing permissions and %
37% limitations under the License. %
38% %
39%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
40%
41%
42%
43*/
44
45/*
46 Include declarations.
47*/
cristy4c08aed2011-07-01 19:47:50 +000048#include "MagickCore/studio.h"
49#include "MagickCore/MagickCore.h"
50#include "MagickCore/exception-private.h"
51#include "MagickCore/monitor-private.h"
52#include "MagickCore/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,
cristy3ed852e2009-09-05 21:47:34 +0000223 *source_image;
224
cristy3ed852e2009-09-05 21:47:34 +0000225 MagickBooleanType
226 status;
227
cristycee97112010-05-28 00:44:52 +0000228 MagickOffsetType
229 progress;
230
231 ssize_t
232 y;
233
cristy7eb1b7a2010-06-26 15:47:49 +0000234 assert(source != (ImageView *) NULL);
235 assert(source->signature == MagickSignature);
236 if (transfer == (DuplexTransferImageViewMethod) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000237 return(MagickFalse);
cristy7eb1b7a2010-06-26 15:47:49 +0000238 source_image=source->image;
cristy7eb1b7a2010-06-26 15:47:49 +0000239 destination_image=destination->image;
cristy47fa6ee2011-08-05 17:35:33 +0000240 exception=destination->exception;
cristy574cc262011-08-05 01:23:58 +0000241 if (SetImageStorageClass(destination_image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000242 return(MagickFalse);
243 status=MagickTrue;
244 progress=0;
cristyb5d5f722009-11-04 03:03:49 +0000245#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy09d81172010-10-21 16:15:05 +0000246 #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(source->number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000247#endif
cristyc3ebda22010-06-27 17:11:57 +0000248 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
cristy3ed852e2009-09-05 21:47:34 +0000249 {
cristy5c9e6f22010-09-17 17:31:01 +0000250 const int
251 id = GetOpenMPThreadId();
cristyad740052010-07-03 01:38:03 +0000252
cristy3ed852e2009-09-05 21:47:34 +0000253 MagickBooleanType
254 sync;
255
cristy4c08aed2011-07-01 19:47:50 +0000256 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +0000257 *restrict duplex_pixels,
258 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000259
cristy4c08aed2011-07-01 19:47:50 +0000260 register Quantum
cristyc47d1f82009-11-26 01:44:43 +0000261 *restrict destination_pixels;
cristy3ed852e2009-09-05 21:47:34 +0000262
263 if (status == MagickFalse)
264 continue;
cristyc3ebda22010-06-27 17:11:57 +0000265 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
266 source->extent.width,1,source->exception);
cristy4c08aed2011-07-01 19:47:50 +0000267 if (pixels == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000268 {
269 status=MagickFalse;
270 continue;
271 }
cristyc3ebda22010-06-27 17:11:57 +0000272 duplex_pixels=GetCacheViewVirtualPixels(duplex->view,duplex->extent.x,y,
273 duplex->extent.width,1,duplex->exception);
cristy4c08aed2011-07-01 19:47:50 +0000274 if (duplex_pixels == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000275 {
276 status=MagickFalse;
277 continue;
278 }
cristy3ed852e2009-09-05 21:47:34 +0000279 destination_pixels=GetCacheViewAuthenticPixels(destination->view,
cristyc3ebda22010-06-27 17:11:57 +0000280 destination->extent.x,y,destination->extent.width,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000281 if (destination_pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000282 {
283 status=MagickFalse;
284 continue;
285 }
cristyc3ebda22010-06-27 17:11:57 +0000286 if (transfer(source,duplex,destination,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000287 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000288 sync=SyncCacheViewAuthenticPixels(destination->view,exception);
289 if (sync == MagickFalse)
290 {
291 InheritException(destination->exception,GetCacheViewException(
292 source->view));
293 status=MagickFalse;
294 }
295 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
296 {
297 MagickBooleanType
298 proceed;
299
cristyb5d5f722009-11-04 03:03:49 +0000300#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy7eb1b7a2010-06-26 15:47:49 +0000301 #pragma omp critical (MagickCore_DuplexTransferImageViewIterator)
cristy3ed852e2009-09-05 21:47:34 +0000302#endif
cristyc3ebda22010-06-27 17:11:57 +0000303 proceed=SetImageProgress(source_image,source->description,progress++,
304 source->extent.height);
cristy3ed852e2009-09-05 21:47:34 +0000305 if (proceed == MagickFalse)
306 status=MagickFalse;
307 }
308 }
309 return(status);
310}
311
312/*
313%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
314% %
315% %
316% %
cristy4c08aed2011-07-01 19:47:50 +0000317% G e t I m a g e V i e w A u t h e n t i c M e t a c o n t e n t %
cristycc34c492010-06-26 23:49:12 +0000318% %
319% %
320% %
321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
322%
cristy4c08aed2011-07-01 19:47:50 +0000323% GetImageViewAuthenticMetacontent() returns the image view authentic
324% meta-content.
cristycc34c492010-06-26 23:49:12 +0000325%
326% The format of the GetImageViewAuthenticPixels method is:
327%
cristy4c08aed2011-07-01 19:47:50 +0000328% void *GetImageViewAuthenticMetacontent(
329% const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000330%
331% A description of each parameter follows:
332%
cristy73b7d4c2010-06-27 00:31:00 +0000333% o image_view: the image view.
cristycc34c492010-06-26 23:49:12 +0000334%
335*/
cristy4c08aed2011-07-01 19:47:50 +0000336MagickExport void *GetImageViewAuthenticMetacontent(
cristy73b7d4c2010-06-27 00:31:00 +0000337 const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000338{
cristy73b7d4c2010-06-27 00:31:00 +0000339 assert(image_view != (ImageView *) NULL);
340 assert(image_view->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +0000341 return(GetCacheViewAuthenticMetacontent(image_view->view));
cristycc34c492010-06-26 23:49:12 +0000342}
343
344/*
345%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
346% %
347% %
348% %
349% 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 %
350% %
351% %
352% %
353%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
354%
cristy73b7d4c2010-06-27 00:31:00 +0000355% GetImageViewAuthenticPixels() returns the image view authentic pixels.
cristycc34c492010-06-26 23:49:12 +0000356%
357% The format of the GetImageViewAuthenticPixels method is:
358%
cristy4c08aed2011-07-01 19:47:50 +0000359% Quantum *GetImageViewAuthenticPixels(const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000360%
361% A description of each parameter follows:
362%
cristy73b7d4c2010-06-27 00:31:00 +0000363% o image_view: the image view.
cristycc34c492010-06-26 23:49:12 +0000364%
365*/
cristy4c08aed2011-07-01 19:47:50 +0000366MagickExport Quantum *GetImageViewAuthenticPixels(
cristy73b7d4c2010-06-27 00:31:00 +0000367 const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000368{
cristy73b7d4c2010-06-27 00:31:00 +0000369 assert(image_view != (ImageView *) NULL);
370 assert(image_view->signature == MagickSignature);
371 return(GetCacheViewAuthenticPixelQueue(image_view->view));
cristycc34c492010-06-26 23:49:12 +0000372}
373
374/*
375%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
376% %
377% %
378% %
cristy7eb1b7a2010-06-26 15:47:49 +0000379% 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 +0000380% %
381% %
382% %
383%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
384%
cristy7eb1b7a2010-06-26 15:47:49 +0000385% GetImageViewException() returns the severity, reason, and description of any
cristy73b7d4c2010-06-27 00:31:00 +0000386% error that occurs when utilizing a image view.
cristy3ed852e2009-09-05 21:47:34 +0000387%
cristy7eb1b7a2010-06-26 15:47:49 +0000388% The format of the GetImageViewException method is:
cristy3ed852e2009-09-05 21:47:34 +0000389%
cristy73b7d4c2010-06-27 00:31:00 +0000390% char *GetImageViewException(const PixelImage *image_view,
cristy3ed852e2009-09-05 21:47:34 +0000391% ExceptionType *severity)
392%
393% A description of each parameter follows:
394%
cristy73b7d4c2010-06-27 00:31:00 +0000395% o image_view: the pixel image_view.
cristy3ed852e2009-09-05 21:47:34 +0000396%
397% o severity: the severity of the error is returned here.
398%
399*/
cristy73b7d4c2010-06-27 00:31:00 +0000400MagickExport char *GetImageViewException(const ImageView *image_view,
cristy3ed852e2009-09-05 21:47:34 +0000401 ExceptionType *severity)
402{
403 char
404 *description;
405
cristy73b7d4c2010-06-27 00:31:00 +0000406 assert(image_view != (const ImageView *) NULL);
407 assert(image_view->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +0000408 assert(severity != (ExceptionType *) NULL);
cristy73b7d4c2010-06-27 00:31:00 +0000409 *severity=image_view->exception->severity;
cristy3ed852e2009-09-05 21:47:34 +0000410 description=(char *) AcquireQuantumMemory(2UL*MaxTextExtent,
411 sizeof(*description));
412 if (description == (char *) NULL)
cristy7eb1b7a2010-06-26 15:47:49 +0000413 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000414 *description='\0';
cristy73b7d4c2010-06-27 00:31:00 +0000415 if (image_view->exception->reason != (char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000416 (void) CopyMagickString(description,GetLocaleExceptionMessage(
cristy73b7d4c2010-06-27 00:31:00 +0000417 image_view->exception->severity,image_view->exception->reason),
cristy3ed852e2009-09-05 21:47:34 +0000418 MaxTextExtent);
cristy73b7d4c2010-06-27 00:31:00 +0000419 if (image_view->exception->description != (char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000420 {
421 (void) ConcatenateMagickString(description," (",MaxTextExtent);
422 (void) ConcatenateMagickString(description,GetLocaleExceptionMessage(
cristy73b7d4c2010-06-27 00:31:00 +0000423 image_view->exception->severity,image_view->exception->description),
cristy3ed852e2009-09-05 21:47:34 +0000424 MaxTextExtent);
425 (void) ConcatenateMagickString(description,")",MaxTextExtent);
426 }
427 return(description);
428}
429
430/*
431%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
432% %
433% %
434% %
cristyc3ebda22010-06-27 17:11:57 +0000435% G e t I m a g e V i e w E x t e n t %
cristy3ed852e2009-09-05 21:47:34 +0000436% %
437% %
438% %
439%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
440%
cristyc3ebda22010-06-27 17:11:57 +0000441% GetImageViewExtent() returns the image view extent.
cristy3ed852e2009-09-05 21:47:34 +0000442%
cristyc3ebda22010-06-27 17:11:57 +0000443% The format of the GetImageViewExtent method is:
cristy3ed852e2009-09-05 21:47:34 +0000444%
cristyc3ebda22010-06-27 17:11:57 +0000445% RectangleInfo GetImageViewExtent(const ImageView *image_view)
cristy3ed852e2009-09-05 21:47:34 +0000446%
447% A description of each parameter follows:
448%
cristy73b7d4c2010-06-27 00:31:00 +0000449% o image_view: the image view.
cristy3ed852e2009-09-05 21:47:34 +0000450%
451*/
cristyc3ebda22010-06-27 17:11:57 +0000452MagickExport RectangleInfo GetImageViewExtent(const ImageView *image_view)
cristy3ed852e2009-09-05 21:47:34 +0000453{
cristy73b7d4c2010-06-27 00:31:00 +0000454 assert(image_view != (ImageView *) NULL);
455 assert(image_view->signature == MagickSignature);
cristyc3ebda22010-06-27 17:11:57 +0000456 return(image_view->extent);
cristy73b7d4c2010-06-27 00:31:00 +0000457}
458
459/*
460%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
461% %
462% %
463% %
464% G e t I m a g e V i e w I m a g e %
465% %
466% %
467% %
468%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
469%
470% GetImageViewImage() returns the image associated with the image view.
471%
472% The format of the GetImageViewImage method is:
473%
474% MagickCore *GetImageViewImage(const ImageView *image_view)
475%
476% A description of each parameter follows:
477%
478% o image_view: the image view.
479%
480*/
481MagickExport Image *GetImageViewImage(const ImageView *image_view)
482{
483 assert(image_view != (ImageView *) NULL);
484 assert(image_view->signature == MagickSignature);
485 return(image_view->image);
cristy3ed852e2009-09-05 21:47:34 +0000486}
487
488/*
489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
490% %
491% %
492% %
cristy7eb1b7a2010-06-26 15:47:49 +0000493% 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 +0000494% %
495% %
496% %
497%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
498%
cristy73b7d4c2010-06-27 00:31:00 +0000499% GetImageViewIterator() iterates over the image view in parallel and calls
cristyc3ebda22010-06-27 17:11:57 +0000500% your get method for each scanline of the view. The pixel extent is
cristy3ed852e2009-09-05 21:47:34 +0000501% not confined to the image canvas-- that is you can include negative offsets
502% or widths or heights that exceed the image dimension. Any updates to
503% the pixels in your callback are ignored.
504%
cristyd6dfc0d2010-06-27 19:30:49 +0000505% The callback signature is:
506%
507% MagickBooleanType GetImageViewMethod(const ImageView *source,
508% const ssize_t y,const int thread_id,void *context)
509%
cristy58739472010-06-26 20:27:18 +0000510% Use this pragma if the view is not single threaded:
cristy3ed852e2009-09-05 21:47:34 +0000511%
512% #pragma omp critical
513%
514% to define a section of code in your callback get method that must be
515% executed by a single thread at a time.
516%
cristy7eb1b7a2010-06-26 15:47:49 +0000517% The format of the GetImageViewIterator method is:
cristy3ed852e2009-09-05 21:47:34 +0000518%
cristy7eb1b7a2010-06-26 15:47:49 +0000519% MagickBooleanType GetImageViewIterator(ImageView *source,
520% GetImageViewMethod get,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000521%
522% A description of each parameter follows:
523%
cristy73b7d4c2010-06-27 00:31:00 +0000524% o source: the source image view.
cristy3ed852e2009-09-05 21:47:34 +0000525%
526% o get: the get callback method.
527%
528% o context: the user defined context.
529%
530*/
cristy7eb1b7a2010-06-26 15:47:49 +0000531MagickExport MagickBooleanType GetImageViewIterator(ImageView *source,
532 GetImageViewMethod get,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000533{
cristy3ed852e2009-09-05 21:47:34 +0000534 Image
535 *source_image;
536
cristy3ed852e2009-09-05 21:47:34 +0000537 MagickBooleanType
538 status;
539
cristycee97112010-05-28 00:44:52 +0000540 MagickOffsetType
541 progress;
542
543 ssize_t
544 y;
545
cristy7eb1b7a2010-06-26 15:47:49 +0000546 assert(source != (ImageView *) NULL);
547 assert(source->signature == MagickSignature);
548 if (get == (GetImageViewMethod) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000549 return(MagickFalse);
cristy7eb1b7a2010-06-26 15:47:49 +0000550 source_image=source->image;
cristy3ed852e2009-09-05 21:47:34 +0000551 status=MagickTrue;
552 progress=0;
cristyb5d5f722009-11-04 03:03:49 +0000553#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy09d81172010-10-21 16:15:05 +0000554 #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(source->number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000555#endif
cristyc3ebda22010-06-27 17:11:57 +0000556 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
cristy3ed852e2009-09-05 21:47:34 +0000557 {
cristy5c9e6f22010-09-17 17:31:01 +0000558 const int
559 id = GetOpenMPThreadId();
cristyad740052010-07-03 01:38:03 +0000560
cristy4c08aed2011-07-01 19:47:50 +0000561 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000562 *pixels;
563
cristy3ed852e2009-09-05 21:47:34 +0000564 if (status == MagickFalse)
565 continue;
cristyc3ebda22010-06-27 17:11:57 +0000566 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
567 source->extent.width,1,source->exception);
cristy4c08aed2011-07-01 19:47:50 +0000568 if (pixels == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000569 {
570 status=MagickFalse;
571 continue;
572 }
cristyd6dfc0d2010-06-27 19:30:49 +0000573 if (get(source,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000574 status=MagickFalse;
575 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
576 {
577 MagickBooleanType
578 proceed;
579
cristyb5d5f722009-11-04 03:03:49 +0000580#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy7eb1b7a2010-06-26 15:47:49 +0000581 #pragma omp critical (MagickCore_GetImageViewIterator)
cristy3ed852e2009-09-05 21:47:34 +0000582#endif
cristyc3ebda22010-06-27 17:11:57 +0000583 proceed=SetImageProgress(source_image,source->description,progress++,
584 source->extent.height);
cristy3ed852e2009-09-05 21:47:34 +0000585 if (proceed == MagickFalse)
586 status=MagickFalse;
587 }
588 }
589 return(status);
590}
591
592/*
593%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
594% %
595% %
596% %
cristy4c08aed2011-07-01 19:47:50 +0000597% G e t I m a g e V i e w V i r t u a l M e t a c o n t e n t %
cristycc34c492010-06-26 23:49:12 +0000598% %
599% %
600% %
601%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
602%
cristy4c08aed2011-07-01 19:47:50 +0000603% GetImageViewVirtualMetacontent() returns the image view virtual
604% meta-content.
cristycc34c492010-06-26 23:49:12 +0000605%
cristy4c08aed2011-07-01 19:47:50 +0000606% The format of the GetImageViewVirtualMetacontent method is:
cristycc34c492010-06-26 23:49:12 +0000607%
cristy4c08aed2011-07-01 19:47:50 +0000608% const void *GetImageViewVirtualMetacontent(
cristy73b7d4c2010-06-27 00:31:00 +0000609% const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000610%
611% A description of each parameter follows:
612%
cristy73b7d4c2010-06-27 00:31:00 +0000613% o image_view: the image view.
cristycc34c492010-06-26 23:49:12 +0000614%
615*/
cristy4c08aed2011-07-01 19:47:50 +0000616MagickExport const void *GetImageViewVirtualMetacontent(
cristy73b7d4c2010-06-27 00:31:00 +0000617 const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000618{
cristy73b7d4c2010-06-27 00:31:00 +0000619 assert(image_view != (ImageView *) NULL);
620 assert(image_view->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +0000621 return(GetCacheViewVirtualMetacontent(image_view->view));
cristycc34c492010-06-26 23:49:12 +0000622}
623
624/*
625%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
626% %
627% %
628% %
629% 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 %
630% %
631% %
632% %
633%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
634%
cristy73b7d4c2010-06-27 00:31:00 +0000635% GetImageViewVirtualPixels() returns the image view virtual pixels.
cristycc34c492010-06-26 23:49:12 +0000636%
637% The format of the GetImageViewVirtualPixels method is:
638%
cristy4c08aed2011-07-01 19:47:50 +0000639% const Quantum *GetImageViewVirtualPixels(const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000640%
641% A description of each parameter follows:
642%
cristy73b7d4c2010-06-27 00:31:00 +0000643% o image_view: the image view.
cristycc34c492010-06-26 23:49:12 +0000644%
645*/
cristy4c08aed2011-07-01 19:47:50 +0000646MagickExport const Quantum *GetImageViewVirtualPixels(
cristy73b7d4c2010-06-27 00:31:00 +0000647 const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000648{
cristy73b7d4c2010-06-27 00:31:00 +0000649 assert(image_view != (ImageView *) NULL);
650 assert(image_view->signature == MagickSignature);
651 return(GetCacheViewVirtualPixelQueue(image_view->view));
cristycc34c492010-06-26 23:49:12 +0000652}
653
654/*
655%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
656% %
657% %
658% %
cristy7eb1b7a2010-06-26 15:47:49 +0000659% I s I m a g e V i e w %
cristy3ed852e2009-09-05 21:47:34 +0000660% %
661% %
662% %
663%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
664%
cristy73b7d4c2010-06-27 00:31:00 +0000665% IsImageView() returns MagickTrue if the the parameter is verified as a image
666% view object.
cristy3ed852e2009-09-05 21:47:34 +0000667%
cristy7eb1b7a2010-06-26 15:47:49 +0000668% The format of the IsImageView method is:
cristy3ed852e2009-09-05 21:47:34 +0000669%
cristy73b7d4c2010-06-27 00:31:00 +0000670% MagickBooleanType IsImageView(const ImageView *image_view)
cristy3ed852e2009-09-05 21:47:34 +0000671%
672% A description of each parameter follows:
673%
cristy73b7d4c2010-06-27 00:31:00 +0000674% o image_view: the image view.
cristy3ed852e2009-09-05 21:47:34 +0000675%
676*/
cristy73b7d4c2010-06-27 00:31:00 +0000677MagickExport MagickBooleanType IsImageView(const ImageView *image_view)
cristy3ed852e2009-09-05 21:47:34 +0000678{
cristy73b7d4c2010-06-27 00:31:00 +0000679 if (image_view == (const ImageView *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000680 return(MagickFalse);
cristy73b7d4c2010-06-27 00:31:00 +0000681 if (image_view->signature != MagickSignature)
cristy3ed852e2009-09-05 21:47:34 +0000682 return(MagickFalse);
683 return(MagickTrue);
684}
685
686/*
687%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
688% %
689% %
690% %
cristy7eb1b7a2010-06-26 15:47:49 +0000691% N e w I m a g e V i e w %
cristy3ed852e2009-09-05 21:47:34 +0000692% %
693% %
694% %
695%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
696%
cristy73b7d4c2010-06-27 00:31:00 +0000697% NewImageView() returns a image view required for all other methods in the
698% Image View API.
cristy3ed852e2009-09-05 21:47:34 +0000699%
cristy7eb1b7a2010-06-26 15:47:49 +0000700% The format of the NewImageView method is:
cristy3ed852e2009-09-05 21:47:34 +0000701%
cristy7eb1b7a2010-06-26 15:47:49 +0000702% ImageView *NewImageView(MagickCore *wand)
cristy3ed852e2009-09-05 21:47:34 +0000703%
704% A description of each parameter follows:
705%
706% o wand: the wand.
707%
708*/
cristy7eb1b7a2010-06-26 15:47:49 +0000709MagickExport ImageView *NewImageView(Image *image)
cristy3ed852e2009-09-05 21:47:34 +0000710{
cristy7eb1b7a2010-06-26 15:47:49 +0000711 ImageView
cristy73b7d4c2010-06-27 00:31:00 +0000712 *image_view;
cristy3ed852e2009-09-05 21:47:34 +0000713
cristy7eb1b7a2010-06-26 15:47:49 +0000714 assert(image != (Image *) NULL);
715 assert(image->signature == MagickSignature);
cristy73bd4a52010-10-05 11:24:23 +0000716 image_view=(ImageView *) AcquireMagickMemory(sizeof(*image_view));
cristy73b7d4c2010-06-27 00:31:00 +0000717 if (image_view == (ImageView *) NULL)
cristy7eb1b7a2010-06-26 15:47:49 +0000718 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy73b7d4c2010-06-27 00:31:00 +0000719 (void) ResetMagickMemory(image_view,0,sizeof(*image_view));
cristyc3ebda22010-06-27 17:11:57 +0000720 image_view->description=ConstantString("ImageView");
cristy73b7d4c2010-06-27 00:31:00 +0000721 image_view->image=image;
722 image_view->view=AcquireCacheView(image_view->image);
cristyc3ebda22010-06-27 17:11:57 +0000723 image_view->extent.width=image->columns;
724 image_view->extent.height=image->rows;
725 image_view->extent.x=0;
726 image_view->extent.y=0;
cristy73b7d4c2010-06-27 00:31:00 +0000727 image_view->number_threads=GetOpenMPMaximumThreads();
cristyc3ebda22010-06-27 17:11:57 +0000728 image_view->exception=AcquireExceptionInfo();
cristy73b7d4c2010-06-27 00:31:00 +0000729 image_view->debug=IsEventLogging();
730 image_view->signature=MagickSignature;
731 return(image_view);
cristy3ed852e2009-09-05 21:47:34 +0000732}
733
734/*
735%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
736% %
737% %
738% %
cristy7eb1b7a2010-06-26 15:47:49 +0000739% N e w I m a g e V i e w R e g i o n %
cristy3ed852e2009-09-05 21:47:34 +0000740% %
741% %
742% %
743%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
744%
cristy73b7d4c2010-06-27 00:31:00 +0000745% NewImageViewRegion() returns a image view required for all other methods
746% in the Image View API.
cristy3ed852e2009-09-05 21:47:34 +0000747%
cristy7eb1b7a2010-06-26 15:47:49 +0000748% The format of the NewImageViewRegion method is:
cristy3ed852e2009-09-05 21:47:34 +0000749%
cristy7eb1b7a2010-06-26 15:47:49 +0000750% ImageView *NewImageViewRegion(MagickCore *wand,const ssize_t x,
cristybb503372010-05-27 20:51:26 +0000751% const ssize_t y,const size_t width,const size_t height)
cristy3ed852e2009-09-05 21:47:34 +0000752%
753% A description of each parameter follows:
754%
755% o wand: the magick wand.
756%
cristyc3ebda22010-06-27 17:11:57 +0000757% o x,y,columns,rows: These values define the perimeter of a extent of
cristy3ed852e2009-09-05 21:47:34 +0000758% pixel_wands view.
759%
760*/
cristy7eb1b7a2010-06-26 15:47:49 +0000761MagickExport ImageView *NewImageViewRegion(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +0000762 const ssize_t y,const size_t width,const size_t height)
cristy3ed852e2009-09-05 21:47:34 +0000763{
cristy7eb1b7a2010-06-26 15:47:49 +0000764 ImageView
cristy73b7d4c2010-06-27 00:31:00 +0000765 *image_view;
cristy3ed852e2009-09-05 21:47:34 +0000766
cristy7eb1b7a2010-06-26 15:47:49 +0000767 assert(image != (Image *) NULL);
768 assert(image->signature == MagickSignature);
cristy73bd4a52010-10-05 11:24:23 +0000769 image_view=(ImageView *) AcquireMagickMemory(sizeof(*image_view));
cristy73b7d4c2010-06-27 00:31:00 +0000770 if (image_view == (ImageView *) NULL)
cristy7eb1b7a2010-06-26 15:47:49 +0000771 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy73b7d4c2010-06-27 00:31:00 +0000772 (void) ResetMagickMemory(image_view,0,sizeof(*image_view));
cristyc3ebda22010-06-27 17:11:57 +0000773 image_view->description=ConstantString("ImageView");
cristy73b7d4c2010-06-27 00:31:00 +0000774 image_view->view=AcquireCacheView(image_view->image);
775 image_view->image=image;
cristyc3ebda22010-06-27 17:11:57 +0000776 image_view->extent.width=width;
777 image_view->extent.height=height;
778 image_view->extent.x=x;
779 image_view->extent.y=y;
cristy73b7d4c2010-06-27 00:31:00 +0000780 image_view->number_threads=GetOpenMPMaximumThreads();
cristyc3ebda22010-06-27 17:11:57 +0000781 image_view->exception=AcquireExceptionInfo();
cristy73b7d4c2010-06-27 00:31:00 +0000782 image_view->debug=IsEventLogging();
783 image_view->signature=MagickSignature;
784 return(image_view);
cristy3ed852e2009-09-05 21:47:34 +0000785}
786
787/*
788%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
789% %
790% %
791% %
cristyc3ebda22010-06-27 17:11:57 +0000792% S e t I m a g e V i e w D e s c r i p t i o n %
793% %
794% %
795% %
796%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
797%
798% SetImageViewDescription() associates a description with an image view.
799%
800% The format of the SetImageViewDescription method is:
801%
802% void SetImageViewDescription(ImageView *image_view,
803% const char *description)
804%
805% A description of each parameter follows:
806%
807% o image_view: the image view.
808%
809% o description: the image view description.
810%
811*/
812MagickExport void SetImageViewDescription(ImageView *image_view,
813 const char *description)
814{
815 assert(image_view != (ImageView *) NULL);
816 assert(image_view->signature == MagickSignature);
817 image_view->description=ConstantString(description);
818}
819
820/*
821%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
822% %
823% %
824% %
cristy7eb1b7a2010-06-26 15:47:49 +0000825% 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 +0000826% %
827% %
828% %
829%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
830%
cristy73b7d4c2010-06-27 00:31:00 +0000831% SetImageViewIterator() iterates over the image view in parallel and calls
cristyc3ebda22010-06-27 17:11:57 +0000832% your set method for each scanline of the view. The pixel extent is
cristy3ed852e2009-09-05 21:47:34 +0000833% confined to the image canvas-- that is no negative offsets or widths or
834% heights that exceed the image dimension. The pixels are initiallly
835% undefined and any settings you make in the callback method are automagically
836% synced back to your image.
837%
cristyd6dfc0d2010-06-27 19:30:49 +0000838% The callback signature is:
839%
840% MagickBooleanType SetImageViewMethod(ImageView *destination,
841% const ssize_t y,const int thread_id,void *context)
842%
cristy58739472010-06-26 20:27:18 +0000843% Use this pragma if the view is not single threaded:
cristy3ed852e2009-09-05 21:47:34 +0000844%
845% #pragma omp critical
846%
847% to define a section of code in your callback set method that must be
848% executed by a single thread at a time.
849%
cristy7eb1b7a2010-06-26 15:47:49 +0000850% The format of the SetImageViewIterator method is:
cristy3ed852e2009-09-05 21:47:34 +0000851%
cristy7eb1b7a2010-06-26 15:47:49 +0000852% MagickBooleanType SetImageViewIterator(ImageView *destination,
853% SetImageViewMethod set,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000854%
855% A description of each parameter follows:
856%
cristy73b7d4c2010-06-27 00:31:00 +0000857% o destination: the image view.
cristy3ed852e2009-09-05 21:47:34 +0000858%
859% o set: the set callback method.
860%
861% o context: the user defined context.
862%
863*/
cristy7eb1b7a2010-06-26 15:47:49 +0000864MagickExport MagickBooleanType SetImageViewIterator(ImageView *destination,
865 SetImageViewMethod set,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000866{
cristy3ed852e2009-09-05 21:47:34 +0000867 ExceptionInfo
868 *exception;
869
870 Image
871 *destination_image;
872
cristy3ed852e2009-09-05 21:47:34 +0000873 MagickBooleanType
874 status;
875
cristycee97112010-05-28 00:44:52 +0000876 MagickOffsetType
877 progress;
878
879 ssize_t
880 y;
881
cristy7eb1b7a2010-06-26 15:47:49 +0000882 assert(destination != (ImageView *) NULL);
883 assert(destination->signature == MagickSignature);
884 if (set == (SetImageViewMethod) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000885 return(MagickFalse);
cristy7eb1b7a2010-06-26 15:47:49 +0000886 destination_image=destination->image;
cristy47fa6ee2011-08-05 17:35:33 +0000887 exception=destination->exception;
cristy574cc262011-08-05 01:23:58 +0000888 if (SetImageStorageClass(destination_image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000889 return(MagickFalse);
890 status=MagickTrue;
891 progress=0;
cristyb5d5f722009-11-04 03:03:49 +0000892#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy09d81172010-10-21 16:15:05 +0000893 #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(destination->number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000894#endif
cristyc3ebda22010-06-27 17:11:57 +0000895 for (y=destination->extent.y; y < (ssize_t) destination->extent.height; y++)
cristy3ed852e2009-09-05 21:47:34 +0000896 {
cristy5c9e6f22010-09-17 17:31:01 +0000897 const int
898 id = GetOpenMPThreadId();
cristyad740052010-07-03 01:38:03 +0000899
cristy3ed852e2009-09-05 21:47:34 +0000900 MagickBooleanType
901 sync;
902
cristy4c08aed2011-07-01 19:47:50 +0000903 register Quantum
cristyc47d1f82009-11-26 01:44:43 +0000904 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000905
906 if (status == MagickFalse)
907 continue;
cristyc3ebda22010-06-27 17:11:57 +0000908 pixels=GetCacheViewAuthenticPixels(destination->view,destination->extent.x,
909 y,destination->extent.width,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000910 if (pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000911 {
912 InheritException(destination->exception,GetCacheViewException(
913 destination->view));
914 status=MagickFalse;
915 continue;
916 }
cristyd6dfc0d2010-06-27 19:30:49 +0000917 if (set(destination,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000918 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000919 sync=SyncCacheViewAuthenticPixels(destination->view,exception);
920 if (sync == MagickFalse)
921 {
922 InheritException(destination->exception,GetCacheViewException(
923 destination->view));
924 status=MagickFalse;
925 }
926 if (destination_image->progress_monitor != (MagickProgressMonitor) NULL)
927 {
928 MagickBooleanType
929 proceed;
930
cristyb5d5f722009-11-04 03:03:49 +0000931#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy7eb1b7a2010-06-26 15:47:49 +0000932 #pragma omp critical (MagickCore_SetImageViewIterator)
cristy3ed852e2009-09-05 21:47:34 +0000933#endif
cristyc3ebda22010-06-27 17:11:57 +0000934 proceed=SetImageProgress(destination_image,destination->description,
935 progress++,destination->extent.height);
cristy3ed852e2009-09-05 21:47:34 +0000936 if (proceed == MagickFalse)
937 status=MagickFalse;
938 }
939 }
940 return(status);
941}
942
943/*
944%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
945% %
946% %
947% %
cristy09d81172010-10-21 16:15:05 +0000948% S e t I m a g e V i e w T h r e a d s %
949% %
950% %
951% %
952%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
953%
954% SetImageViewThreads() sets the number of threads in a thread team.
955%
956% The format of the SetImageViewDescription method is:
957%
958% void SetImageViewThreads(ImageView *image_view,
959% const size_t number_threads)
960%
961% A description of each parameter follows:
962%
963% o image_view: the image view.
964%
965% o number_threads: the number of threads in a thread team.
966%
967*/
968MagickExport void SetImageViewThreads(ImageView *image_view,
969 const size_t number_threads)
970{
971 assert(image_view != (ImageView *) NULL);
972 assert(image_view->signature == MagickSignature);
973 image_view->number_threads=number_threads;
974 if (number_threads > GetOpenMPMaximumThreads())
975 image_view->number_threads=GetOpenMPMaximumThreads();
976}
977
978/*
979%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
980% %
981% %
982% %
cristy7eb1b7a2010-06-26 15:47:49 +0000983% 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 +0000984% %
985% %
986% %
987%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
988%
cristy73b7d4c2010-06-27 00:31:00 +0000989% TransferImageViewIterator() iterates over two image views in parallel and
cristy3ed852e2009-09-05 21:47:34 +0000990% calls your transfer method for each scanline of the view. The source pixel
cristyc3ebda22010-06-27 17:11:57 +0000991% extent is not confined to the image canvas-- that is you can include
cristy3ed852e2009-09-05 21:47:34 +0000992% negative offsets or widths or heights that exceed the image dimension.
cristy73b7d4c2010-06-27 00:31:00 +0000993% However, the destination image view is confined to the image canvas-- that
cristy3ed852e2009-09-05 21:47:34 +0000994% is no negative offsets or widths or heights that exceed the image dimension
995% are permitted.
996%
cristyd6dfc0d2010-06-27 19:30:49 +0000997% The callback signature is:
998%
999% MagickBooleanType TransferImageViewMethod(const ImageView *source,
1000% ImageView *destination,const ssize_t y,const int thread_id,
1001% void *context)
1002%
cristy58739472010-06-26 20:27:18 +00001003% Use this pragma if the view is not single threaded:
cristy3ed852e2009-09-05 21:47:34 +00001004%
1005% #pragma omp critical
1006%
1007% to define a section of code in your callback transfer method that must be
1008% executed by a single thread at a time.
1009%
cristy7eb1b7a2010-06-26 15:47:49 +00001010% The format of the TransferImageViewIterator method is:
cristy3ed852e2009-09-05 21:47:34 +00001011%
cristy7eb1b7a2010-06-26 15:47:49 +00001012% MagickBooleanType TransferImageViewIterator(ImageView *source,
1013% ImageView *destination,TransferImageViewMethod transfer,void *context)
cristy3ed852e2009-09-05 21:47:34 +00001014%
1015% A description of each parameter follows:
1016%
cristy73b7d4c2010-06-27 00:31:00 +00001017% o source: the source image view.
cristy3ed852e2009-09-05 21:47:34 +00001018%
cristy73b7d4c2010-06-27 00:31:00 +00001019% o destination: the destination image view.
cristy3ed852e2009-09-05 21:47:34 +00001020%
1021% o transfer: the transfer callback method.
1022%
1023% o context: the user defined context.
1024%
1025*/
cristy7eb1b7a2010-06-26 15:47:49 +00001026MagickExport MagickBooleanType TransferImageViewIterator(ImageView *source,
1027 ImageView *destination,TransferImageViewMethod transfer,void *context)
cristy3ed852e2009-09-05 21:47:34 +00001028{
cristy3ed852e2009-09-05 21:47:34 +00001029 ExceptionInfo
1030 *exception;
1031
1032 Image
1033 *destination_image,
1034 *source_image;
1035
cristy3ed852e2009-09-05 21:47:34 +00001036 MagickBooleanType
1037 status;
1038
cristycee97112010-05-28 00:44:52 +00001039 MagickOffsetType
1040 progress;
1041
1042 ssize_t
1043 y;
1044
cristy7eb1b7a2010-06-26 15:47:49 +00001045 assert(source != (ImageView *) NULL);
1046 assert(source->signature == MagickSignature);
1047 if (transfer == (TransferImageViewMethod) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001048 return(MagickFalse);
cristy7eb1b7a2010-06-26 15:47:49 +00001049 source_image=source->image;
1050 destination_image=destination->image;
cristy47fa6ee2011-08-05 17:35:33 +00001051 exception=destination->exception;
cristy574cc262011-08-05 01:23:58 +00001052 if (SetImageStorageClass(destination_image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001053 return(MagickFalse);
1054 status=MagickTrue;
1055 progress=0;
cristyb5d5f722009-11-04 03:03:49 +00001056#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy09d81172010-10-21 16:15:05 +00001057 #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(source->number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001058#endif
cristyc3ebda22010-06-27 17:11:57 +00001059 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
cristy3ed852e2009-09-05 21:47:34 +00001060 {
cristy5c9e6f22010-09-17 17:31:01 +00001061 const int
1062 id = GetOpenMPThreadId();
cristyad740052010-07-03 01:38:03 +00001063
cristy3ed852e2009-09-05 21:47:34 +00001064 MagickBooleanType
1065 sync;
1066
cristy4c08aed2011-07-01 19:47:50 +00001067 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00001068 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001069
cristy4c08aed2011-07-01 19:47:50 +00001070 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00001071 *restrict destination_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001072
1073 if (status == MagickFalse)
1074 continue;
cristyc3ebda22010-06-27 17:11:57 +00001075 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
1076 source->extent.width,1,source->exception);
cristy4c08aed2011-07-01 19:47:50 +00001077 if (pixels == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001078 {
1079 status=MagickFalse;
1080 continue;
1081 }
cristy3ed852e2009-09-05 21:47:34 +00001082 destination_pixels=GetCacheViewAuthenticPixels(destination->view,
cristyc3ebda22010-06-27 17:11:57 +00001083 destination->extent.x,y,destination->extent.width,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001084 if (destination_pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001085 {
1086 status=MagickFalse;
1087 continue;
1088 }
cristyc3ebda22010-06-27 17:11:57 +00001089 if (transfer(source,destination,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001090 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00001091 sync=SyncCacheViewAuthenticPixels(destination->view,exception);
1092 if (sync == MagickFalse)
1093 {
1094 InheritException(destination->exception,GetCacheViewException(
1095 source->view));
1096 status=MagickFalse;
1097 }
1098 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1099 {
1100 MagickBooleanType
1101 proceed;
1102
cristyb5d5f722009-11-04 03:03:49 +00001103#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy7eb1b7a2010-06-26 15:47:49 +00001104 #pragma omp critical (MagickCore_TransferImageViewIterator)
cristy3ed852e2009-09-05 21:47:34 +00001105#endif
cristyc3ebda22010-06-27 17:11:57 +00001106 proceed=SetImageProgress(source_image,source->description,progress++,
1107 source->extent.height);
cristy3ed852e2009-09-05 21:47:34 +00001108 if (proceed == MagickFalse)
1109 status=MagickFalse;
1110 }
1111 }
1112 return(status);
1113}
1114
1115/*
1116%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1117% %
1118% %
1119% %
cristy7eb1b7a2010-06-26 15:47:49 +00001120% 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 +00001121% %
1122% %
1123% %
1124%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1125%
cristy73b7d4c2010-06-27 00:31:00 +00001126% UpdateImageViewIterator() iterates over the image view in parallel and calls
cristyc3ebda22010-06-27 17:11:57 +00001127% your update method for each scanline of the view. The pixel extent is
cristy3ed852e2009-09-05 21:47:34 +00001128% confined to the image canvas-- that is no negative offsets or widths or
1129% heights that exceed the image dimension are permitted. Updates to pixels
1130% in your callback are automagically synced back to the image.
1131%
cristyd6dfc0d2010-06-27 19:30:49 +00001132% The callback signature is:
1133%
1134% MagickBooleanType UpdateImageViewMethod(ImageView *source,
1135% const ssize_t y,const int thread_id,void *context)
1136%
cristy58739472010-06-26 20:27:18 +00001137% Use this pragma if the view is not single threaded:
cristy3ed852e2009-09-05 21:47:34 +00001138%
1139% #pragma omp critical
1140%
1141% to define a section of code in your callback update method that must be
1142% executed by a single thread at a time.
1143%
cristy7eb1b7a2010-06-26 15:47:49 +00001144% The format of the UpdateImageViewIterator method is:
cristy3ed852e2009-09-05 21:47:34 +00001145%
cristy7eb1b7a2010-06-26 15:47:49 +00001146% MagickBooleanType UpdateImageViewIterator(ImageView *source,
1147% UpdateImageViewMethod update,void *context)
cristy3ed852e2009-09-05 21:47:34 +00001148%
1149% A description of each parameter follows:
1150%
cristy73b7d4c2010-06-27 00:31:00 +00001151% o source: the source image view.
cristy3ed852e2009-09-05 21:47:34 +00001152%
1153% o update: the update callback method.
1154%
1155% o context: the user defined context.
1156%
1157*/
cristy7eb1b7a2010-06-26 15:47:49 +00001158MagickExport MagickBooleanType UpdateImageViewIterator(ImageView *source,
1159 UpdateImageViewMethod update,void *context)
cristy3ed852e2009-09-05 21:47:34 +00001160{
cristy3ed852e2009-09-05 21:47:34 +00001161 ExceptionInfo
1162 *exception;
1163
1164 Image
1165 *source_image;
1166
cristy3ed852e2009-09-05 21:47:34 +00001167 MagickBooleanType
1168 status;
1169
cristycee97112010-05-28 00:44:52 +00001170 MagickOffsetType
1171 progress;
1172
1173 ssize_t
1174 y;
1175
cristy7eb1b7a2010-06-26 15:47:49 +00001176 assert(source != (ImageView *) NULL);
1177 assert(source->signature == MagickSignature);
1178 if (update == (UpdateImageViewMethod) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001179 return(MagickFalse);
cristy7eb1b7a2010-06-26 15:47:49 +00001180 source_image=source->image;
cristy47fa6ee2011-08-05 17:35:33 +00001181 exception=source->exception;
cristy574cc262011-08-05 01:23:58 +00001182 if (SetImageStorageClass(source_image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001183 return(MagickFalse);
1184 status=MagickTrue;
1185 progress=0;
cristyb5d5f722009-11-04 03:03:49 +00001186#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy09d81172010-10-21 16:15:05 +00001187 #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(source->number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001188#endif
cristyc3ebda22010-06-27 17:11:57 +00001189 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
cristy3ed852e2009-09-05 21:47:34 +00001190 {
cristy5c9e6f22010-09-17 17:31:01 +00001191 const int
1192 id = GetOpenMPThreadId();
cristyad740052010-07-03 01:38:03 +00001193
cristy4c08aed2011-07-01 19:47:50 +00001194 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00001195 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001196
1197 if (status == MagickFalse)
1198 continue;
cristyc3ebda22010-06-27 17:11:57 +00001199 pixels=GetCacheViewAuthenticPixels(source->view,source->extent.x,y,
1200 source->extent.width,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001201 if (pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001202 {
cristy73b7d4c2010-06-27 00:31:00 +00001203 InheritException(source->exception,GetCacheViewException(source->view));
cristy3ed852e2009-09-05 21:47:34 +00001204 status=MagickFalse;
1205 continue;
1206 }
cristyc3ebda22010-06-27 17:11:57 +00001207 if (update(source,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001208 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00001209 if (SyncCacheViewAuthenticPixels(source->view,exception) == MagickFalse)
1210 {
1211 InheritException(source->exception,GetCacheViewException(source->view));
1212 status=MagickFalse;
1213 }
1214 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1215 {
1216 MagickBooleanType
1217 proceed;
1218
cristyb5d5f722009-11-04 03:03:49 +00001219#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy7eb1b7a2010-06-26 15:47:49 +00001220 #pragma omp critical (MagickCore_UpdateImageViewIterator)
cristy3ed852e2009-09-05 21:47:34 +00001221#endif
cristyc3ebda22010-06-27 17:11:57 +00001222 proceed=SetImageProgress(source_image,source->description,progress++,
1223 source->extent.height);
cristy3ed852e2009-09-05 21:47:34 +00001224 if (proceed == MagickFalse)
1225 status=MagickFalse;
1226 }
1227 }
1228 return(status);
1229}