/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- SetRegionThreads
- InitializePixelIteratorOptions
- PixelIterateMonoRead
- PixelIterateMonoModify
- PixelIterateDualRead
- PixelIterateDualImplementation
- PixelIterateDualModify
- PixelIterateDualNew
- PixelIterateTripleImplementation
- PixelIterateTripleModify
- PixelIterateTripleNew
/*
% Copyright (C) 2004-2010 GraphicsMagick Group
%
% This program is covered by multiple licenses, which are described in
% Copyright.txt. You should have received a copy of Copyright.txt with this
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
%
% Interfaces to support simple iterative pixel read/update access within
% an image or between two images.
%
% Written by Bob Friesenhahn, March 2004, Updated for rows 2008.
%
*/
#include "magick/studio.h"
#include "magick/monitor.h"
#include "magick/pixel_cache.h"
#include "magick/pixel_iterator.h"
#include "magick/utility.h"
/*
Temporarily set the maximum numer of threads to use based on
user options and region size. The max_threads parameter should
be initialized with the value returned by omp_get_max_threads().
The number of threads actually used is returned.
*/
static int
SetRegionThreads(const int max_threads,
const PixelIteratorOptions *options,
const unsigned long columns,
const unsigned long rows)
{
static const unsigned long
tiny_region_metric = 64;
int
region_threads;
region_threads=max_threads;
if ((options) && (options->max_threads > 0))
{
/*
Allow the user to specify the number of threads, up to the
current limit.
*/
region_threads=Min(max_threads,options->max_threads);
}
else if (((columns <= tiny_region_metric && rows <= tiny_region_metric)) ||
((magick_uint64_t) columns*rows <= tiny_region_metric*tiny_region_metric))
{
/*
Run tiny regions single threaded.
*/
region_threads=1;
}
if (region_threads < max_threads)
{
omp_set_num_threads(region_threads);
}
return region_threads;
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% I n i t i a l i z e P i x e l I t e r a t o r O p t i o n s %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% InitializePixelIteratorOptions() assigns default options to a user-provided
% PixelIteratorOptions structure. This function should always be used
% to initialize the PixelIteratorOptions structure prior to making any
% changes to it.
%
% The format of the InitializePixelIteratorOptions method is:
%
% void InitializePixelIteratorOptions(PixelIteratorOptions *options,
% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o options: pointer to PixelIteratorOptions structure to initialize.
%
% o exception: Return any errors or warnings in this structure.
%
*/
MagickExport void
InitializePixelIteratorOptions(PixelIteratorOptions *options,
ExceptionInfo *exception)
{
ARG_NOT_USED(exception);
assert(options != (PixelIteratorOptions *) NULL);
options->max_threads=0;
options->signature=MagickSignature;
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% P i x e l I t e r a t e M o n o R e a d %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% PixelIterateMonoRead() iterates through a region of an image and invokes a
% user-provided callback function (of type PixelRowIteratorMonoReadCallback)
% for a row of pixels. This is useful to support simple operations such as
% statistics computation.
%
% The format of the PixelIterateMonoRead method is:
%
% MagickPassFail PixelIterateMonoRead(
% PixelIteratorMonoReadCallback call_back,
% const PixelIteratorOptions *options,
% const char *description,
% void *mutable_data,
% const void *immutable_data,
% const long x,
% const long y,
% const unsigned long columns,
% const unsigned long rows,
% const Image *image,
% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o call_back: A user-provided C callback function which is passed the
% address of pixels from each image.
%
% o options: Pixel iterator execution options (may be NULL).
%
% o description: textual description of operation being performed.
%
% o mutable_data: User-provided mutable context data.
%
% o immutable_data: User-provided immutable context data.
%
% o x: The horizontal ordinate of the top left corner of the region.
%
% o y: The vertical ordinate of the top left corner of the region.
%
% o columns: Width of pixel region
%
% o rows: Height of pixel region
%
% o image: The address of the Image.
%
% o exception: If an error is reported, this argument is updated with the reason.
%
*/
MagickExport MagickPassFail
PixelIterateMonoRead(PixelIteratorMonoReadCallback call_back,
const PixelIteratorOptions *options,
const char *description,
void *mutable_data,
const void *immutable_data,
const long x,
const long y,
const unsigned long columns,
const unsigned long rows,
const Image *image,
ExceptionInfo *exception)
{
MagickPassFail
status = MagickPass;
register long
row;
unsigned long
row_count=0;
int
max_threads=1;
max_threads=omp_get_max_threads();
(void) SetRegionThreads(max_threads,options,columns,rows);
#if defined(HAVE_OPENMP)
# pragma omp parallel for schedule(static,1) shared(row_count, status)
#endif
for (row=y; row < (long) (y+rows); row++)
{
MagickPassFail
thread_status;
const PixelPacket
* restrict pixels;
const IndexPacket
* restrict indexes;
thread_status=status;
if (thread_status == MagickFail)
continue;
pixels=AcquireImagePixels(image,x, row, columns, 1, exception);
if (!pixels)
thread_status=MagickFail;
indexes=AccessImmutableIndexes(image);
if (thread_status != MagickFail)
thread_status=(call_back)(mutable_data,immutable_data,image,pixels,indexes,columns,exception);
#if defined(HAVE_OPENMP)
# pragma omp critical (GM_PixelIterateMonoRead)
#endif
{
row_count++;
if (QuantumTick(row_count,rows))
if (!MagickMonitorFormatted(row_count,rows,exception,
description,image->filename))
thread_status=MagickFail;
if (thread_status == MagickFail)
status=MagickFail;
}
}
omp_set_num_threads(max_threads);
return (status);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% P i x e l I t e r a t e M o n o M o d i f y %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% PixelIterateMonoModify() iterates through a region of an image and invokes
% a user-provided callback function (of type PixelIteratorMonoReadCallback)
% for a region of pixels. This is useful to support simple operations such as
% level shifting, colorspace translation, or thresholding.
%
% The format of the PixelIterateMonoModify method is:
%
% MagickPassFail PixelIterateMonoModify(
% PixelIteratorMonoModifyCallback call_back,
% const PixelIteratorOptions *options,
% const char *description,
% void *mutable_data,
% const void *immutable_data,
% const long x,
% const long y,
% const unsigned long columns,
% const unsigned long rows,
% Image *image,
% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o call_back: A user-provided C callback function which is passed the
% address of pixels from each image.
%
% o options: Pixel iterator execution options (may be NULL).
%
% o description: textual description of operation being performed.
%
% o mutable_data: User-provided mutable context data.
%
% o immutable_data: User-provided immutable context data.
%
% o x: The horizontal ordinate of the top left corner of the region.
%
% o y: The vertical ordinate of the top left corner of the region.
%
% o columns: Width of pixel region
%
% o rows: Height of pixel region
%
% o image: The address of the Image.
%
% o exception: If an error is reported, this argument is updated with the reason.
%
*/
MagickExport MagickPassFail
PixelIterateMonoModify(PixelIteratorMonoModifyCallback call_back,
const PixelIteratorOptions *options,
const char *description,
void *mutable_data,
const void *immutable_data,
const long x,
const long y,
const unsigned long columns,
const unsigned long rows,
Image *image,
ExceptionInfo *exception)
{
MagickPassFail
status = MagickPass;
register long
row;
unsigned long
row_count=0;
int
max_threads;
max_threads=omp_get_max_threads();
(void) SetRegionThreads(max_threads,options,columns,rows);
#if defined(HAVE_OPENMP)
# pragma omp parallel for schedule(static,1) shared(row_count, status)
#endif
for (row=y; row < (long) (y+rows); row++)
{
MagickBool
thread_status;
PixelPacket
* restrict pixels;
IndexPacket
* restrict indexes;
thread_status=status;
if (thread_status == MagickFail)
continue;
pixels=GetImagePixelsEx(image, x, row, columns, 1, exception);
if (!pixels)
thread_status=MagickFail;
indexes=AccessMutableIndexes(image);
if (thread_status != MagickFail)
thread_status=(call_back)(mutable_data,immutable_data,image,pixels,indexes,columns,exception);
if (thread_status != MagickFail)
if (!SyncImagePixelsEx(image,exception))
thread_status=MagickFail;
#if defined(HAVE_OPENMP)
# pragma omp critical (GM_PixelIterateMonoModify)
#endif
{
row_count++;
if (QuantumTick(row_count,rows))
if (!MagickMonitorFormatted(row_count,rows,exception,
description,image->filename))
thread_status=MagickFail;
if (thread_status == MagickFail)
status=MagickFail;
}
}
omp_set_num_threads(max_threads);
return (status);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% P i x e l I t e r a t e D u a l R e a d %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% PixelIterateDualRead() iterates through pixel regions of two images and
% invokes a user-provided callback function (of type
% PixelIteratorDualReadCallback) for each row of pixels. This is useful to
% support operations such as image comparison.
%
% The format of the PixelIterateDualModify method is:
%
% MagickPassFail PixelIterateDualRead(
% PixelIteratorDualReadCallback call_back,
% const PixelIteratorOptions *options,
% const char *description,
% void *mutable_data,
% const void *immutable_data,
% const unsigned long columns,
% const unsigned long rows,
% const Image *first_image,
% const long first_x,
% const long first_y,
% const Image *second_image,
% const long second_x,
% const long second_y,
% ExceptionInfo *exception);
%
% A description of each parameter follows:
%
% o call_back: A user-provided C callback function which is passed the
% address of pixels from each image.
%
% o options: Pixel iterator execution options (may be NULL).
%
% o description: textual description of operation being performed.
%
% o mutable_data: User-provided mutable context data.
%
% o immutable_data: User-provided immutable context data.
%
% o columns: Width of pixel region
%
% o rows: Height of pixel region
%
% o first_image: The address of the first Image.
%
% o first_x: The horizontal ordinate of the top left corner of the first region.
%
% o first_y: The vertical ordinate of the top left corner of the first region.
%
% o second_image: The address of the second Image.
%
% o second_x: The horizontal ordinate of the top left corner of the second region.
%
% o second_y: The vertical ordinate of the top left corner of the second region.
%
% o exception: If an error is reported, this argument is updated with the reason.
%
*/
MagickExport MagickPassFail
PixelIterateDualRead(PixelIteratorDualReadCallback call_back,
const PixelIteratorOptions *options,
const char *description,
void *mutable_data,
const void *immutable_data,
const unsigned long columns,
const unsigned long rows,
const Image *first_image,
const long first_x,
const long first_y,
const Image *second_image,
const long second_x,
const long second_y,
ExceptionInfo *exception)
{
MagickPassFail
status = MagickPass;
register long
row;
unsigned long
row_count=0;
int
max_threads;
max_threads=omp_get_max_threads();
(void) SetRegionThreads(max_threads,options,columns,rows);
#if defined(HAVE_OPENMP)
# pragma omp parallel for schedule(static,1) shared(row_count, status)
#endif
for (row=0; row < (long) rows; row++)
{
MagickBool
thread_status;
long
first_row,
second_row;
const PixelPacket
* restrict first_pixels,
* restrict second_pixels;
const IndexPacket
* restrict first_indexes,
* restrict second_indexes;
thread_status=status;
if (thread_status == MagickFail)
continue;
first_row=first_y+row;
second_row=second_y+row;
first_pixels=AcquireImagePixels(first_image, first_x, first_row,
columns, 1, exception);
if (!first_pixels)
thread_status=MagickFail;
first_indexes=AccessImmutableIndexes(first_image);
second_pixels=AcquireImagePixels(second_image, second_x, second_row,
columns, 1, exception);
if (!second_pixels)
thread_status=MagickFail;
second_indexes=AccessImmutableIndexes(second_image);
if (thread_status != MagickFail)
thread_status=(call_back)(mutable_data,immutable_data,
first_image,first_pixels,first_indexes,
second_image,second_pixels,second_indexes,
columns, exception);
#if defined(HAVE_OPENMP)
# pragma omp critical (GM_PixelIterateDualRead)
#endif
{
row_count++;
if (QuantumTick(row_count,rows))
if (!MagickMonitorFormatted(row_count,rows,exception,
description,first_image->filename,
second_image->filename))
thread_status=MagickFail;
if (thread_status == MagickFail)
status=MagickFail;
}
}
omp_set_num_threads(max_threads);
return (status);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% P i x e l I t e r a t e D u a l M o d i f y %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% PixelIterateDualModify() iterates through pixel regions of two images and
% invokes a user-provided callback function (of type
% PixelIteratorDualModifyCallback) for each row of pixels. This is useful to
% support operations such as composition.
%
% The format of the PixelIterateDualModify method is:
%
% MagickPassFail PixelIterateDualModify(
% PixelIteratorDualModifyCallback call_back,
% const PixelIteratorOptions *options,
% const char *description,
% void *mutable_data,
% const void *immutable_data,
% const unsigned long columns,
% const unsigned long rows,
% const Image *source_image,
% const long source_x,
% const long source_y,
% Image *update_image,
% const long update_x,
% const long update_y,
% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o call_back: A user-provided C callback function which reads from
% a region of source pixels and updates a region of destination pixels.
%
% o options: Pixel iterator execution options (may be NULL).
%
% o description: textual description of operation being performed.
%
% o mutable_data: User-provided mutable context data.
%
% o immutable_data: User-provided immutable context data.
%
% o columns: Width of pixel region
%
% o rows: Height of pixel region
%
% o source_image: The address of the constant source Image.
%
% o source_x: The horizontal ordinate of the top left corner of the source region.
%
% o source_y: The vertical ordinate of the top left corner of the source region.
%
% o update_image: The address of the update Image.
%
% o update_x: The horizontal ordinate of the top left corner of the update region.
%
% o update_y: The vertical ordinate of the top left corner of the update region.
%
% o exception: If an error is reported, this argument is updated with the reason.
%
*/
static MagickPassFail
PixelIterateDualImplementation(PixelIteratorDualModifyCallback call_back,
const PixelIteratorOptions *options,
const char *description,
void *mutable_data,
const void *immutable_data,
const unsigned long columns,
const unsigned long rows,
const Image *source_image,
const long source_x,
const long source_y,
Image *update_image,
const long update_x,
const long update_y,
ExceptionInfo *exception,
MagickBool set)
{
MagickPassFail
status = MagickPass;
register long
row;
unsigned long
row_count=0;
int
max_threads;
max_threads=omp_get_max_threads();
(void) SetRegionThreads(max_threads,options,columns,rows);
#if defined(HAVE_OPENMP)
# pragma omp parallel for schedule(static,1) shared(row_count, status)
#endif
for (row=0; row < (long) rows; row++)
{
MagickBool
thread_status;
const PixelPacket
* restrict source_pixels;
const IndexPacket
* restrict source_indexes;
PixelPacket
* restrict update_pixels;
IndexPacket
* restrict update_indexes;
register long
source_row,
update_row;
thread_status=status;
if (thread_status == MagickFail)
continue;
source_row=source_y+row;
update_row=update_y+row;
source_pixels=AcquireImagePixels(source_image, source_x, source_row,
columns, 1, exception);
if (!source_pixels)
thread_status=MagickFail;
source_indexes=AccessImmutableIndexes(source_image);
if (set)
update_pixels=SetImagePixelsEx(update_image, update_x, update_row,
columns, 1, exception);
else
update_pixels=GetImagePixelsEx(update_image, update_x, update_row,
columns, 1, exception);
if (!update_pixels)
thread_status=MagickFail;
update_indexes=AccessMutableIndexes(update_image);
if (thread_status != MagickFail)
thread_status=(call_back)(mutable_data,immutable_data,
source_image,source_pixels,source_indexes,
update_image,update_pixels,update_indexes,
columns,exception);
if (thread_status != MagickFail)
if (!SyncImagePixelsEx(update_image,exception))
thread_status=MagickFail;
#if defined(HAVE_OPENMP)
# pragma omp critical (GM_PixelIterateDualImplementation)
#endif
{
row_count++;
if (QuantumTick(row_count,rows))
if (!MagickMonitorFormatted(row_count,rows,exception,
description,source_image->filename,
update_image->filename))
thread_status=MagickFail;
if (thread_status == MagickFail)
status=MagickFail;
}
}
omp_set_num_threads(max_threads);
return (status);
}
MagickExport MagickPassFail
PixelIterateDualModify(PixelIteratorDualModifyCallback call_back,
const PixelIteratorOptions *options,
const char *description,
void *mutable_data,
const void *immutable_data,
const unsigned long columns,
const unsigned long rows,
const Image *source_image,
const long source_x,
const long source_y,
Image *update_image,
const long update_x,
const long update_y,
ExceptionInfo *exception)
{
return PixelIterateDualImplementation
(call_back,options,description,mutable_data,immutable_data,columns,rows,
source_image,source_x,source_y,update_image,update_x,update_y,exception,
MagickFalse);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% P i x e l I t e r a t e D u a l N e w %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% PixelIterateDualNew() iterates through pixel regions of two images and
% invokes a user-provided callback function (of type
% PixelIteratorDualNewCallback) for each row of pixels. This is used if a
% new output image is created based on an input image. The difference from
% PixelIterateDualModify() is that the output pixels are not initialized so
% it is more efficient when outputting a new image.
%
% The format of the PixelIterateDualNew method is:
%
% MagickPassFail PixelIterateDualNew(
% PixelIteratorDualNewCallback call_back,
% const PixelIteratorOptions *options,
% const char *description,
% void *mutable_data,
% const void *immutable_data,
% const unsigned long columns,
% const unsigned long rows,
% const Image *source_image,
% const long source_x,
% const long source_y,
% Image *new_image,
% const long new_x,
% const long new_y,
% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o call_back: A user-provided C callback function which reads from
% a region of source pixels and initializes a region of destination pixels.
%
% o options: Pixel iterator execution options (may be NULL).
%
% o description: textual description of operation being performed.
%
% o mutable_data: User-provided mutable context data.
%
% o immutable_data: User-provided immutable context data.
%
% o columns: Width of pixel region
%
% o rows: Height of pixel region
%
% o source_image: The address of the constant source Image.
%
% o source_x: The horizontal ordinate of the top left corner of the source region.
%
% o source_y: The vertical ordinate of the top left corner of the source region.
%
% o new_image: The address of the new Image.
%
% o new_x: The horizontal ordinate of the top left corner of the new region.
%
% o new_y: The vertical ordinate of the top left corner of the new region.
%
% o exception: If an error is reported, this argument is updated with the reason.
%
*/
MagickExport MagickPassFail
PixelIterateDualNew(PixelIteratorDualNewCallback call_back,
const PixelIteratorOptions *options,
const char *description,
void *mutable_data,
const void *immutable_data,
const unsigned long columns,
const unsigned long rows,
const Image *source_image,
const long source_x,
const long source_y,
Image *new_image,
const long new_x,
const long new_y,
ExceptionInfo *exception)
{
return PixelIterateDualImplementation
(call_back,options,description,mutable_data,immutable_data,columns,rows,
source_image,source_x,source_y,new_image,new_x,new_y,exception,
MagickTrue);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% P i x e l I t e r a t e T r i p l e M o d i f y %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% PixelIterateTripleModify() iterates through pixel regions of three images
% and invokes a user-provided callback function (of type
% PixelIteratorTripleModifyCallback) for each row of pixels. The first two
% images are read-only, while the third image is read-write for update.
% Access of the first two images is done lock-step using the same coordinates.
% This is useful to support operations such as image differencing.
%
% The format of the PixelIterateTripleModify method is:
%
% MagickPassFail PixelIterateTripleModify(
% PixelIteratorTripleModifyCallback call_back,
% const PixelIteratorOptions *options,
% const char *description,
% void *mutable_data,
% const void *immutable_data,
% const unsigned long columns,
% const unsigned long rows,
% const Image *source1_image,
% const Image *source2_image,
% const long source_x,
% const long source_y,
% Image *update_image,
% const long update_x,
% const long update_y,
% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o call_back: A user-provided C callback function which reads from
% a region of source pixels and updates a region of destination pixels.
%
% o options: Pixel iterator execution options (may be NULL).
%
% o description: textual description of operation being performed.
%
% o mutable_data: User-provided mutable context data.
%
% o immutable_data: User-provided immutable context data.
%
% o columns: Width of pixel region
%
% o rows: Height of pixel region
%
% o source1_image: The address of the constant source 1 Image.
%
% o source2_image: The address of the constant source 2 Image.
%
% o source_x: The horizontal ordinate of the top left corner of the source regions.
%
% o source_y: The vertical ordinate of the top left corner of the source regions.
%
% o update_image: The address of the update Image.
%
% o update_x: The horizontal ordinate of the top left corner of the update region.
%
% o update_y: The vertical ordinate of the top left corner of the update region.
%
% o exception: If an error is reported, this argument is updated with the reason.
%
*/
static MagickPassFail
PixelIterateTripleImplementation(PixelIteratorTripleModifyCallback call_back,
const PixelIteratorOptions *options,
const char *description,
void *mutable_data,
const void *immutable_data,
const unsigned long columns,
const unsigned long rows,
const Image *source1_image,
const Image *source2_image,
const long source_x,
const long source_y,
Image *update_image,
const long update_x,
const long update_y,
ExceptionInfo *exception,
MagickBool set)
{
MagickPassFail
status = MagickPass;
register long
row;
unsigned long
row_count=0;
int
max_threads;
max_threads=omp_get_max_threads();
(void) SetRegionThreads(max_threads,options,columns,rows);
#if defined(HAVE_OPENMP)
# pragma omp parallel for schedule(static,1) shared(row_count, status)
#endif
for (row=0; row < (long) rows; row++)
{
MagickBool
thread_status;
const PixelPacket
* restrict source1_pixels,
* restrict source2_pixels;
const IndexPacket
* restrict source1_indexes,
* restrict source2_indexes;
PixelPacket
* restrict update_pixels;
IndexPacket
* restrict update_indexes;
long
source_row,
update_row;
thread_status=status;
if (thread_status == MagickFail)
continue;
source_row=source_y+row;
update_row=update_y+row;
/*
First image (read only).
*/
source1_pixels=AcquireImagePixels(source1_image, source_x, source_row,
columns, 1, exception);
if (!source1_pixels)
thread_status=MagickFail;
source1_indexes=AccessImmutableIndexes(source1_image);
/*
Second image (read only).
*/
source2_pixels=AcquireImagePixels(source2_image, source_x, source_row,
columns, 1, exception);
if (!source2_pixels)
thread_status=MagickFail;
source2_indexes=AccessImmutableIndexes(source2_image);
/*
Third image (read/write).
*/
if (set)
update_pixels=SetImagePixelsEx(update_image, update_x, update_row,
columns, 1, exception);
else
update_pixels=GetImagePixelsEx(update_image, update_x, update_row,
columns, 1, exception);
if (!update_pixels)
{
thread_status=MagickFail;
CopyException(exception,&update_image->exception);
}
update_indexes=AccessMutableIndexes(update_image);
if (thread_status != MagickFail)
status=(call_back)(mutable_data,immutable_data,
source1_image,source1_pixels,source1_indexes,
source2_image,source2_pixels,source2_indexes,
update_image,update_pixels,update_indexes,
columns,exception);
if (!SyncImagePixelsEx(update_image,exception))
thread_status=MagickFail;
#if defined(HAVE_OPENMP)
# pragma omp critical (GM_PixelIterateTripleImplementation)
#endif
{
row_count++;
if (QuantumTick(row_count,rows))
if (!MagickMonitorFormatted(row_count,rows,exception,description,
source1_image->filename,
source2_image->filename,
update_image->filename))
thread_status=MagickFail;
if (thread_status == MagickFail)
status=MagickFail;
}
}
omp_set_num_threads(max_threads);
return (status);
}
MagickExport MagickPassFail
PixelIterateTripleModify(PixelIteratorTripleModifyCallback call_back,
const PixelIteratorOptions *options,
const char *description,
void *mutable_data,
const void *immutable_data,
const unsigned long columns,
const unsigned long rows,
const Image *source1_image,
const Image *source2_image,
const long source_x,
const long source_y,
Image *update_image,
const long update_x,
const long update_y,
ExceptionInfo *exception)
{
return PixelIterateTripleImplementation
(call_back,options,description,mutable_data,immutable_data,columns,rows,
source1_image,source2_image,source_x,source_y,
update_image,update_x,update_y,
exception,MagickFalse);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% P i x e l I t e r a t e T r i p l e N e w %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% PixelIterateTripleNew() iterates through pixel regions of three images
% and invokes a user-provided callback function (of type
% PixelIteratorTripleNewCallback) for each row of pixels. The first two
% images are read-only, while the third image is read-write for update.
% Access of the first two images is done lock-step using the same coordinates.
% This is used if a new output image is created based on two input images.
% The difference from PixelIterateTripleModify() is that the output pixels
% are not initialized so it is more efficient when outputting a new image.
%
% The format of the PixelIterateTripleNew method is:
%
% MagickPassFail PixelIterateTripleNew(
% PixelIteratorTripleNewCallback call_back,
% const PixelIteratorOptions *options,
% const char *description,
% void *mutable_data,
% const void *immutable_data,
% const unsigned long columns,
% const unsigned long rows,
% const Image *source1_image,
% const Image *source2_image,
% const long source_x,
% const long source_y,
% Image *new_image,
% const long new_x,
% const long new_y,
% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o call_back: A user-provided C callback function which reads from
% a region of source pixels and initializes a region of destination pixels.
%
% o options: Pixel iterator execution options (may be NULL).
%
% o description: textual description of operation being performed.
%
% o mutable_data: User-provided mutable context data.
%
% o immutable_data: User-provided immutable context data.
%
% o columns: Width of pixel region
%
% o rows: Height of pixel region
%
% o source1_image: The address of the constant source 1 Image.
%
% o source2_image: The address of the constant source 2 Image.
%
% o source_x: The horizontal ordinate of the top left corner of the source regions.
%
% o source_y: The vertical ordinate of the top left corner of the source regions.
%
% o new_image: The address of the new Image.
%
% o new_x: The horizontal ordinate of the top left corner of the new region.
%
% o new_y: The vertical ordinate of the top left corner of the new region.
%
% o exception: If an error is reported, this argument is updated with the reason.
%
*/
MagickExport MagickPassFail
PixelIterateTripleNew(PixelIteratorTripleNewCallback call_back,
const PixelIteratorOptions *options,
const char *description,
void *mutable_data,
const void *immutable_data,
const unsigned long columns,
const unsigned long rows,
const Image *source1_image,
const Image *source2_image,
const long source_x,
const long source_y,
Image *new_image,
const long new_x,
const long new_y,
ExceptionInfo *exception)
{
return PixelIterateTripleImplementation
(call_back,options,description,mutable_data,immutable_data,columns,rows,
source1_image,source2_image,source_x,source_y,
new_image,new_x,new_y,
exception,MagickTrue);
}