blob: 90e9a49878e3ff64fa1d576693e593ec620d01cc [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% %
cristy1454be72011-12-19 01:52:48 +000025% Copyright 1999-2012 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 Image
219 *destination_image,
cristy3ed852e2009-09-05 21:47:34 +0000220 *source_image;
221
cristy3ed852e2009-09-05 21:47:34 +0000222 MagickBooleanType
223 status;
224
cristycee97112010-05-28 00:44:52 +0000225 MagickOffsetType
226 progress;
227
228 ssize_t
229 y;
230
cristy7eb1b7a2010-06-26 15:47:49 +0000231 assert(source != (ImageView *) NULL);
232 assert(source->signature == MagickSignature);
233 if (transfer == (DuplexTransferImageViewMethod) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000234 return(MagickFalse);
cristy7eb1b7a2010-06-26 15:47:49 +0000235 source_image=source->image;
cristy7eb1b7a2010-06-26 15:47:49 +0000236 destination_image=destination->image;
cristy7c3af952011-10-20 16:04:16 +0000237 status=SetImageStorageClass(destination_image,DirectClass,
238 destination->exception);
239 if (status == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000240 return(MagickFalse);
241 status=MagickTrue;
242 progress=0;
cristyb5d5f722009-11-04 03:03:49 +0000243#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy09d81172010-10-21 16:15:05 +0000244 #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(source->number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000245#endif
cristyc3ebda22010-06-27 17:11:57 +0000246 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
cristy3ed852e2009-09-05 21:47:34 +0000247 {
cristy5c9e6f22010-09-17 17:31:01 +0000248 const int
249 id = GetOpenMPThreadId();
cristyad740052010-07-03 01:38:03 +0000250
cristy3ed852e2009-09-05 21:47:34 +0000251 MagickBooleanType
252 sync;
253
cristy4c08aed2011-07-01 19:47:50 +0000254 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +0000255 *restrict duplex_pixels,
256 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000257
cristy4c08aed2011-07-01 19:47:50 +0000258 register Quantum
cristyc47d1f82009-11-26 01:44:43 +0000259 *restrict destination_pixels;
cristy3ed852e2009-09-05 21:47:34 +0000260
261 if (status == MagickFalse)
262 continue;
cristyc3ebda22010-06-27 17:11:57 +0000263 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
264 source->extent.width,1,source->exception);
cristy4c08aed2011-07-01 19:47:50 +0000265 if (pixels == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000266 {
267 status=MagickFalse;
268 continue;
269 }
cristyc3ebda22010-06-27 17:11:57 +0000270 duplex_pixels=GetCacheViewVirtualPixels(duplex->view,duplex->extent.x,y,
271 duplex->extent.width,1,duplex->exception);
cristy4c08aed2011-07-01 19:47:50 +0000272 if (duplex_pixels == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000273 {
274 status=MagickFalse;
275 continue;
276 }
cristy3ed852e2009-09-05 21:47:34 +0000277 destination_pixels=GetCacheViewAuthenticPixels(destination->view,
cristy7c3af952011-10-20 16:04:16 +0000278 destination->extent.x,y,destination->extent.width,1,
279 destination->exception);
cristy4c08aed2011-07-01 19:47:50 +0000280 if (destination_pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000281 {
282 status=MagickFalse;
283 continue;
284 }
cristyc3ebda22010-06-27 17:11:57 +0000285 if (transfer(source,duplex,destination,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000286 status=MagickFalse;
cristy7c3af952011-10-20 16:04:16 +0000287 sync=SyncCacheViewAuthenticPixels(destination->view,destination->exception);
cristy3ed852e2009-09-05 21:47:34 +0000288 if (sync == MagickFalse)
cristy7c3af952011-10-20 16:04:16 +0000289 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000290 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
291 {
292 MagickBooleanType
293 proceed;
294
cristyb5d5f722009-11-04 03:03:49 +0000295#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy7eb1b7a2010-06-26 15:47:49 +0000296 #pragma omp critical (MagickCore_DuplexTransferImageViewIterator)
cristy3ed852e2009-09-05 21:47:34 +0000297#endif
cristyc3ebda22010-06-27 17:11:57 +0000298 proceed=SetImageProgress(source_image,source->description,progress++,
299 source->extent.height);
cristy3ed852e2009-09-05 21:47:34 +0000300 if (proceed == MagickFalse)
301 status=MagickFalse;
302 }
303 }
304 return(status);
305}
306
307/*
308%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
309% %
310% %
311% %
cristy7c3af952011-10-20 16:04:16 +0000312% 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 +0000313% %
314% %
315% %
316%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
317%
cristy4c08aed2011-07-01 19:47:50 +0000318% GetImageViewAuthenticMetacontent() returns the image view authentic
319% meta-content.
cristycc34c492010-06-26 23:49:12 +0000320%
321% The format of the GetImageViewAuthenticPixels method is:
322%
cristy4c08aed2011-07-01 19:47:50 +0000323% void *GetImageViewAuthenticMetacontent(
324% const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000325%
326% A description of each parameter follows:
327%
cristy73b7d4c2010-06-27 00:31:00 +0000328% o image_view: the image view.
cristycc34c492010-06-26 23:49:12 +0000329%
330*/
cristy4c08aed2011-07-01 19:47:50 +0000331MagickExport void *GetImageViewAuthenticMetacontent(
cristy73b7d4c2010-06-27 00:31:00 +0000332 const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000333{
cristy73b7d4c2010-06-27 00:31:00 +0000334 assert(image_view != (ImageView *) NULL);
335 assert(image_view->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +0000336 return(GetCacheViewAuthenticMetacontent(image_view->view));
cristycc34c492010-06-26 23:49:12 +0000337}
338
339/*
340%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
341% %
342% %
343% %
344% 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 %
345% %
346% %
347% %
348%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
349%
cristy73b7d4c2010-06-27 00:31:00 +0000350% GetImageViewAuthenticPixels() returns the image view authentic pixels.
cristycc34c492010-06-26 23:49:12 +0000351%
352% The format of the GetImageViewAuthenticPixels method is:
353%
cristy4c08aed2011-07-01 19:47:50 +0000354% Quantum *GetImageViewAuthenticPixels(const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000355%
356% A description of each parameter follows:
357%
cristy73b7d4c2010-06-27 00:31:00 +0000358% o image_view: the image view.
cristycc34c492010-06-26 23:49:12 +0000359%
360*/
cristy4c08aed2011-07-01 19:47:50 +0000361MagickExport Quantum *GetImageViewAuthenticPixels(
cristy73b7d4c2010-06-27 00:31:00 +0000362 const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000363{
cristy73b7d4c2010-06-27 00:31:00 +0000364 assert(image_view != (ImageView *) NULL);
365 assert(image_view->signature == MagickSignature);
366 return(GetCacheViewAuthenticPixelQueue(image_view->view));
cristycc34c492010-06-26 23:49:12 +0000367}
368
369/*
370%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
371% %
372% %
373% %
cristy7eb1b7a2010-06-26 15:47:49 +0000374% 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 +0000375% %
376% %
377% %
378%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
379%
cristy7eb1b7a2010-06-26 15:47:49 +0000380% GetImageViewException() returns the severity, reason, and description of any
cristy73b7d4c2010-06-27 00:31:00 +0000381% error that occurs when utilizing a image view.
cristy3ed852e2009-09-05 21:47:34 +0000382%
cristy7eb1b7a2010-06-26 15:47:49 +0000383% The format of the GetImageViewException method is:
cristy3ed852e2009-09-05 21:47:34 +0000384%
cristy73b7d4c2010-06-27 00:31:00 +0000385% char *GetImageViewException(const PixelImage *image_view,
cristy3ed852e2009-09-05 21:47:34 +0000386% ExceptionType *severity)
387%
388% A description of each parameter follows:
389%
cristy73b7d4c2010-06-27 00:31:00 +0000390% o image_view: the pixel image_view.
cristy3ed852e2009-09-05 21:47:34 +0000391%
392% o severity: the severity of the error is returned here.
393%
394*/
cristy73b7d4c2010-06-27 00:31:00 +0000395MagickExport char *GetImageViewException(const ImageView *image_view,
cristy3ed852e2009-09-05 21:47:34 +0000396 ExceptionType *severity)
397{
398 char
399 *description;
400
cristy73b7d4c2010-06-27 00:31:00 +0000401 assert(image_view != (const ImageView *) NULL);
402 assert(image_view->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +0000403 assert(severity != (ExceptionType *) NULL);
cristy73b7d4c2010-06-27 00:31:00 +0000404 *severity=image_view->exception->severity;
cristy3ed852e2009-09-05 21:47:34 +0000405 description=(char *) AcquireQuantumMemory(2UL*MaxTextExtent,
406 sizeof(*description));
407 if (description == (char *) NULL)
cristy7eb1b7a2010-06-26 15:47:49 +0000408 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000409 *description='\0';
cristy73b7d4c2010-06-27 00:31:00 +0000410 if (image_view->exception->reason != (char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000411 (void) CopyMagickString(description,GetLocaleExceptionMessage(
cristy73b7d4c2010-06-27 00:31:00 +0000412 image_view->exception->severity,image_view->exception->reason),
cristy3ed852e2009-09-05 21:47:34 +0000413 MaxTextExtent);
cristy73b7d4c2010-06-27 00:31:00 +0000414 if (image_view->exception->description != (char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000415 {
416 (void) ConcatenateMagickString(description," (",MaxTextExtent);
417 (void) ConcatenateMagickString(description,GetLocaleExceptionMessage(
cristy73b7d4c2010-06-27 00:31:00 +0000418 image_view->exception->severity,image_view->exception->description),
cristy3ed852e2009-09-05 21:47:34 +0000419 MaxTextExtent);
420 (void) ConcatenateMagickString(description,")",MaxTextExtent);
421 }
422 return(description);
423}
424
425/*
426%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
427% %
428% %
429% %
cristyc3ebda22010-06-27 17:11:57 +0000430% G e t I m a g e V i e w E x t e n t %
cristy3ed852e2009-09-05 21:47:34 +0000431% %
432% %
433% %
434%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
435%
cristyc3ebda22010-06-27 17:11:57 +0000436% GetImageViewExtent() returns the image view extent.
cristy3ed852e2009-09-05 21:47:34 +0000437%
cristyc3ebda22010-06-27 17:11:57 +0000438% The format of the GetImageViewExtent method is:
cristy3ed852e2009-09-05 21:47:34 +0000439%
cristyc3ebda22010-06-27 17:11:57 +0000440% RectangleInfo GetImageViewExtent(const ImageView *image_view)
cristy3ed852e2009-09-05 21:47:34 +0000441%
442% A description of each parameter follows:
443%
cristy73b7d4c2010-06-27 00:31:00 +0000444% o image_view: the image view.
cristy3ed852e2009-09-05 21:47:34 +0000445%
446*/
cristyc3ebda22010-06-27 17:11:57 +0000447MagickExport RectangleInfo GetImageViewExtent(const ImageView *image_view)
cristy3ed852e2009-09-05 21:47:34 +0000448{
cristy73b7d4c2010-06-27 00:31:00 +0000449 assert(image_view != (ImageView *) NULL);
450 assert(image_view->signature == MagickSignature);
cristyc3ebda22010-06-27 17:11:57 +0000451 return(image_view->extent);
cristy73b7d4c2010-06-27 00:31:00 +0000452}
453
454/*
455%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
456% %
457% %
458% %
459% G e t I m a g e V i e w I m a g e %
460% %
461% %
462% %
463%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
464%
465% GetImageViewImage() returns the image associated with the image view.
466%
467% The format of the GetImageViewImage method is:
468%
469% MagickCore *GetImageViewImage(const ImageView *image_view)
470%
471% A description of each parameter follows:
472%
473% o image_view: the image view.
474%
475*/
476MagickExport Image *GetImageViewImage(const ImageView *image_view)
477{
478 assert(image_view != (ImageView *) NULL);
479 assert(image_view->signature == MagickSignature);
480 return(image_view->image);
cristy3ed852e2009-09-05 21:47:34 +0000481}
482
483/*
484%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
485% %
486% %
487% %
cristy7eb1b7a2010-06-26 15:47:49 +0000488% 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 +0000489% %
490% %
491% %
492%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
493%
cristy73b7d4c2010-06-27 00:31:00 +0000494% GetImageViewIterator() iterates over the image view in parallel and calls
cristyc3ebda22010-06-27 17:11:57 +0000495% your get method for each scanline of the view. The pixel extent is
cristy3ed852e2009-09-05 21:47:34 +0000496% not confined to the image canvas-- that is you can include negative offsets
497% or widths or heights that exceed the image dimension. Any updates to
498% the pixels in your callback are ignored.
499%
cristyd6dfc0d2010-06-27 19:30:49 +0000500% The callback signature is:
501%
502% MagickBooleanType GetImageViewMethod(const ImageView *source,
503% const ssize_t y,const int thread_id,void *context)
504%
cristy58739472010-06-26 20:27:18 +0000505% Use this pragma if the view is not single threaded:
cristy3ed852e2009-09-05 21:47:34 +0000506%
507% #pragma omp critical
508%
509% to define a section of code in your callback get method that must be
510% executed by a single thread at a time.
511%
cristy7eb1b7a2010-06-26 15:47:49 +0000512% The format of the GetImageViewIterator method is:
cristy3ed852e2009-09-05 21:47:34 +0000513%
cristy7eb1b7a2010-06-26 15:47:49 +0000514% MagickBooleanType GetImageViewIterator(ImageView *source,
515% GetImageViewMethod get,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000516%
517% A description of each parameter follows:
518%
cristy73b7d4c2010-06-27 00:31:00 +0000519% o source: the source image view.
cristy3ed852e2009-09-05 21:47:34 +0000520%
521% o get: the get callback method.
522%
523% o context: the user defined context.
524%
525*/
cristy7eb1b7a2010-06-26 15:47:49 +0000526MagickExport MagickBooleanType GetImageViewIterator(ImageView *source,
527 GetImageViewMethod get,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000528{
cristy3ed852e2009-09-05 21:47:34 +0000529 Image
530 *source_image;
531
cristy3ed852e2009-09-05 21:47:34 +0000532 MagickBooleanType
533 status;
534
cristycee97112010-05-28 00:44:52 +0000535 MagickOffsetType
536 progress;
537
538 ssize_t
539 y;
540
cristy7eb1b7a2010-06-26 15:47:49 +0000541 assert(source != (ImageView *) NULL);
542 assert(source->signature == MagickSignature);
543 if (get == (GetImageViewMethod) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000544 return(MagickFalse);
cristy7eb1b7a2010-06-26 15:47:49 +0000545 source_image=source->image;
cristy3ed852e2009-09-05 21:47:34 +0000546 status=MagickTrue;
547 progress=0;
cristyb5d5f722009-11-04 03:03:49 +0000548#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy09d81172010-10-21 16:15:05 +0000549 #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(source->number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000550#endif
cristyc3ebda22010-06-27 17:11:57 +0000551 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
cristy3ed852e2009-09-05 21:47:34 +0000552 {
cristy5c9e6f22010-09-17 17:31:01 +0000553 const int
554 id = GetOpenMPThreadId();
cristyad740052010-07-03 01:38:03 +0000555
cristy4c08aed2011-07-01 19:47:50 +0000556 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000557 *pixels;
558
cristy3ed852e2009-09-05 21:47:34 +0000559 if (status == MagickFalse)
560 continue;
cristyc3ebda22010-06-27 17:11:57 +0000561 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
562 source->extent.width,1,source->exception);
cristy4c08aed2011-07-01 19:47:50 +0000563 if (pixels == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000564 {
565 status=MagickFalse;
566 continue;
567 }
cristyd6dfc0d2010-06-27 19:30:49 +0000568 if (get(source,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000569 status=MagickFalse;
570 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
571 {
572 MagickBooleanType
573 proceed;
574
cristyb5d5f722009-11-04 03:03:49 +0000575#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy7eb1b7a2010-06-26 15:47:49 +0000576 #pragma omp critical (MagickCore_GetImageViewIterator)
cristy3ed852e2009-09-05 21:47:34 +0000577#endif
cristyc3ebda22010-06-27 17:11:57 +0000578 proceed=SetImageProgress(source_image,source->description,progress++,
579 source->extent.height);
cristy3ed852e2009-09-05 21:47:34 +0000580 if (proceed == MagickFalse)
581 status=MagickFalse;
582 }
583 }
584 return(status);
585}
586
587/*
588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
589% %
590% %
591% %
cristy4c08aed2011-07-01 19:47:50 +0000592% 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 +0000593% %
594% %
595% %
596%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
597%
cristy4c08aed2011-07-01 19:47:50 +0000598% GetImageViewVirtualMetacontent() returns the image view virtual
599% meta-content.
cristycc34c492010-06-26 23:49:12 +0000600%
cristy4c08aed2011-07-01 19:47:50 +0000601% The format of the GetImageViewVirtualMetacontent method is:
cristycc34c492010-06-26 23:49:12 +0000602%
cristy4c08aed2011-07-01 19:47:50 +0000603% const void *GetImageViewVirtualMetacontent(
cristy73b7d4c2010-06-27 00:31:00 +0000604% const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000605%
606% A description of each parameter follows:
607%
cristy73b7d4c2010-06-27 00:31:00 +0000608% o image_view: the image view.
cristycc34c492010-06-26 23:49:12 +0000609%
610*/
cristy4c08aed2011-07-01 19:47:50 +0000611MagickExport const void *GetImageViewVirtualMetacontent(
cristy73b7d4c2010-06-27 00:31:00 +0000612 const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000613{
cristy73b7d4c2010-06-27 00:31:00 +0000614 assert(image_view != (ImageView *) NULL);
615 assert(image_view->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +0000616 return(GetCacheViewVirtualMetacontent(image_view->view));
cristycc34c492010-06-26 23:49:12 +0000617}
618
619/*
620%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
621% %
622% %
623% %
624% 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 %
625% %
626% %
627% %
628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
629%
cristy73b7d4c2010-06-27 00:31:00 +0000630% GetImageViewVirtualPixels() returns the image view virtual pixels.
cristycc34c492010-06-26 23:49:12 +0000631%
632% The format of the GetImageViewVirtualPixels method is:
633%
cristy4c08aed2011-07-01 19:47:50 +0000634% const Quantum *GetImageViewVirtualPixels(const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000635%
636% A description of each parameter follows:
637%
cristy73b7d4c2010-06-27 00:31:00 +0000638% o image_view: the image view.
cristycc34c492010-06-26 23:49:12 +0000639%
640*/
cristy4c08aed2011-07-01 19:47:50 +0000641MagickExport const Quantum *GetImageViewVirtualPixels(
cristy73b7d4c2010-06-27 00:31:00 +0000642 const ImageView *image_view)
cristycc34c492010-06-26 23:49:12 +0000643{
cristy73b7d4c2010-06-27 00:31:00 +0000644 assert(image_view != (ImageView *) NULL);
645 assert(image_view->signature == MagickSignature);
646 return(GetCacheViewVirtualPixelQueue(image_view->view));
cristycc34c492010-06-26 23:49:12 +0000647}
648
649/*
650%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
651% %
652% %
653% %
cristy7eb1b7a2010-06-26 15:47:49 +0000654% I s I m a g e V i e w %
cristy3ed852e2009-09-05 21:47:34 +0000655% %
656% %
657% %
658%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
659%
cristy73b7d4c2010-06-27 00:31:00 +0000660% IsImageView() returns MagickTrue if the the parameter is verified as a image
661% view object.
cristy3ed852e2009-09-05 21:47:34 +0000662%
cristy7eb1b7a2010-06-26 15:47:49 +0000663% The format of the IsImageView method is:
cristy3ed852e2009-09-05 21:47:34 +0000664%
cristy73b7d4c2010-06-27 00:31:00 +0000665% MagickBooleanType IsImageView(const ImageView *image_view)
cristy3ed852e2009-09-05 21:47:34 +0000666%
667% A description of each parameter follows:
668%
cristy73b7d4c2010-06-27 00:31:00 +0000669% o image_view: the image view.
cristy3ed852e2009-09-05 21:47:34 +0000670%
671*/
cristy73b7d4c2010-06-27 00:31:00 +0000672MagickExport MagickBooleanType IsImageView(const ImageView *image_view)
cristy3ed852e2009-09-05 21:47:34 +0000673{
cristy73b7d4c2010-06-27 00:31:00 +0000674 if (image_view == (const ImageView *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000675 return(MagickFalse);
cristy73b7d4c2010-06-27 00:31:00 +0000676 if (image_view->signature != MagickSignature)
cristy3ed852e2009-09-05 21:47:34 +0000677 return(MagickFalse);
678 return(MagickTrue);
679}
680
681/*
682%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
683% %
684% %
685% %
cristy7eb1b7a2010-06-26 15:47:49 +0000686% N e w I m a g e V i e w %
cristy3ed852e2009-09-05 21:47:34 +0000687% %
688% %
689% %
690%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
691%
cristy73b7d4c2010-06-27 00:31:00 +0000692% NewImageView() returns a image view required for all other methods in the
693% Image View API.
cristy3ed852e2009-09-05 21:47:34 +0000694%
cristy7eb1b7a2010-06-26 15:47:49 +0000695% The format of the NewImageView method is:
cristy3ed852e2009-09-05 21:47:34 +0000696%
cristy7eb1b7a2010-06-26 15:47:49 +0000697% ImageView *NewImageView(MagickCore *wand)
cristy3ed852e2009-09-05 21:47:34 +0000698%
699% A description of each parameter follows:
700%
701% o wand: the wand.
702%
703*/
cristy7eb1b7a2010-06-26 15:47:49 +0000704MagickExport ImageView *NewImageView(Image *image)
cristy3ed852e2009-09-05 21:47:34 +0000705{
cristy7eb1b7a2010-06-26 15:47:49 +0000706 ImageView
cristy73b7d4c2010-06-27 00:31:00 +0000707 *image_view;
cristy3ed852e2009-09-05 21:47:34 +0000708
cristy7eb1b7a2010-06-26 15:47:49 +0000709 assert(image != (Image *) NULL);
710 assert(image->signature == MagickSignature);
cristy73bd4a52010-10-05 11:24:23 +0000711 image_view=(ImageView *) AcquireMagickMemory(sizeof(*image_view));
cristy73b7d4c2010-06-27 00:31:00 +0000712 if (image_view == (ImageView *) NULL)
cristy7eb1b7a2010-06-26 15:47:49 +0000713 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy73b7d4c2010-06-27 00:31:00 +0000714 (void) ResetMagickMemory(image_view,0,sizeof(*image_view));
cristyc3ebda22010-06-27 17:11:57 +0000715 image_view->description=ConstantString("ImageView");
cristy73b7d4c2010-06-27 00:31:00 +0000716 image_view->image=image;
717 image_view->view=AcquireCacheView(image_view->image);
cristyc3ebda22010-06-27 17:11:57 +0000718 image_view->extent.width=image->columns;
719 image_view->extent.height=image->rows;
720 image_view->extent.x=0;
721 image_view->extent.y=0;
cristy73b7d4c2010-06-27 00:31:00 +0000722 image_view->number_threads=GetOpenMPMaximumThreads();
cristyc3ebda22010-06-27 17:11:57 +0000723 image_view->exception=AcquireExceptionInfo();
cristy73b7d4c2010-06-27 00:31:00 +0000724 image_view->debug=IsEventLogging();
725 image_view->signature=MagickSignature;
726 return(image_view);
cristy3ed852e2009-09-05 21:47:34 +0000727}
728
729/*
730%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
731% %
732% %
733% %
cristy7eb1b7a2010-06-26 15:47:49 +0000734% N e w I m a g e V i e w R e g i o n %
cristy3ed852e2009-09-05 21:47:34 +0000735% %
736% %
737% %
738%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
739%
cristy73b7d4c2010-06-27 00:31:00 +0000740% NewImageViewRegion() returns a image view required for all other methods
741% in the Image View API.
cristy3ed852e2009-09-05 21:47:34 +0000742%
cristy7eb1b7a2010-06-26 15:47:49 +0000743% The format of the NewImageViewRegion method is:
cristy3ed852e2009-09-05 21:47:34 +0000744%
cristy7eb1b7a2010-06-26 15:47:49 +0000745% ImageView *NewImageViewRegion(MagickCore *wand,const ssize_t x,
cristybb503372010-05-27 20:51:26 +0000746% const ssize_t y,const size_t width,const size_t height)
cristy3ed852e2009-09-05 21:47:34 +0000747%
748% A description of each parameter follows:
749%
750% o wand: the magick wand.
751%
cristyc3ebda22010-06-27 17:11:57 +0000752% o x,y,columns,rows: These values define the perimeter of a extent of
cristy3ed852e2009-09-05 21:47:34 +0000753% pixel_wands view.
754%
755*/
cristy7eb1b7a2010-06-26 15:47:49 +0000756MagickExport ImageView *NewImageViewRegion(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +0000757 const ssize_t y,const size_t width,const size_t height)
cristy3ed852e2009-09-05 21:47:34 +0000758{
cristy7eb1b7a2010-06-26 15:47:49 +0000759 ImageView
cristy73b7d4c2010-06-27 00:31:00 +0000760 *image_view;
cristy3ed852e2009-09-05 21:47:34 +0000761
cristy7eb1b7a2010-06-26 15:47:49 +0000762 assert(image != (Image *) NULL);
763 assert(image->signature == MagickSignature);
cristy73bd4a52010-10-05 11:24:23 +0000764 image_view=(ImageView *) AcquireMagickMemory(sizeof(*image_view));
cristy73b7d4c2010-06-27 00:31:00 +0000765 if (image_view == (ImageView *) NULL)
cristy7eb1b7a2010-06-26 15:47:49 +0000766 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy73b7d4c2010-06-27 00:31:00 +0000767 (void) ResetMagickMemory(image_view,0,sizeof(*image_view));
cristyc3ebda22010-06-27 17:11:57 +0000768 image_view->description=ConstantString("ImageView");
cristy73b7d4c2010-06-27 00:31:00 +0000769 image_view->view=AcquireCacheView(image_view->image);
770 image_view->image=image;
cristyc3ebda22010-06-27 17:11:57 +0000771 image_view->extent.width=width;
772 image_view->extent.height=height;
773 image_view->extent.x=x;
774 image_view->extent.y=y;
cristy73b7d4c2010-06-27 00:31:00 +0000775 image_view->number_threads=GetOpenMPMaximumThreads();
cristyc3ebda22010-06-27 17:11:57 +0000776 image_view->exception=AcquireExceptionInfo();
cristy73b7d4c2010-06-27 00:31:00 +0000777 image_view->debug=IsEventLogging();
778 image_view->signature=MagickSignature;
779 return(image_view);
cristy3ed852e2009-09-05 21:47:34 +0000780}
781
782/*
783%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
784% %
785% %
786% %
cristyc3ebda22010-06-27 17:11:57 +0000787% S e t I m a g e V i e w D e s c r i p t i o n %
788% %
789% %
790% %
791%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
792%
793% SetImageViewDescription() associates a description with an image view.
794%
795% The format of the SetImageViewDescription method is:
796%
797% void SetImageViewDescription(ImageView *image_view,
798% const char *description)
799%
800% A description of each parameter follows:
801%
802% o image_view: the image view.
803%
804% o description: the image view description.
805%
806*/
807MagickExport void SetImageViewDescription(ImageView *image_view,
808 const char *description)
809{
810 assert(image_view != (ImageView *) NULL);
811 assert(image_view->signature == MagickSignature);
812 image_view->description=ConstantString(description);
813}
814
815/*
816%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
817% %
818% %
819% %
cristy7eb1b7a2010-06-26 15:47:49 +0000820% 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 +0000821% %
822% %
823% %
824%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
825%
cristy73b7d4c2010-06-27 00:31:00 +0000826% SetImageViewIterator() iterates over the image view in parallel and calls
cristyc3ebda22010-06-27 17:11:57 +0000827% your set method for each scanline of the view. The pixel extent is
cristy3ed852e2009-09-05 21:47:34 +0000828% confined to the image canvas-- that is no negative offsets or widths or
829% heights that exceed the image dimension. The pixels are initiallly
830% undefined and any settings you make in the callback method are automagically
831% synced back to your image.
832%
cristyd6dfc0d2010-06-27 19:30:49 +0000833% The callback signature is:
834%
835% MagickBooleanType SetImageViewMethod(ImageView *destination,
836% const ssize_t y,const int thread_id,void *context)
837%
cristy58739472010-06-26 20:27:18 +0000838% Use this pragma if the view is not single threaded:
cristy3ed852e2009-09-05 21:47:34 +0000839%
840% #pragma omp critical
841%
842% to define a section of code in your callback set method that must be
843% executed by a single thread at a time.
844%
cristy7eb1b7a2010-06-26 15:47:49 +0000845% The format of the SetImageViewIterator method is:
cristy3ed852e2009-09-05 21:47:34 +0000846%
cristy7eb1b7a2010-06-26 15:47:49 +0000847% MagickBooleanType SetImageViewIterator(ImageView *destination,
848% SetImageViewMethod set,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000849%
850% A description of each parameter follows:
851%
cristy73b7d4c2010-06-27 00:31:00 +0000852% o destination: the image view.
cristy3ed852e2009-09-05 21:47:34 +0000853%
854% o set: the set callback method.
855%
856% o context: the user defined context.
857%
858*/
cristy7eb1b7a2010-06-26 15:47:49 +0000859MagickExport MagickBooleanType SetImageViewIterator(ImageView *destination,
860 SetImageViewMethod set,void *context)
cristy3ed852e2009-09-05 21:47:34 +0000861{
cristy3ed852e2009-09-05 21:47:34 +0000862 Image
863 *destination_image;
864
cristy3ed852e2009-09-05 21:47:34 +0000865 MagickBooleanType
866 status;
867
cristycee97112010-05-28 00:44:52 +0000868 MagickOffsetType
869 progress;
870
871 ssize_t
872 y;
873
cristy7eb1b7a2010-06-26 15:47:49 +0000874 assert(destination != (ImageView *) NULL);
875 assert(destination->signature == MagickSignature);
876 if (set == (SetImageViewMethod) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000877 return(MagickFalse);
cristy7eb1b7a2010-06-26 15:47:49 +0000878 destination_image=destination->image;
cristy7c3af952011-10-20 16:04:16 +0000879 status=SetImageStorageClass(destination_image,DirectClass,
880 destination->exception);
881 if (status == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000882 return(MagickFalse);
883 status=MagickTrue;
884 progress=0;
cristyb5d5f722009-11-04 03:03:49 +0000885#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy09d81172010-10-21 16:15:05 +0000886 #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(destination->number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000887#endif
cristyc3ebda22010-06-27 17:11:57 +0000888 for (y=destination->extent.y; y < (ssize_t) destination->extent.height; y++)
cristy3ed852e2009-09-05 21:47:34 +0000889 {
cristy5c9e6f22010-09-17 17:31:01 +0000890 const int
891 id = GetOpenMPThreadId();
cristyad740052010-07-03 01:38:03 +0000892
cristy3ed852e2009-09-05 21:47:34 +0000893 MagickBooleanType
894 sync;
895
cristy4c08aed2011-07-01 19:47:50 +0000896 register Quantum
cristyc47d1f82009-11-26 01:44:43 +0000897 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000898
899 if (status == MagickFalse)
900 continue;
cristyc3ebda22010-06-27 17:11:57 +0000901 pixels=GetCacheViewAuthenticPixels(destination->view,destination->extent.x,
cristy7c3af952011-10-20 16:04:16 +0000902 y,destination->extent.width,1,destination->exception);
cristy4c08aed2011-07-01 19:47:50 +0000903 if (pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000904 {
cristy3ed852e2009-09-05 21:47:34 +0000905 status=MagickFalse;
906 continue;
907 }
cristyd6dfc0d2010-06-27 19:30:49 +0000908 if (set(destination,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000909 status=MagickFalse;
cristy7c3af952011-10-20 16:04:16 +0000910 sync=SyncCacheViewAuthenticPixels(destination->view,destination->exception);
cristy3ed852e2009-09-05 21:47:34 +0000911 if (sync == MagickFalse)
cristy7c3af952011-10-20 16:04:16 +0000912 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000913 if (destination_image->progress_monitor != (MagickProgressMonitor) NULL)
914 {
915 MagickBooleanType
916 proceed;
917
cristyb5d5f722009-11-04 03:03:49 +0000918#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy7eb1b7a2010-06-26 15:47:49 +0000919 #pragma omp critical (MagickCore_SetImageViewIterator)
cristy3ed852e2009-09-05 21:47:34 +0000920#endif
cristyc3ebda22010-06-27 17:11:57 +0000921 proceed=SetImageProgress(destination_image,destination->description,
922 progress++,destination->extent.height);
cristy3ed852e2009-09-05 21:47:34 +0000923 if (proceed == MagickFalse)
924 status=MagickFalse;
925 }
926 }
927 return(status);
928}
929
930/*
931%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
932% %
933% %
934% %
cristy09d81172010-10-21 16:15:05 +0000935% S e t I m a g e V i e w T h r e a d s %
936% %
937% %
938% %
939%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
940%
941% SetImageViewThreads() sets the number of threads in a thread team.
942%
943% The format of the SetImageViewDescription method is:
944%
945% void SetImageViewThreads(ImageView *image_view,
946% const size_t number_threads)
947%
948% A description of each parameter follows:
949%
950% o image_view: the image view.
951%
952% o number_threads: the number of threads in a thread team.
953%
954*/
955MagickExport void SetImageViewThreads(ImageView *image_view,
956 const size_t number_threads)
957{
958 assert(image_view != (ImageView *) NULL);
959 assert(image_view->signature == MagickSignature);
960 image_view->number_threads=number_threads;
961 if (number_threads > GetOpenMPMaximumThreads())
962 image_view->number_threads=GetOpenMPMaximumThreads();
963}
964
965/*
966%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
967% %
968% %
969% %
cristy7eb1b7a2010-06-26 15:47:49 +0000970% 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 +0000971% %
972% %
973% %
974%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
975%
cristy73b7d4c2010-06-27 00:31:00 +0000976% TransferImageViewIterator() iterates over two image views in parallel and
cristy3ed852e2009-09-05 21:47:34 +0000977% calls your transfer method for each scanline of the view. The source pixel
cristyc3ebda22010-06-27 17:11:57 +0000978% extent is not confined to the image canvas-- that is you can include
cristy3ed852e2009-09-05 21:47:34 +0000979% negative offsets or widths or heights that exceed the image dimension.
cristy73b7d4c2010-06-27 00:31:00 +0000980% However, the destination image view is confined to the image canvas-- that
cristy3ed852e2009-09-05 21:47:34 +0000981% is no negative offsets or widths or heights that exceed the image dimension
982% are permitted.
983%
cristyd6dfc0d2010-06-27 19:30:49 +0000984% The callback signature is:
985%
986% MagickBooleanType TransferImageViewMethod(const ImageView *source,
987% ImageView *destination,const ssize_t y,const int thread_id,
988% void *context)
989%
cristy58739472010-06-26 20:27:18 +0000990% Use this pragma if the view is not single threaded:
cristy3ed852e2009-09-05 21:47:34 +0000991%
992% #pragma omp critical
993%
994% to define a section of code in your callback transfer method that must be
995% executed by a single thread at a time.
996%
cristy7eb1b7a2010-06-26 15:47:49 +0000997% The format of the TransferImageViewIterator method is:
cristy3ed852e2009-09-05 21:47:34 +0000998%
cristy7eb1b7a2010-06-26 15:47:49 +0000999% MagickBooleanType TransferImageViewIterator(ImageView *source,
1000% ImageView *destination,TransferImageViewMethod transfer,void *context)
cristy3ed852e2009-09-05 21:47:34 +00001001%
1002% A description of each parameter follows:
1003%
cristy73b7d4c2010-06-27 00:31:00 +00001004% o source: the source image view.
cristy3ed852e2009-09-05 21:47:34 +00001005%
cristy73b7d4c2010-06-27 00:31:00 +00001006% o destination: the destination image view.
cristy3ed852e2009-09-05 21:47:34 +00001007%
1008% o transfer: the transfer callback method.
1009%
1010% o context: the user defined context.
1011%
1012*/
cristy7eb1b7a2010-06-26 15:47:49 +00001013MagickExport MagickBooleanType TransferImageViewIterator(ImageView *source,
1014 ImageView *destination,TransferImageViewMethod transfer,void *context)
cristy3ed852e2009-09-05 21:47:34 +00001015{
cristy3ed852e2009-09-05 21:47:34 +00001016 Image
1017 *destination_image,
1018 *source_image;
1019
cristy3ed852e2009-09-05 21:47:34 +00001020 MagickBooleanType
1021 status;
1022
cristycee97112010-05-28 00:44:52 +00001023 MagickOffsetType
1024 progress;
1025
1026 ssize_t
1027 y;
1028
cristy7eb1b7a2010-06-26 15:47:49 +00001029 assert(source != (ImageView *) NULL);
1030 assert(source->signature == MagickSignature);
1031 if (transfer == (TransferImageViewMethod) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001032 return(MagickFalse);
cristy7eb1b7a2010-06-26 15:47:49 +00001033 source_image=source->image;
1034 destination_image=destination->image;
cristy7c3af952011-10-20 16:04:16 +00001035 status=SetImageStorageClass(destination_image,DirectClass,
1036 destination->exception);
1037 if (status == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001038 return(MagickFalse);
1039 status=MagickTrue;
1040 progress=0;
cristyb5d5f722009-11-04 03:03:49 +00001041#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy09d81172010-10-21 16:15:05 +00001042 #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(source->number_threads)
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 {
cristy5c9e6f22010-09-17 17:31:01 +00001046 const int
1047 id = GetOpenMPThreadId();
cristyad740052010-07-03 01:38:03 +00001048
cristy3ed852e2009-09-05 21:47:34 +00001049 MagickBooleanType
1050 sync;
1051
cristy4c08aed2011-07-01 19:47:50 +00001052 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00001053 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001054
cristy4c08aed2011-07-01 19:47:50 +00001055 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00001056 *restrict destination_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001057
1058 if (status == MagickFalse)
1059 continue;
cristyc3ebda22010-06-27 17:11:57 +00001060 pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
1061 source->extent.width,1,source->exception);
cristy4c08aed2011-07-01 19:47:50 +00001062 if (pixels == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001063 {
1064 status=MagickFalse;
1065 continue;
1066 }
cristy3ed852e2009-09-05 21:47:34 +00001067 destination_pixels=GetCacheViewAuthenticPixels(destination->view,
cristy7c3af952011-10-20 16:04:16 +00001068 destination->extent.x,y,destination->extent.width,1,
1069 destination->exception);
cristy4c08aed2011-07-01 19:47:50 +00001070 if (destination_pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001071 {
1072 status=MagickFalse;
1073 continue;
1074 }
cristyc3ebda22010-06-27 17:11:57 +00001075 if (transfer(source,destination,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001076 status=MagickFalse;
cristy7c3af952011-10-20 16:04:16 +00001077 sync=SyncCacheViewAuthenticPixels(destination->view,destination->exception);
cristy3ed852e2009-09-05 21:47:34 +00001078 if (sync == MagickFalse)
cristy7c3af952011-10-20 16:04:16 +00001079 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00001080 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1081 {
1082 MagickBooleanType
1083 proceed;
1084
cristyb5d5f722009-11-04 03:03:49 +00001085#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy7eb1b7a2010-06-26 15:47:49 +00001086 #pragma omp critical (MagickCore_TransferImageViewIterator)
cristy3ed852e2009-09-05 21:47:34 +00001087#endif
cristyc3ebda22010-06-27 17:11:57 +00001088 proceed=SetImageProgress(source_image,source->description,progress++,
1089 source->extent.height);
cristy3ed852e2009-09-05 21:47:34 +00001090 if (proceed == MagickFalse)
1091 status=MagickFalse;
1092 }
1093 }
1094 return(status);
1095}
1096
1097/*
1098%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1099% %
1100% %
1101% %
cristy7eb1b7a2010-06-26 15:47:49 +00001102% 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 +00001103% %
1104% %
1105% %
1106%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1107%
cristy73b7d4c2010-06-27 00:31:00 +00001108% UpdateImageViewIterator() iterates over the image view in parallel and calls
cristyc3ebda22010-06-27 17:11:57 +00001109% your update method for each scanline of the view. The pixel extent is
cristy3ed852e2009-09-05 21:47:34 +00001110% confined to the image canvas-- that is no negative offsets or widths or
1111% heights that exceed the image dimension are permitted. Updates to pixels
1112% in your callback are automagically synced back to the image.
1113%
cristyd6dfc0d2010-06-27 19:30:49 +00001114% The callback signature is:
1115%
1116% MagickBooleanType UpdateImageViewMethod(ImageView *source,
1117% const ssize_t y,const int thread_id,void *context)
1118%
cristy58739472010-06-26 20:27:18 +00001119% Use this pragma if the view is not single threaded:
cristy3ed852e2009-09-05 21:47:34 +00001120%
1121% #pragma omp critical
1122%
1123% to define a section of code in your callback update method that must be
1124% executed by a single thread at a time.
1125%
cristy7eb1b7a2010-06-26 15:47:49 +00001126% The format of the UpdateImageViewIterator method is:
cristy3ed852e2009-09-05 21:47:34 +00001127%
cristy7eb1b7a2010-06-26 15:47:49 +00001128% MagickBooleanType UpdateImageViewIterator(ImageView *source,
1129% UpdateImageViewMethod update,void *context)
cristy3ed852e2009-09-05 21:47:34 +00001130%
1131% A description of each parameter follows:
1132%
cristy73b7d4c2010-06-27 00:31:00 +00001133% o source: the source image view.
cristy3ed852e2009-09-05 21:47:34 +00001134%
1135% o update: the update callback method.
1136%
1137% o context: the user defined context.
1138%
1139*/
cristy7eb1b7a2010-06-26 15:47:49 +00001140MagickExport MagickBooleanType UpdateImageViewIterator(ImageView *source,
1141 UpdateImageViewMethod update,void *context)
cristy3ed852e2009-09-05 21:47:34 +00001142{
cristy3ed852e2009-09-05 21:47:34 +00001143 Image
1144 *source_image;
1145
cristy3ed852e2009-09-05 21:47:34 +00001146 MagickBooleanType
1147 status;
1148
cristycee97112010-05-28 00:44:52 +00001149 MagickOffsetType
1150 progress;
1151
1152 ssize_t
1153 y;
1154
cristy7eb1b7a2010-06-26 15:47:49 +00001155 assert(source != (ImageView *) NULL);
1156 assert(source->signature == MagickSignature);
1157 if (update == (UpdateImageViewMethod) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001158 return(MagickFalse);
cristy7eb1b7a2010-06-26 15:47:49 +00001159 source_image=source->image;
cristy7c3af952011-10-20 16:04:16 +00001160 status=SetImageStorageClass(source_image,DirectClass,source->exception);
1161 if (status == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001162 return(MagickFalse);
1163 status=MagickTrue;
1164 progress=0;
cristyb5d5f722009-11-04 03:03:49 +00001165#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy09d81172010-10-21 16:15:05 +00001166 #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(source->number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001167#endif
cristyc3ebda22010-06-27 17:11:57 +00001168 for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
cristy3ed852e2009-09-05 21:47:34 +00001169 {
cristy5c9e6f22010-09-17 17:31:01 +00001170 const int
1171 id = GetOpenMPThreadId();
cristyad740052010-07-03 01:38:03 +00001172
cristy4c08aed2011-07-01 19:47:50 +00001173 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00001174 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001175
1176 if (status == MagickFalse)
1177 continue;
cristyc3ebda22010-06-27 17:11:57 +00001178 pixels=GetCacheViewAuthenticPixels(source->view,source->extent.x,y,
cristy7c3af952011-10-20 16:04:16 +00001179 source->extent.width,1,source->exception);
cristy4c08aed2011-07-01 19:47:50 +00001180 if (pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001181 {
cristy3ed852e2009-09-05 21:47:34 +00001182 status=MagickFalse;
1183 continue;
1184 }
cristyc3ebda22010-06-27 17:11:57 +00001185 if (update(source,y,id,context) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001186 status=MagickFalse;
cristy7c3af952011-10-20 16:04:16 +00001187 status=SyncCacheViewAuthenticPixels(source->view,source->exception);
1188 if (status == MagickFalse)
1189 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00001190 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1191 {
1192 MagickBooleanType
1193 proceed;
1194
cristyb5d5f722009-11-04 03:03:49 +00001195#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy7eb1b7a2010-06-26 15:47:49 +00001196 #pragma omp critical (MagickCore_UpdateImageViewIterator)
cristy3ed852e2009-09-05 21:47:34 +00001197#endif
cristyc3ebda22010-06-27 17:11:57 +00001198 proceed=SetImageProgress(source_image,source->description,progress++,
1199 source->extent.height);
cristy3ed852e2009-09-05 21:47:34 +00001200 if (proceed == MagickFalse)
1201 status=MagickFalse;
1202 }
1203 }
1204 return(status);
1205}