blob: c63629b155980ab2d45ed90ccbac52a4e500eb41 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% PPPP IIIII X X EEEEE L %
7% P P I X X E L %
8% PPPP I X EEE L %
9% P I X X E L %
10% P IIIII X X EEEEE LLLLL %
11% %
12% V V IIIII EEEEE W W %
13% V V I E W W %
14% V V I EEE W W W %
15% V V I E WW WW %
16% V IIIII EEEEE W W %
17% %
18% %
19% MagickWand Pixel View Methods %
20% %
21% Software Design %
22% John Cristy %
23% March 2003 %
24% %
25% %
cristy16af1cb2009-12-11 21:38:29 +000026% Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000027% dedicated to making software imaging solutions freely available. %
28% %
29% You may not use this file except in compliance with the License. You may %
30% obtain a copy of the License at %
31% %
32% http://www.imagemagick.org/script/license.php %
33% %
34% Unless required by applicable law or agreed to in writing, software %
35% distributed under the License is distributed on an "AS IS" BASIS, %
36% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
37% See the License for the specific language governing permissions and %
38% limitations under the License. %
39% %
40%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
41%
42%
43%
44*/
45
46/*
47 Include declarations.
48*/
49#include "wand/studio.h"
50#include "wand/MagickWand.h"
51#include "wand/magick-wand-private.h"
52#include "wand/wand.h"
53#include "magick/monitor-private.h"
54#include "magick/thread-private.h"
55/*
56 Define declarations.
57*/
58#define PixelViewId "PixelView"
59
60/*
61 Typedef declarations.
62*/
63struct _PixelView
64{
cristybb503372010-05-27 20:51:26 +000065 size_t
cristy3ed852e2009-09-05 21:47:34 +000066 id;
67
68 char
69 name[MaxTextExtent];
70
71 ExceptionInfo
72 *exception;
73
74 MagickWand
75 *wand;
76
77 CacheView
78 *view;
79
80 RectangleInfo
81 region;
82
cristybb503372010-05-27 20:51:26 +000083 size_t
cristy3ed852e2009-09-05 21:47:34 +000084 number_threads;
85
86 PixelWand
87 ***pixel_wands;
88
89 MagickBooleanType
90 debug;
91
cristybb503372010-05-27 20:51:26 +000092 size_t
cristy3ed852e2009-09-05 21:47:34 +000093 signature;
94};
95
96/*
97%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
98% %
99% %
100% %
101% C l o n e P i x e l V i e w %
102% %
103% %
104% %
105%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
106%
107% ClonePixelView() makes a copy of the specified pixel view.
108%
109% The format of the ClonePixelView method is:
110%
111% PixelView *ClonePixelView(const PixelView *pixel_view)
112%
113% A description of each parameter follows:
114%
115% o pixel_view: the pixel view.
116%
117*/
118WandExport PixelView *ClonePixelView(const PixelView *pixel_view)
119{
120 PixelView
121 *clone_view;
122
cristybb503372010-05-27 20:51:26 +0000123 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000124 i;
125
126 assert(pixel_view != (PixelView *) NULL);
127 assert(pixel_view->signature == WandSignature);
128 if (pixel_view->debug != MagickFalse)
129 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",pixel_view->name);
cristy90823212009-12-12 20:48:33 +0000130 clone_view=(PixelView *) AcquireAlignedMemory(1,sizeof(*clone_view));
cristy3ed852e2009-09-05 21:47:34 +0000131 if (clone_view == (PixelView *) NULL)
132 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
133 pixel_view->name);
134 (void) ResetMagickMemory(clone_view,0,sizeof(*clone_view));
135 clone_view->id=AcquireWandId();
cristye8c25f92010-06-03 00:53:06 +0000136 (void) FormatMagickString(clone_view->name,MaxTextExtent,"%s-%.20g",
137 PixelViewId,(double) clone_view->id);
cristy3ed852e2009-09-05 21:47:34 +0000138 clone_view->exception=AcquireExceptionInfo();
139 InheritException(clone_view->exception,pixel_view->exception);
140 clone_view->view=CloneCacheView(pixel_view->view);
141 clone_view->region=pixel_view->region;
142 clone_view->number_threads=pixel_view->number_threads;
cristybb503372010-05-27 20:51:26 +0000143 for (i=0; i < (ssize_t) pixel_view->number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000144 clone_view->pixel_wands[i]=ClonePixelWands((const PixelWand **)
145 pixel_view->pixel_wands[i],pixel_view->region.width);
146 clone_view->debug=pixel_view->debug;
147 if (clone_view->debug != MagickFalse)
148 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",clone_view->name);
149 clone_view->signature=WandSignature;
150 return(clone_view);
151}
152
153/*
154%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
155% %
156% %
157% %
158% D e s t r o y P i x e l V i e w %
159% %
160% %
161% %
162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
163%
164% DestroyPixelView() deallocates memory associated with a pixel view.
165%
166% The format of the DestroyPixelView method is:
167%
168% PixelView *DestroyPixelView(PixelView *pixel_view,
cristybb503372010-05-27 20:51:26 +0000169% const size_t number_wands,const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000170%
171% A description of each parameter follows:
172%
173% o pixel_view: the pixel view.
174%
175% o number_wand: the number of pixel wands.
176%
177% o number_threads: number of threads.
178%
179*/
180
181static PixelWand ***DestroyPixelsThreadSet(PixelWand ***pixel_wands,
cristybb503372010-05-27 20:51:26 +0000182 const size_t number_wands,const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000183{
cristybb503372010-05-27 20:51:26 +0000184 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000185 i;
186
187 assert(pixel_wands != (PixelWand ***) NULL);
cristybb503372010-05-27 20:51:26 +0000188 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000189 if (pixel_wands[i] != (PixelWand **) NULL)
190 pixel_wands[i]=DestroyPixelWands(pixel_wands[i],number_wands);
191 pixel_wands=(PixelWand ***) RelinquishAlignedMemory(pixel_wands);
192 return(pixel_wands);
193}
194
195WandExport PixelView *DestroyPixelView(PixelView *pixel_view)
196{
197 assert(pixel_view != (PixelView *) NULL);
198 assert(pixel_view->signature == WandSignature);
199 pixel_view->pixel_wands=DestroyPixelsThreadSet(pixel_view->pixel_wands,
200 pixel_view->region.width,pixel_view->number_threads);
201 pixel_view->view=DestroyCacheView(pixel_view->view);
202 pixel_view->exception=DestroyExceptionInfo(pixel_view->exception);
203 pixel_view->signature=(~WandSignature);
204 RelinquishWandId(pixel_view->id);
205 pixel_view=(PixelView *) RelinquishMagickMemory(pixel_view);
206 return(pixel_view);
207}
208
209/*
210%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
211% %
212% %
213% %
214% D u p l e x T r a n s f e r P i x e l V i e w I t e r a t o r %
215% %
216% %
217% %
218%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
219%
220% DuplexTransferPixelViewIterator() iterates over three pixel views in
221% parallel and calls your transfer method for each scanline of the view. The
222% source and duplex pixel region is not confined to the image canvas-- that is
223% you can include negative offsets or widths or heights that exceed the image
224% dimension. However, the destination pixel view is confined to the image
225% canvas-- that is no negative offsets or widths or heights that exceed the
226% image dimension are permitted.
227%
228% Use this pragma:
229%
230% #pragma omp critical
231%
232% to define a section of code in your callback transfer method that must be
233% executed by a single thread at a time.
234%
235% The format of the DuplexTransferPixelViewIterator method is:
236%
237% MagickBooleanType DuplexTransferPixelViewIterator(PixelView *source,
238% PixelView *duplex,PixelView *destination,
239% DuplexTransferPixelViewMethod transfer,void *context)
240%
241% A description of each parameter follows:
242%
243% o source: the source pixel view.
244%
245% o duplex: the duplex pixel view.
246%
247% o destination: the destination pixel view.
248%
249% o transfer: the transfer callback method.
250%
251% o context: the user defined context.
252%
253*/
254WandExport MagickBooleanType DuplexTransferPixelViewIterator(
255 PixelView *source,PixelView *duplex,PixelView *destination,
256 DuplexTransferPixelViewMethod transfer,void *context)
257{
258#define DuplexTransferPixelViewTag "PixelView/DuplexTransfer"
259
260 ExceptionInfo
261 *exception;
262
263 Image
264 *destination_image,
265 *duplex_image,
266 *source_image;
267
cristy3ed852e2009-09-05 21:47:34 +0000268 MagickBooleanType
269 status;
270
cristycee97112010-05-28 00:44:52 +0000271 MagickOffsetType
272 progress;
273
274 ssize_t
275 y;
276
cristy3ed852e2009-09-05 21:47:34 +0000277 assert(source != (PixelView *) NULL);
278 assert(source->signature == WandSignature);
279 if (transfer == (DuplexTransferPixelViewMethod) NULL)
280 return(MagickFalse);
281 source_image=source->wand->images;
282 duplex_image=duplex->wand->images;
283 destination_image=destination->wand->images;
284 if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
285 return(MagickFalse);
286 status=MagickTrue;
287 progress=0;
288 exception=destination->exception;
cristyb5d5f722009-11-04 03:03:49 +0000289#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristycde47d32009-11-04 03:05:18 +0000290 #pragma omp parallel for schedule(static,1) shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +0000291#endif
cristybb503372010-05-27 20:51:26 +0000292 for (y=source->region.y; y < (ssize_t) source->region.height; y++)
cristy3ed852e2009-09-05 21:47:34 +0000293 {
294 MagickBooleanType
295 sync;
296
297 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000298 *restrict duplex_indexes,
299 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +0000300
301 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000302 *restrict duplex_pixels,
303 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000304
305 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000306 *restrict destination_indexes;
cristy3ed852e2009-09-05 21:47:34 +0000307
cristybb503372010-05-27 20:51:26 +0000308 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000309 id,
310 x;
311
312 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000313 *restrict destination_pixels;
cristy3ed852e2009-09-05 21:47:34 +0000314
315 if (status == MagickFalse)
316 continue;
317 id=GetOpenMPThreadId();
318 pixels=GetCacheViewVirtualPixels(source->view,source->region.x,y,
319 source->region.width,1,source->exception);
320 if (pixels == (const PixelPacket *) NULL)
321 {
322 status=MagickFalse;
323 continue;
324 }
325 indexes=GetCacheViewVirtualIndexQueue(source->view);
cristybb503372010-05-27 20:51:26 +0000326 for (x=0; x < (ssize_t) source->region.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000327 PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
328 if (source_image->colorspace == CMYKColorspace)
cristybb503372010-05-27 20:51:26 +0000329 for (x=0; x < (ssize_t) source->region.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000330 PixelSetBlackQuantum(source->pixel_wands[id][x],indexes[x]);
331 if (source_image->storage_class == PseudoClass)
cristybb503372010-05-27 20:51:26 +0000332 for (x=0; x < (ssize_t) source->region.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000333 PixelSetIndex(source->pixel_wands[id][x],indexes[x]);
334 duplex_pixels=GetCacheViewVirtualPixels(duplex->view,duplex->region.x,y,
335 duplex->region.width,1,duplex->exception);
336 if (duplex_pixels == (const PixelPacket *) NULL)
337 {
338 status=MagickFalse;
339 continue;
340 }
341 duplex_indexes=GetCacheViewVirtualIndexQueue(duplex->view);
cristybb503372010-05-27 20:51:26 +0000342 for (x=0; x < (ssize_t) duplex->region.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000343 PixelSetQuantumColor(duplex->pixel_wands[id][x],duplex_pixels+x);
344 if (duplex_image->colorspace == CMYKColorspace)
cristybb503372010-05-27 20:51:26 +0000345 for (x=0; x < (ssize_t) duplex->region.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000346 PixelSetBlackQuantum(duplex->pixel_wands[id][x],duplex_indexes[x]);
347 if (duplex_image->storage_class == PseudoClass)
cristybb503372010-05-27 20:51:26 +0000348 for (x=0; x < (ssize_t) duplex->region.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000349 PixelSetIndex(duplex->pixel_wands[id][x],duplex_indexes[x]);
350 destination_pixels=GetCacheViewAuthenticPixels(destination->view,
351 destination->region.x,y,destination->region.width,1,exception);
352 if (destination_pixels == (PixelPacket *) NULL)
353 {
354 status=MagickFalse;
355 continue;
356 }
357 destination_indexes=GetCacheViewAuthenticIndexQueue(destination->view);
cristybb503372010-05-27 20:51:26 +0000358 for (x=0; x < (ssize_t) destination->region.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000359 PixelSetQuantumColor(destination->pixel_wands[id][x],
360 destination_pixels+x);
361 if (destination_image->colorspace == CMYKColorspace)
cristybb503372010-05-27 20:51:26 +0000362 for (x=0; x < (ssize_t) destination->region.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000363 PixelSetBlackQuantum(destination->pixel_wands[id][x],
364 destination_indexes[x]);
365 if (destination_image->storage_class == PseudoClass)
cristybb503372010-05-27 20:51:26 +0000366 for (x=0; x < (ssize_t) destination->region.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000367 PixelSetIndex(destination->pixel_wands[id][x],destination_indexes[x]);
368 if (transfer(source,duplex,destination,context) == MagickFalse)
369 status=MagickFalse;
cristybb503372010-05-27 20:51:26 +0000370 for (x=0; x < (ssize_t) destination->region.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000371 PixelGetQuantumColor(destination->pixel_wands[id][x],
372 destination_pixels+x);
373 if (destination_image->colorspace == CMYKColorspace)
cristybb503372010-05-27 20:51:26 +0000374 for (x=0; x < (ssize_t) destination->region.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000375 destination_indexes[x]=PixelGetBlackQuantum(
376 destination->pixel_wands[id][x]);
377 sync=SyncCacheViewAuthenticPixels(destination->view,exception);
378 if (sync == MagickFalse)
379 {
380 InheritException(destination->exception,GetCacheViewException(
381 source->view));
382 status=MagickFalse;
383 }
384 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
385 {
386 MagickBooleanType
387 proceed;
388
cristyb5d5f722009-11-04 03:03:49 +0000389#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +0000390 #pragma omp critical (MagickWand_DuplexTransferPixelViewIterator)
391#endif
392 proceed=SetImageProgress(source_image,DuplexTransferPixelViewTag,
393 progress++,source->region.height);
394 if (proceed == MagickFalse)
395 status=MagickFalse;
396 }
397 }
398 return(status);
399}
400
401/*
402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
403% %
404% %
405% %
406% G e t P i x e l V i e w E x c e p t i o n %
407% %
408% %
409% %
410%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
411%
412% GetPixelViewException() returns the severity, reason, and description of any
413% error that occurs when utilizing a pixel view.
414%
415% The format of the GetPixelViewException method is:
416%
417% char *GetPixelViewException(const PixelWand *pixel_view,
418% ExceptionType *severity)
419%
420% A description of each parameter follows:
421%
422% o pixel_view: the pixel pixel_view.
423%
424% o severity: the severity of the error is returned here.
425%
426*/
427WandExport char *GetPixelViewException(const PixelView *pixel_view,
428 ExceptionType *severity)
429{
430 char
431 *description;
432
433 assert(pixel_view != (const PixelView *) NULL);
434 assert(pixel_view->signature == WandSignature);
435 if (pixel_view->debug != MagickFalse)
436 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",pixel_view->name);
437 assert(severity != (ExceptionType *) NULL);
438 *severity=pixel_view->exception->severity;
439 description=(char *) AcquireQuantumMemory(2UL*MaxTextExtent,
440 sizeof(*description));
441 if (description == (char *) NULL)
442 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
443 pixel_view->name);
444 *description='\0';
445 if (pixel_view->exception->reason != (char *) NULL)
446 (void) CopyMagickString(description,GetLocaleExceptionMessage(
447 pixel_view->exception->severity,pixel_view->exception->reason),
448 MaxTextExtent);
449 if (pixel_view->exception->description != (char *) NULL)
450 {
451 (void) ConcatenateMagickString(description," (",MaxTextExtent);
452 (void) ConcatenateMagickString(description,GetLocaleExceptionMessage(
453 pixel_view->exception->severity,pixel_view->exception->description),
454 MaxTextExtent);
455 (void) ConcatenateMagickString(description,")",MaxTextExtent);
456 }
457 return(description);
458}
459
460/*
461%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
462% %
463% %
464% %
465% G e t P i x e l V i e w H e i g h t %
466% %
467% %
468% %
469%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
470%
471% GetPixelViewHeight() returns the pixel view height.
472%
473% The format of the GetPixelViewHeight method is:
474%
cristybb503372010-05-27 20:51:26 +0000475% size_t GetPixelViewHeight(const PixelView *pixel_view)
cristy3ed852e2009-09-05 21:47:34 +0000476%
477% A description of each parameter follows:
478%
479% o pixel_view: the pixel view.
480%
481*/
cristybb503372010-05-27 20:51:26 +0000482WandExport size_t GetPixelViewHeight(const PixelView *pixel_view)
cristy3ed852e2009-09-05 21:47:34 +0000483{
484 assert(pixel_view != (PixelView *) NULL);
485 assert(pixel_view->signature == WandSignature);
486 return(pixel_view->region.height);
487}
488
489/*
490%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
491% %
492% %
493% %
494% G e t P i x e l V i e w I t e r a t o r %
495% %
496% %
497% %
498%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
499%
500% GetPixelViewIterator() iterates over the pixel view in parallel and calls
501% your get method for each scanline of the view. The pixel region is
502% not confined to the image canvas-- that is you can include negative offsets
503% or widths or heights that exceed the image dimension. Any updates to
504% the pixels in your callback are ignored.
505%
506% Use this pragma:
507%
508% #pragma omp critical
509%
510% to define a section of code in your callback get method that must be
511% executed by a single thread at a time.
512%
513% The format of the GetPixelViewIterator method is:
514%
515% MagickBooleanType GetPixelViewIterator(PixelView *source,
516% GetPixelViewMethod get,void *context)
517%
518% A description of each parameter follows:
519%
520% o source: the source pixel view.
521%
522% o get: the get callback method.
523%
524% o context: the user defined context.
525%
526*/
527WandExport MagickBooleanType GetPixelViewIterator(PixelView *source,
528 GetPixelViewMethod get,void *context)
529{
530#define GetPixelViewTag "PixelView/Get"
531
532 Image
533 *source_image;
534
cristy3ed852e2009-09-05 21:47:34 +0000535 MagickBooleanType
536 status;
537
cristycee97112010-05-28 00:44:52 +0000538 MagickOffsetType
539 progress;
540
541 ssize_t
542 y;
543
cristy3ed852e2009-09-05 21:47:34 +0000544 assert(source != (PixelView *) NULL);
545 assert(source->signature == WandSignature);
546 if (get == (GetPixelViewMethod) NULL)
547 return(MagickFalse);
548 source_image=source->wand->images;
549 status=MagickTrue;
550 progress=0;
cristyb5d5f722009-11-04 03:03:49 +0000551#if defined(MAGICKCORE_OPENMP_SUPPORT)
552 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +0000553#endif
cristybb503372010-05-27 20:51:26 +0000554 for (y=source->region.y; y < (ssize_t) source->region.height; y++)
cristy3ed852e2009-09-05 21:47:34 +0000555 {
556 register const IndexPacket
557 *indexes;
558
559 register const PixelPacket
560 *pixels;
561
cristybb503372010-05-27 20:51:26 +0000562 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000563 id,
564 x;
565
566 if (status == MagickFalse)
567 continue;
568 id=GetOpenMPThreadId();
569 pixels=GetCacheViewVirtualPixels(source->view,source->region.x,y,
570 source->region.width,1,source->exception);
571 if (pixels == (const PixelPacket *) NULL)
572 {
573 status=MagickFalse;
574 continue;
575 }
576 indexes=GetCacheViewVirtualIndexQueue(source->view);
cristybb503372010-05-27 20:51:26 +0000577 for (x=0; x < (ssize_t) source->region.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000578 PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
579 if (source_image->colorspace == CMYKColorspace)
cristybb503372010-05-27 20:51:26 +0000580 for (x=0; x < (ssize_t) source->region.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000581 PixelSetBlackQuantum(source->pixel_wands[id][x],indexes[x]);
582 if (source_image->storage_class == PseudoClass)
cristybb503372010-05-27 20:51:26 +0000583 for (x=0; x < (ssize_t) source->region.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000584 PixelSetIndex(source->pixel_wands[id][x],indexes[x]);
585 if (get(source,context) == MagickFalse)
586 status=MagickFalse;
587 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
588 {
589 MagickBooleanType
590 proceed;
591
cristyb5d5f722009-11-04 03:03:49 +0000592#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +0000593 #pragma omp critical (MagickWand_GetPixelViewIterator)
594#endif
595 proceed=SetImageProgress(source_image,GetPixelViewTag,progress++,
596 source->region.height);
597 if (proceed == MagickFalse)
598 status=MagickFalse;
599 }
600 }
601 return(status);
602}
603
604/*
605%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
606% %
607% %
608% %
609% G e t P i x e l V i e w P i x e l s %
610% %
611% %
612% %
613%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
614%
615% GetPixelViewPixels() returns the pixel view pixel_wands.
616%
617% The format of the GetPixelViewPixels method is:
618%
619% PixelWand *GetPixelViewPixels(const PixelView *pixel_view)
620%
621% A description of each parameter follows:
622%
623% o pixel_view: the pixel view.
624%
625*/
626WandExport PixelWand **GetPixelViewPixels(const PixelView *pixel_view)
627{
cristybb503372010-05-27 20:51:26 +0000628 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000629 id;
630
631 assert(pixel_view != (PixelView *) NULL);
632 assert(pixel_view->signature == WandSignature);
633 id=GetOpenMPThreadId();
634 return(pixel_view->pixel_wands[id]);
635}
636
637/*
638%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
639% %
640% %
641% %
642% G e t P i x e l V i e w W a n d %
643% %
644% %
645% %
646%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
647%
648% GetPixelViewWand() returns the magick wand associated with the pixel view.
649%
650% The format of the GetPixelViewWand method is:
651%
652% MagickWand *GetPixelViewWand(const PixelView *pixel_view)
653%
654% A description of each parameter follows:
655%
656% o pixel_view: the pixel view.
657%
658*/
659WandExport MagickWand *GetPixelViewWand(const PixelView *pixel_view)
660{
661 assert(pixel_view != (PixelView *) NULL);
662 assert(pixel_view->signature == WandSignature);
663 return(pixel_view->wand);
664}
665
666/*
667%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
668% %
669% %
670% %
671% G e t P i x e l V i e w W i d t h %
672% %
673% %
674% %
675%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
676%
677% GetPixelViewWidth() returns the pixel view width.
678%
679% The format of the GetPixelViewWidth method is:
680%
cristybb503372010-05-27 20:51:26 +0000681% size_t GetPixelViewWidth(const PixelView *pixel_view)
cristy3ed852e2009-09-05 21:47:34 +0000682%
683% A description of each parameter follows:
684%
685% o pixel_view: the pixel view.
686%
687*/
cristybb503372010-05-27 20:51:26 +0000688WandExport size_t GetPixelViewWidth(const PixelView *pixel_view)
cristy3ed852e2009-09-05 21:47:34 +0000689{
690 assert(pixel_view != (PixelView *) NULL);
691 assert(pixel_view->signature == WandSignature);
692 return(pixel_view->region.width);
693}
694
695/*
696%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
697% %
698% %
699% %
700% G e t P i x e l V i e w X %
701% %
702% %
703% %
704%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
705%
706% GetPixelViewX() returns the pixel view x offset.
707%
708% The format of the GetPixelViewX method is:
709%
cristybb503372010-05-27 20:51:26 +0000710% ssize_t GetPixelViewX(const PixelView *pixel_view)
cristy3ed852e2009-09-05 21:47:34 +0000711%
712% A description of each parameter follows:
713%
714% o pixel_view: the pixel view.
715%
716*/
cristybb503372010-05-27 20:51:26 +0000717WandExport ssize_t GetPixelViewX(const PixelView *pixel_view)
cristy3ed852e2009-09-05 21:47:34 +0000718{
719 assert(pixel_view != (PixelView *) NULL);
720 assert(pixel_view->signature == WandSignature);
721 return(pixel_view->region.x);
722}
723
724/*
725%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
726% %
727% %
728% %
729% G e t P i x e l V i e w Y %
730% %
731% %
732% %
733%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
734%
735% GetPixelViewY() returns the pixel view y offset.
736%
737% The format of the GetPixelViewY method is:
738%
cristybb503372010-05-27 20:51:26 +0000739% ssize_t GetPixelViewY(const PixelView *pixel_view)
cristy3ed852e2009-09-05 21:47:34 +0000740%
741% A description of each parameter follows:
742%
743% o pixel_view: the pixel view.
744%
745*/
cristybb503372010-05-27 20:51:26 +0000746WandExport ssize_t GetPixelViewY(const PixelView *pixel_view)
cristy3ed852e2009-09-05 21:47:34 +0000747{
748 assert(pixel_view != (PixelView *) NULL);
749 assert(pixel_view->signature == WandSignature);
750 return(pixel_view->region.y);
751}
752
753/*
754%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
755% %
756% %
757% %
758% I s P i x e l V i e w %
759% %
760% %
761% %
762%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
763%
764% IsPixelView() returns MagickTrue if the the parameter is verified as a pixel
765% view container.
766%
767% The format of the IsPixelView method is:
768%
769% MagickBooleanType IsPixelView(const PixelView *pixel_view)
770%
771% A description of each parameter follows:
772%
773% o pixel_view: the pixel view.
774%
775*/
776WandExport MagickBooleanType IsPixelView(const PixelView *pixel_view)
777{
778 size_t
779 length;
780
781 if (pixel_view == (const PixelView *) NULL)
782 return(MagickFalse);
783 if (pixel_view->signature != WandSignature)
784 return(MagickFalse);
785 length=strlen(PixelViewId);
786 if (LocaleNCompare(pixel_view->name,PixelViewId,length) != 0)
787 return(MagickFalse);
788 return(MagickTrue);
789}
790
791/*
792%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
793% %
794% %
795% %
796% N e w P i x e l V i e w %
797% %
798% %
799% %
800%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
801%
802% NewPixelView() returns a pixel view required for all other methods in the
803% Pixel View API.
804%
805% The format of the NewPixelView method is:
806%
807% PixelView *NewPixelView(MagickWand *wand)
808%
809% A description of each parameter follows:
810%
811% o wand: the wand.
812%
813*/
814
cristybb503372010-05-27 20:51:26 +0000815static PixelWand ***AcquirePixelsThreadSet(const size_t number_wands,
816 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000817{
818 PixelWand
819 ***pixel_wands;
820
cristybb503372010-05-27 20:51:26 +0000821 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000822 i;
823
824 pixel_wands=(PixelWand ***) AcquireAlignedMemory(number_threads,
825 sizeof(*pixel_wands));
826 if (pixel_wands == (PixelWand ***) NULL)
827 return((PixelWand ***) NULL);
828 (void) ResetMagickMemory(pixel_wands,0,number_threads*sizeof(*pixel_wands));
cristybb503372010-05-27 20:51:26 +0000829 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000830 {
831 pixel_wands[i]=NewPixelWands(number_wands);
832 if (pixel_wands[i] == (PixelWand **) NULL)
833 return(DestroyPixelsThreadSet(pixel_wands,number_wands,number_threads));
834 }
835 return(pixel_wands);
836}
837
838WandExport PixelView *NewPixelView(MagickWand *wand)
839{
840 PixelView
841 *pixel_view;
842
843 assert(wand != (MagickWand *) NULL);
844 assert(wand->signature == MagickSignature);
cristy90823212009-12-12 20:48:33 +0000845 pixel_view=(PixelView *) AcquireAlignedMemory(1,sizeof(*pixel_view));
cristy3ed852e2009-09-05 21:47:34 +0000846 if (pixel_view == (PixelView *) NULL)
847 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
848 GetExceptionMessage(errno));
849 (void) ResetMagickMemory(pixel_view,0,sizeof(*pixel_view));
850 pixel_view->id=AcquireWandId();
cristye8c25f92010-06-03 00:53:06 +0000851 (void) FormatMagickString(pixel_view->name,MaxTextExtent,"%s-%.20g",
852 PixelViewId,(double) pixel_view->id);
cristy3ed852e2009-09-05 21:47:34 +0000853 pixel_view->exception=AcquireExceptionInfo();
854 pixel_view->wand=wand;
855 pixel_view->view=AcquireCacheView(pixel_view->wand->images);
856 pixel_view->region.width=wand->images->columns;
857 pixel_view->region.height=wand->images->rows;
858 pixel_view->number_threads=GetOpenMPMaximumThreads();
859 pixel_view->pixel_wands=AcquirePixelsThreadSet(pixel_view->region.width,
860 pixel_view->number_threads);
861 if (pixel_view->pixel_wands == (PixelWand ***) NULL)
862 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
863 GetExceptionMessage(errno));
864 pixel_view->debug=IsEventLogging();
865 pixel_view->signature=WandSignature;
866 return(pixel_view);
867}
868
869/*
870%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
871% %
872% %
873% %
874% N e w P i x e l V i e w R e g i o n %
875% %
876% %
877% %
878%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
879%
880% NewPixelViewRegion() returns a pixel view required for all other methods
881% in the Pixel View API.
882%
883% The format of the NewPixelViewRegion method is:
884%
cristybb503372010-05-27 20:51:26 +0000885% PixelView *NewPixelViewRegion(MagickWand *wand,const ssize_t x,
886% const ssize_t y,const size_t width,const size_t height)
cristy3ed852e2009-09-05 21:47:34 +0000887%
888% A description of each parameter follows:
889%
890% o wand: the magick wand.
891%
892% o x,y,columns,rows: These values define the perimeter of a region of
893% pixel_wands view.
894%
895*/
cristybb503372010-05-27 20:51:26 +0000896WandExport PixelView *NewPixelViewRegion(MagickWand *wand,const ssize_t x,
897 const ssize_t y,const size_t width,const size_t height)
cristy3ed852e2009-09-05 21:47:34 +0000898{
899 PixelView
900 *pixel_view;
901
902 assert(wand != (MagickWand *) NULL);
903 assert(wand->signature == MagickSignature);
cristy90823212009-12-12 20:48:33 +0000904 pixel_view=(PixelView *) AcquireAlignedMemory(1,sizeof(*pixel_view));
cristy3ed852e2009-09-05 21:47:34 +0000905 if (pixel_view == (PixelView *) NULL)
906 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
907 GetExceptionMessage(errno));
908 (void) ResetMagickMemory(pixel_view,0,sizeof(*pixel_view));
909 pixel_view->id=AcquireWandId();
cristye8c25f92010-06-03 00:53:06 +0000910 (void) FormatMagickString(pixel_view->name,MaxTextExtent,"%s-%.20g",
911 PixelViewId,(double) pixel_view->id);
cristy3ed852e2009-09-05 21:47:34 +0000912 pixel_view->exception=AcquireExceptionInfo();
913 pixel_view->view=AcquireCacheView(pixel_view->wand->images);
914 pixel_view->wand=wand;
915 pixel_view->region.width=width;
916 pixel_view->region.height=height;
917 pixel_view->region.x=x;
918 pixel_view->region.y=y;
919 pixel_view->number_threads=GetOpenMPMaximumThreads();
920 pixel_view->pixel_wands=AcquirePixelsThreadSet(pixel_view->region.width,
921 pixel_view->number_threads);
922 if (pixel_view->pixel_wands == (PixelWand ***) NULL)
923 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
924 GetExceptionMessage(errno));
925 pixel_view->debug=IsEventLogging();
926 pixel_view->signature=WandSignature;
927 return(pixel_view);
928}
929
930/*
931%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
932% %
933% %
934% %
935% S e t P i x e l V i e w I t e r a t o r %
936% %
937% %
938% %
939%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
940%
941% SetPixelViewIterator() iterates over the pixel view in parallel and calls
942% your set method for each scanline of the view. The pixel region is
943% confined to the image canvas-- that is no negative offsets or widths or
944% heights that exceed the image dimension. The pixels are initiallly
945% undefined and any settings you make in the callback method are automagically
946% synced back to your image.
947%
948% Use this pragma:
949%
950% #pragma omp critical
951%
952% to define a section of code in your callback set method that must be
953% executed by a single thread at a time.
954%
955% The format of the SetPixelViewIterator method is:
956%
957% MagickBooleanType SetPixelViewIterator(PixelView *destination,
958% SetPixelViewMethod set,void *context)
959%
960% A description of each parameter follows:
961%
962% o destination: the pixel view.
963%
964% o set: the set callback method.
965%
966% o context: the user defined context.
967%
968*/
969WandExport MagickBooleanType SetPixelViewIterator(PixelView *destination,
970 SetPixelViewMethod set,void *context)
971{
972#define SetPixelViewTag "PixelView/Set"
973
974 ExceptionInfo
975 *exception;
976
977 Image
978 *destination_image;
979
cristy3ed852e2009-09-05 21:47:34 +0000980 MagickBooleanType
981 status;
982
cristycee97112010-05-28 00:44:52 +0000983 MagickOffsetType
984 progress;
985
986 ssize_t
987 y;
988
cristy3ed852e2009-09-05 21:47:34 +0000989 assert(destination != (PixelView *) NULL);
990 assert(destination->signature == WandSignature);
991 if (set == (SetPixelViewMethod) NULL)
992 return(MagickFalse);
993 destination_image=destination->wand->images;
994 if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
995 return(MagickFalse);
996 status=MagickTrue;
997 progress=0;
998 exception=destination->exception;
cristyb5d5f722009-11-04 03:03:49 +0000999#if defined(MAGICKCORE_OPENMP_SUPPORT)
1000 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +00001001#endif
cristybb503372010-05-27 20:51:26 +00001002 for (y=destination->region.y; y < (ssize_t) destination->region.height; y++)
cristy3ed852e2009-09-05 21:47:34 +00001003 {
1004 MagickBooleanType
1005 sync;
1006
1007 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00001008 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00001009
cristybb503372010-05-27 20:51:26 +00001010 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001011 id,
1012 x;
1013
1014 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001015 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001016
1017 if (status == MagickFalse)
1018 continue;
1019 id=GetOpenMPThreadId();
1020 pixels=GetCacheViewAuthenticPixels(destination->view,destination->region.x,
1021 y,destination->region.width,1,exception);
1022 if (pixels == (PixelPacket *) NULL)
1023 {
1024 InheritException(destination->exception,GetCacheViewException(
1025 destination->view));
1026 status=MagickFalse;
1027 continue;
1028 }
1029 indexes=GetCacheViewAuthenticIndexQueue(destination->view);
1030 if (set(destination,context) == MagickFalse)
1031 status=MagickFalse;
cristybb503372010-05-27 20:51:26 +00001032 for (x=0; x < (ssize_t) destination->region.width; x++)
cristy3ed852e2009-09-05 21:47:34 +00001033 PixelGetQuantumColor(destination->pixel_wands[id][x],pixels+x);
1034 if (destination_image->colorspace == CMYKColorspace)
cristybb503372010-05-27 20:51:26 +00001035 for (x=0; x < (ssize_t) destination->region.width; x++)
cristy3ed852e2009-09-05 21:47:34 +00001036 indexes[x]=PixelGetBlackQuantum(destination->pixel_wands[id][x]);
1037 sync=SyncCacheViewAuthenticPixels(destination->view,exception);
1038 if (sync == MagickFalse)
1039 {
1040 InheritException(destination->exception,GetCacheViewException(
1041 destination->view));
1042 status=MagickFalse;
1043 }
1044 if (destination_image->progress_monitor != (MagickProgressMonitor) NULL)
1045 {
1046 MagickBooleanType
1047 proceed;
1048
cristyb5d5f722009-11-04 03:03:49 +00001049#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +00001050 #pragma omp critical (MagickWand_SetPixelViewIterator)
1051#endif
1052 proceed=SetImageProgress(destination_image,SetPixelViewTag,progress++,
1053 destination->region.height);
1054 if (proceed == MagickFalse)
1055 status=MagickFalse;
1056 }
1057 }
1058 return(status);
1059}
1060
1061/*
1062%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1063% %
1064% %
1065% %
1066% T r a n s f e r P i x e l V i e w I t e r a t o r %
1067% %
1068% %
1069% %
1070%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1071%
1072% TransferPixelViewIterator() iterates over two pixel views in parallel and
1073% calls your transfer method for each scanline of the view. The source pixel
1074% region is not confined to the image canvas-- that is you can include
1075% negative offsets or widths or heights that exceed the image dimension.
1076% However, the destination pixel view is confined to the image canvas-- that
1077% is no negative offsets or widths or heights that exceed the image dimension
1078% are permitted.
1079%
1080% Use this pragma:
1081%
1082% #pragma omp critical
1083%
1084% to define a section of code in your callback transfer method that must be
1085% executed by a single thread at a time.
1086%
1087% The format of the TransferPixelViewIterator method is:
1088%
1089% MagickBooleanType TransferPixelViewIterator(PixelView *source,
1090% PixelView *destination,TransferPixelViewMethod transfer,void *context)
1091%
1092% A description of each parameter follows:
1093%
1094% o source: the source pixel view.
1095%
1096% o destination: the destination pixel view.
1097%
1098% o transfer: the transfer callback method.
1099%
1100% o context: the user defined context.
1101%
1102*/
1103WandExport MagickBooleanType TransferPixelViewIterator(PixelView *source,
1104 PixelView *destination,TransferPixelViewMethod transfer,void *context)
1105{
1106#define TransferPixelViewTag "PixelView/Transfer"
1107
1108 ExceptionInfo
1109 *exception;
1110
1111 Image
1112 *destination_image,
1113 *source_image;
1114
cristy3ed852e2009-09-05 21:47:34 +00001115 MagickBooleanType
1116 status;
1117
cristycee97112010-05-28 00:44:52 +00001118 MagickOffsetType
1119 progress;
1120
1121 ssize_t
1122 y;
1123
cristy3ed852e2009-09-05 21:47:34 +00001124 assert(source != (PixelView *) NULL);
1125 assert(source->signature == WandSignature);
1126 if (transfer == (TransferPixelViewMethod) NULL)
1127 return(MagickFalse);
1128 source_image=source->wand->images;
1129 destination_image=destination->wand->images;
1130 if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
1131 return(MagickFalse);
1132 status=MagickTrue;
1133 progress=0;
1134 exception=destination->exception;
cristyb5d5f722009-11-04 03:03:49 +00001135#if defined(MAGICKCORE_OPENMP_SUPPORT)
1136 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +00001137#endif
cristybb503372010-05-27 20:51:26 +00001138 for (y=source->region.y; y < (ssize_t) source->region.height; y++)
cristy3ed852e2009-09-05 21:47:34 +00001139 {
1140 MagickBooleanType
1141 sync;
1142
1143 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00001144 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00001145
1146 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001147 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001148
1149 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00001150 *restrict destination_indexes;
cristy3ed852e2009-09-05 21:47:34 +00001151
cristybb503372010-05-27 20:51:26 +00001152 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001153 id,
1154 x;
1155
1156 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001157 *restrict destination_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001158
1159 if (status == MagickFalse)
1160 continue;
1161 id=GetOpenMPThreadId();
1162 pixels=GetCacheViewVirtualPixels(source->view,source->region.x,y,
1163 source->region.width,1,source->exception);
1164 if (pixels == (const PixelPacket *) NULL)
1165 {
1166 status=MagickFalse;
1167 continue;
1168 }
1169 indexes=GetCacheViewVirtualIndexQueue(source->view);
cristybb503372010-05-27 20:51:26 +00001170 for (x=0; x < (ssize_t) source->region.width; x++)
cristy3ed852e2009-09-05 21:47:34 +00001171 PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
1172 if (source_image->colorspace == CMYKColorspace)
cristybb503372010-05-27 20:51:26 +00001173 for (x=0; x < (ssize_t) source->region.width; x++)
cristy3ed852e2009-09-05 21:47:34 +00001174 PixelSetBlackQuantum(source->pixel_wands[id][x],indexes[x]);
1175 if (source_image->storage_class == PseudoClass)
cristybb503372010-05-27 20:51:26 +00001176 for (x=0; x < (ssize_t) source->region.width; x++)
cristy3ed852e2009-09-05 21:47:34 +00001177 PixelSetIndex(source->pixel_wands[id][x],indexes[x]);
1178 destination_pixels=GetCacheViewAuthenticPixels(destination->view,
1179 destination->region.x,y,destination->region.width,1,exception);
1180 if (destination_pixels == (PixelPacket *) NULL)
1181 {
1182 status=MagickFalse;
1183 continue;
1184 }
1185 destination_indexes=GetCacheViewAuthenticIndexQueue(destination->view);
cristybb503372010-05-27 20:51:26 +00001186 for (x=0; x < (ssize_t) destination->region.width; x++)
cristy3ed852e2009-09-05 21:47:34 +00001187 PixelSetQuantumColor(destination->pixel_wands[id][x],pixels+x);
1188 if (destination_image->colorspace == CMYKColorspace)
cristybb503372010-05-27 20:51:26 +00001189 for (x=0; x < (ssize_t) destination->region.width; x++)
cristy3ed852e2009-09-05 21:47:34 +00001190 PixelSetBlackQuantum(destination->pixel_wands[id][x],indexes[x]);
1191 if (destination_image->storage_class == PseudoClass)
cristybb503372010-05-27 20:51:26 +00001192 for (x=0; x < (ssize_t) destination->region.width; x++)
cristy3ed852e2009-09-05 21:47:34 +00001193 PixelSetIndex(destination->pixel_wands[id][x],indexes[x]);
1194 if (transfer(source,destination,context) == MagickFalse)
1195 status=MagickFalse;
cristybb503372010-05-27 20:51:26 +00001196 for (x=0; x < (ssize_t) destination->region.width; x++)
cristy3ed852e2009-09-05 21:47:34 +00001197 PixelGetQuantumColor(destination->pixel_wands[id][x],
1198 destination_pixels+x);
1199 if (destination_image->colorspace == CMYKColorspace)
cristybb503372010-05-27 20:51:26 +00001200 for (x=0; x < (ssize_t) destination->region.width; x++)
cristy3ed852e2009-09-05 21:47:34 +00001201 destination_indexes[x]=PixelGetBlackQuantum(
1202 destination->pixel_wands[id][x]);
1203 sync=SyncCacheViewAuthenticPixels(destination->view,exception);
1204 if (sync == MagickFalse)
1205 {
1206 InheritException(destination->exception,GetCacheViewException(
1207 source->view));
1208 status=MagickFalse;
1209 }
1210 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1211 {
1212 MagickBooleanType
1213 proceed;
1214
cristyb5d5f722009-11-04 03:03:49 +00001215#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +00001216 #pragma omp critical (MagickWand_TransferPixelViewIterator)
1217#endif
1218 proceed=SetImageProgress(source_image,TransferPixelViewTag,progress++,
1219 source->region.height);
1220 if (proceed == MagickFalse)
1221 status=MagickFalse;
1222 }
1223 }
1224 return(status);
1225}
1226
1227/*
1228%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1229% %
1230% %
1231% %
1232% U p d a t e P i x e l V i e w I t e r a t o r %
1233% %
1234% %
1235% %
1236%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1237%
1238% UpdatePixelViewIterator() iterates over the pixel view in parallel and calls
1239% your update method for each scanline of the view. The pixel region is
1240% confined to the image canvas-- that is no negative offsets or widths or
1241% heights that exceed the image dimension are permitted. Updates to pixels
1242% in your callback are automagically synced back to the image.
1243%
1244% Use this pragma:
1245%
1246% #pragma omp critical
1247%
1248% to define a section of code in your callback update method that must be
1249% executed by a single thread at a time.
1250%
1251% The format of the UpdatePixelViewIterator method is:
1252%
1253% MagickBooleanType UpdatePixelViewIterator(PixelView *source,
1254% UpdatePixelViewMethod update,void *context)
1255%
1256% A description of each parameter follows:
1257%
1258% o source: the source pixel view.
1259%
1260% o update: the update callback method.
1261%
1262% o context: the user defined context.
1263%
1264*/
1265WandExport MagickBooleanType UpdatePixelViewIterator(PixelView *source,
1266 UpdatePixelViewMethod update,void *context)
1267{
1268#define UpdatePixelViewTag "PixelView/Update"
1269
1270 ExceptionInfo
1271 *exception;
1272
1273 Image
1274 *source_image;
1275
cristy3ed852e2009-09-05 21:47:34 +00001276 MagickBooleanType
1277 status;
1278
cristycee97112010-05-28 00:44:52 +00001279 MagickOffsetType
1280 progress;
1281
1282 ssize_t
1283 y;
1284
cristy3ed852e2009-09-05 21:47:34 +00001285 assert(source != (PixelView *) NULL);
1286 assert(source->signature == WandSignature);
1287 if (update == (UpdatePixelViewMethod) NULL)
1288 return(MagickFalse);
1289 source_image=source->wand->images;
1290 if (SetImageStorageClass(source_image,DirectClass) == MagickFalse)
1291 return(MagickFalse);
1292 status=MagickTrue;
1293 progress=0;
1294 exception=source->exception;
cristyb5d5f722009-11-04 03:03:49 +00001295#if defined(MAGICKCORE_OPENMP_SUPPORT)
1296 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +00001297#endif
cristybb503372010-05-27 20:51:26 +00001298 for (y=source->region.y; y < (ssize_t) source->region.height; y++)
cristy3ed852e2009-09-05 21:47:34 +00001299 {
1300 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00001301 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00001302
cristybb503372010-05-27 20:51:26 +00001303 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001304 id,
1305 x;
1306
1307 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001308 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001309
1310 if (status == MagickFalse)
1311 continue;
1312 id=GetOpenMPThreadId();
1313 pixels=GetCacheViewAuthenticPixels(source->view,source->region.x,y,
1314 source->region.width,1,exception);
1315 if (pixels == (PixelPacket *) NULL)
1316 {
1317 InheritException(source->exception,GetCacheViewException(
1318 source->view));
1319 status=MagickFalse;
1320 continue;
1321 }
1322 indexes=GetCacheViewAuthenticIndexQueue(source->view);
cristybb503372010-05-27 20:51:26 +00001323 for (x=0; x < (ssize_t) source->region.width; x++)
cristy3ed852e2009-09-05 21:47:34 +00001324 PixelSetQuantumColor(source->pixel_wands[id][x],pixels+x);
1325 if (source_image->colorspace == CMYKColorspace)
cristybb503372010-05-27 20:51:26 +00001326 for (x=0; x < (ssize_t) source->region.width; x++)
cristy3ed852e2009-09-05 21:47:34 +00001327 PixelSetBlackQuantum(source->pixel_wands[id][x],indexes[x]);
1328 if (update(source,context) == MagickFalse)
1329 status=MagickFalse;
cristybb503372010-05-27 20:51:26 +00001330 for (x=0; x < (ssize_t) source->region.width; x++)
cristy3ed852e2009-09-05 21:47:34 +00001331 PixelGetQuantumColor(source->pixel_wands[id][x],pixels+x);
1332 if (source_image->colorspace == CMYKColorspace)
cristybb503372010-05-27 20:51:26 +00001333 for (x=0; x < (ssize_t) source->region.width; x++)
cristy3ed852e2009-09-05 21:47:34 +00001334 indexes[x]=PixelGetBlackQuantum(source->pixel_wands[id][x]);
1335 if (SyncCacheViewAuthenticPixels(source->view,exception) == MagickFalse)
1336 {
1337 InheritException(source->exception,GetCacheViewException(source->view));
1338 status=MagickFalse;
1339 }
1340 if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
1341 {
1342 MagickBooleanType
1343 proceed;
1344
cristyb5d5f722009-11-04 03:03:49 +00001345#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +00001346 #pragma omp critical (MagickWand_UpdatePixelViewIterator)
1347#endif
1348 proceed=SetImageProgress(source_image,UpdatePixelViewTag,progress++,
1349 source->region.height);
1350 if (proceed == MagickFalse)
1351 status=MagickFalse;
1352 }
1353 }
1354 return(status);
1355}