|
|
/*
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
% %
|
|
|
% %
|
|
|
% W W AAA N N DDDD %
|
|
|
% W W A A NN N D D %
|
|
|
% W W W AAAAA N N N D D %
|
|
|
% WW WW A A N NN D D %
|
|
|
% W W A A N N DDDD %
|
|
|
% %
|
|
|
% V V IIIII EEEEE W W %
|
|
|
% V V I E W W %
|
|
|
% V V I EEE W W W %
|
|
|
% V V I E WW WW %
|
|
|
% V IIIII EEEEE W W %
|
|
|
% %
|
|
|
% %
|
|
|
% MagickWand Wand View Methods %
|
|
|
% %
|
|
|
% Software Design %
|
|
|
% Cristy %
|
|
|
% March 2003 %
|
|
|
% %
|
|
|
% %
|
|
|
% Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization %
|
|
|
% dedicated to making software imaging solutions freely available. %
|
|
|
% %
|
|
|
% You may not use this file except in compliance with the License. You may %
|
|
|
% obtain a copy of the License at %
|
|
|
% %
|
|
|
% https://imagemagick.org/script/license.php %
|
|
|
% %
|
|
|
% Unless required by applicable law or agreed to in writing, software %
|
|
|
% distributed under the License is distributed on an "AS IS" BASIS, %
|
|
|
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
|
|
|
% See the License for the specific language governing permissions and %
|
|
|
% limitations under the License. %
|
|
|
% %
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
%
|
|
|
%
|
|
|
%
|
|
|
*/
|
|
|
|
|
|
/*
|
|
|
Include declarations.
|
|
|
*/
|
|
|
#include "MagickWand/studio.h"
|
|
|
#include "MagickWand/MagickWand.h"
|
|
|
#include "MagickWand/magick-wand-private.h"
|
|
|
#include "MagickWand/wand.h"
|
|
|
#include "MagickCore/monitor-private.h"
|
|
|
#include "MagickCore/thread-private.h"
|
|
|
/*
|
|
|
Define declarations.
|
|
|
*/
|
|
|
#define WandViewId "WandView"
|
|
|
|
|
|
/*
|
|
|
Typedef declarations.
|
|
|
*/
|
|
|
struct _WandView
|
|
|
{
|
|
|
size_t
|
|
|
id;
|
|
|
|
|
|
char
|
|
|
name[MagickPathExtent],
|
|
|
*description;
|
|
|
|
|
|
RectangleInfo
|
|
|
extent;
|
|
|
|
|
|
MagickWand
|
|
|
*wand;
|
|
|
|
|
|
Image
|
|
|
*image;
|
|
|
|
|
|
CacheView
|
|
|
*view;
|
|
|
|
|
|
PixelWand
|
|
|
***pixel_wands;
|
|
|
|
|
|
ExceptionInfo
|
|
|
*exception;
|
|
|
|
|
|
MagickBooleanType
|
|
|
debug;
|
|
|
|
|
|
size_t
|
|
|
signature;
|
|
|
};
|
|
|
|
|
|
/*
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
% C l o n e W a n d V i e w %
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
%
|
|
|
% CloneWandView() makes a copy of the specified wand view.
|
|
|
%
|
|
|
% The format of the CloneWandView method is:
|
|
|
%
|
|
|
% WandView *CloneWandView(const WandView *wand_view)
|
|
|
%
|
|
|
% A description of each parameter follows:
|
|
|
%
|
|
|
% o wand_view: the wand view.
|
|
|
%
|
|
|
*/
|
|
|
WandExport WandView *CloneWandView(const WandView *wand_view)
|
|
|
{
|
|
|
WandView
|
|
|
*clone_view;
|
|
|
|
|
|
ssize_t
|
|
|
i;
|
|
|
|
|
|
assert(wand_view != (WandView *) NULL);
|
|
|
assert(wand_view->signature == MagickWandSignature);
|
|
|
if (wand_view->debug != MagickFalse)
|
|
|
(void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand_view->name);
|
|
|
clone_view=(WandView *) AcquireCriticalMemory(sizeof(*clone_view));
|
|
|
(void) memset(clone_view,0,sizeof(*clone_view));
|
|
|
clone_view->id=AcquireWandId();
|
|
|
(void) FormatLocaleString(clone_view->name,MagickPathExtent,"%s-%.20g",
|
|
|
WandViewId,(double) clone_view->id);
|
|
|
clone_view->description=ConstantString(wand_view->description);
|
|
|
clone_view->image=CloneImage(wand_view->image,0,0,MagickTrue,
|
|
|
wand_view->exception);
|
|
|
clone_view->view=CloneCacheView(wand_view->view);
|
|
|
clone_view->extent=wand_view->extent;
|
|
|
clone_view->exception=AcquireExceptionInfo();
|
|
|
InheritException(clone_view->exception,wand_view->exception);
|
|
|
for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
|
|
|
clone_view->pixel_wands[i]=ClonePixelWands((const PixelWand **)
|
|
|
wand_view->pixel_wands[i],wand_view->extent.width);
|
|
|
clone_view->debug=wand_view->debug;
|
|
|
if (clone_view->debug != MagickFalse)
|
|
|
(void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",clone_view->name);
|
|
|
clone_view->signature=MagickWandSignature;
|
|
|
return(clone_view);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
% D e s t r o y W a n d V i e w %
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
%
|
|
|
% DestroyWandView() deallocates memory associated with a wand view.
|
|
|
%
|
|
|
% The format of the DestroyWandView method is:
|
|
|
%
|
|
|
% WandView *DestroyWandView(WandView *wand_view)
|
|
|
%
|
|
|
% A description of each parameter follows:
|
|
|
%
|
|
|
% o wand_view: the wand view.
|
|
|
%
|
|
|
*/
|
|
|
|
|
|
static PixelWand ***DestroyPixelsThreadSet(PixelWand ***pixel_wands,
|
|
|
const size_t number_wands)
|
|
|
{
|
|
|
ssize_t
|
|
|
i;
|
|
|
|
|
|
assert(pixel_wands != (PixelWand ***) NULL);
|
|
|
for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
|
|
|
if (pixel_wands[i] != (PixelWand **) NULL)
|
|
|
pixel_wands[i]=DestroyPixelWands(pixel_wands[i],number_wands);
|
|
|
pixel_wands=(PixelWand ***) RelinquishMagickMemory(pixel_wands);
|
|
|
return(pixel_wands);
|
|
|
}
|
|
|
|
|
|
WandExport WandView *DestroyWandView(WandView *wand_view)
|
|
|
{
|
|
|
assert(wand_view != (WandView *) NULL);
|
|
|
assert(wand_view->signature == MagickWandSignature);
|
|
|
wand_view->pixel_wands=DestroyPixelsThreadSet(wand_view->pixel_wands,
|
|
|
wand_view->extent.width);
|
|
|
wand_view->image=DestroyImage(wand_view->image);
|
|
|
wand_view->view=DestroyCacheView(wand_view->view);
|
|
|
wand_view->exception=DestroyExceptionInfo(wand_view->exception);
|
|
|
wand_view->signature=(~MagickWandSignature);
|
|
|
RelinquishWandId(wand_view->id);
|
|
|
wand_view=(WandView *) RelinquishMagickMemory(wand_view);
|
|
|
return(wand_view);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
% D u p l e x T r a n s f e r W a n d V i e w I t e r a t o r %
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
%
|
|
|
% DuplexTransferWandViewIterator() iterates over three wand views in
|
|
|
% parallel and calls your transfer method for each scanline of the view. The
|
|
|
% source and duplex pixel extent is not confined to the image canvas-- that is
|
|
|
% you can include negative offsets or widths or heights that exceed the image
|
|
|
% dimension. However, the destination wand view is confined to the image
|
|
|
% canvas-- that is no negative offsets or widths or heights that exceed the
|
|
|
% image dimension are permitted.
|
|
|
%
|
|
|
% The callback signature is:
|
|
|
%
|
|
|
% MagickBooleanType DuplexTransferImageViewMethod(const WandView *source,
|
|
|
% const WandView *duplex,WandView *destination,const ssize_t y,
|
|
|
% const int thread_id,void *context)
|
|
|
%
|
|
|
% Use this pragma if the view is not single threaded:
|
|
|
%
|
|
|
% #pragma omp critical
|
|
|
%
|
|
|
% to define a section of code in your callback transfer method that must be
|
|
|
% executed by a single thread at a time.
|
|
|
%
|
|
|
% The format of the DuplexTransferWandViewIterator method is:
|
|
|
%
|
|
|
% MagickBooleanType DuplexTransferWandViewIterator(WandView *source,
|
|
|
% WandView *duplex,WandView *destination,
|
|
|
% DuplexTransferWandViewMethod transfer,void *context)
|
|
|
%
|
|
|
% A description of each parameter follows:
|
|
|
%
|
|
|
% o source: the source wand view.
|
|
|
%
|
|
|
% o duplex: the duplex wand view.
|
|
|
%
|
|
|
% o destination: the destination wand view.
|
|
|
%
|
|
|
% o transfer: the transfer callback method.
|
|
|
%
|
|
|
% o context: the user defined context.
|
|
|
%
|
|
|
*/
|
|
|
WandExport MagickBooleanType DuplexTransferWandViewIterator(WandView *source,
|
|
|
WandView *duplex,WandView *destination,DuplexTransferWandViewMethod transfer,
|
|
|
void *context)
|
|
|
{
|
|
|
Image
|
|
|
*destination_image,
|
|
|
*source_image;
|
|
|
|
|
|
MagickBooleanType
|
|
|
status;
|
|
|
|
|
|
MagickOffsetType
|
|
|
progress;
|
|
|
|
|
|
#if defined(MAGICKCORE_OPENMP_SUPPORT)
|
|
|
size_t
|
|
|
height;
|
|
|
#endif
|
|
|
|
|
|
ssize_t
|
|
|
y;
|
|
|
|
|
|
assert(source != (WandView *) NULL);
|
|
|
assert(source->signature == MagickWandSignature);
|
|
|
if (transfer == (DuplexTransferWandViewMethod) NULL)
|
|
|
return(MagickFalse);
|
|
|
source_image=source->wand->images;
|
|
|
destination_image=destination->wand->images;
|
|
|
status=SetImageStorageClass(destination_image,DirectClass,
|
|
|
destination->exception);
|
|
|
if (status == MagickFalse)
|
|
|
return(MagickFalse);
|
|
|
status=MagickTrue;
|
|
|
progress=0;
|
|
|
#if defined(MAGICKCORE_OPENMP_SUPPORT)
|
|
|
height=source->extent.height-source->extent.y;
|
|
|
#pragma omp parallel for schedule(static) shared(progress,status) \
|
|
|
magick_number_threads(source_image,destination_image,height,1)
|
|
|
#endif
|
|
|
for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
|
|
|
{
|
|
|
const int
|
|
|
id = GetOpenMPThreadId();
|
|
|
|
|
|
MagickBooleanType
|
|
|
sync;
|
|
|
|
|
|
const Quantum
|
|
|
*magick_restrict duplex_pixels,
|
|
|
*magick_restrict pixels;
|
|
|
|
|
|
ssize_t
|
|
|
x;
|
|
|
|
|
|
Quantum
|
|
|
*magick_restrict destination_pixels;
|
|
|
|
|
|
if (status == MagickFalse)
|
|
|
continue;
|
|
|
pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
|
|
|
source->extent.width,1,source->exception);
|
|
|
if (pixels == (const Quantum *) NULL)
|
|
|
{
|
|
|
status=MagickFalse;
|
|
|
continue;
|
|
|
}
|
|
|
for (x=0; x < (ssize_t) source->extent.width; x++)
|
|
|
{
|
|
|
PixelSetQuantumPixel(source->image,pixels,source->pixel_wands[id][x]);
|
|
|
pixels+=GetPixelChannels(source->image);
|
|
|
}
|
|
|
duplex_pixels=GetCacheViewVirtualPixels(duplex->view,duplex->extent.x,y,
|
|
|
duplex->extent.width,1,duplex->exception);
|
|
|
if (duplex_pixels == (const Quantum *) NULL)
|
|
|
{
|
|
|
status=MagickFalse;
|
|
|
continue;
|
|
|
}
|
|
|
for (x=0; x < (ssize_t) duplex->extent.width; x++)
|
|
|
{
|
|
|
PixelSetQuantumPixel(duplex->image,duplex_pixels,
|
|
|
duplex->pixel_wands[id][x]);
|
|
|
duplex_pixels+=GetPixelChannels(duplex->image);
|
|
|
}
|
|
|
destination_pixels=GetCacheViewAuthenticPixels(destination->view,
|
|
|
destination->extent.x,y,destination->extent.width,1,
|
|
|
destination->exception);
|
|
|
if (destination_pixels == (Quantum *) NULL)
|
|
|
{
|
|
|
status=MagickFalse;
|
|
|
continue;
|
|
|
}
|
|
|
for (x=0; x < (ssize_t) destination->extent.width; x++)
|
|
|
{
|
|
|
PixelSetQuantumPixel(destination->image,destination_pixels,
|
|
|
destination->pixel_wands[id][x]);
|
|
|
destination_pixels+=GetPixelChannels(destination->image);
|
|
|
}
|
|
|
if (transfer(source,duplex,destination,y,id,context) == MagickFalse)
|
|
|
status=MagickFalse;
|
|
|
destination_pixels=GetCacheViewAuthenticPixels(destination->view,
|
|
|
destination->extent.x,y,destination->extent.width,1,
|
|
|
destination->exception);
|
|
|
for (x=0; x < (ssize_t) destination->extent.width; x++)
|
|
|
{
|
|
|
PixelGetQuantumPixel(destination->image,destination->pixel_wands[id][x],
|
|
|
destination_pixels);
|
|
|
destination_pixels+=GetPixelChannels(destination->image);
|
|
|
}
|
|
|
sync=SyncCacheViewAuthenticPixels(destination->view,destination->exception);
|
|
|
if (sync == MagickFalse)
|
|
|
status=MagickFalse;
|
|
|
if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
|
|
|
{
|
|
|
MagickBooleanType
|
|
|
proceed;
|
|
|
|
|
|
#if defined(MAGICKCORE_OPENMP_SUPPORT)
|
|
|
#pragma omp atomic
|
|
|
#endif
|
|
|
progress++;
|
|
|
proceed=SetImageProgress(source_image,source->description,progress,
|
|
|
source->extent.height);
|
|
|
if (proceed == MagickFalse)
|
|
|
status=MagickFalse;
|
|
|
}
|
|
|
}
|
|
|
return(status);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
% G e t W a n d V i e w E x c e p t i o n %
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
%
|
|
|
% GetWandViewException() returns the severity, reason, and description of any
|
|
|
% error that occurs when utilizing a wand view.
|
|
|
%
|
|
|
% The format of the GetWandViewException method is:
|
|
|
%
|
|
|
% char *GetWandViewException(const WandView *wand_view,
|
|
|
% ExceptionType *severity)
|
|
|
%
|
|
|
% A description of each parameter follows:
|
|
|
%
|
|
|
% o wand_view: the pixel wand_view.
|
|
|
%
|
|
|
% o severity: the severity of the error is returned here.
|
|
|
%
|
|
|
*/
|
|
|
WandExport char *GetWandViewException(const WandView *wand_view,
|
|
|
ExceptionType *severity)
|
|
|
{
|
|
|
char
|
|
|
*description;
|
|
|
|
|
|
assert(wand_view != (const WandView *) NULL);
|
|
|
assert(wand_view->signature == MagickWandSignature);
|
|
|
if (wand_view->debug != MagickFalse)
|
|
|
(void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand_view->name);
|
|
|
assert(severity != (ExceptionType *) NULL);
|
|
|
*severity=wand_view->exception->severity;
|
|
|
description=(char *) AcquireQuantumMemory(2UL*MagickPathExtent,
|
|
|
sizeof(*description));
|
|
|
if (description == (char *) NULL)
|
|
|
ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
|
|
|
wand_view->name);
|
|
|
*description='\0';
|
|
|
if (wand_view->exception->reason != (char *) NULL)
|
|
|
(void) CopyMagickString(description,GetLocaleExceptionMessage(
|
|
|
wand_view->exception->severity,wand_view->exception->reason),
|
|
|
MagickPathExtent);
|
|
|
if (wand_view->exception->description != (char *) NULL)
|
|
|
{
|
|
|
(void) ConcatenateMagickString(description," (",MagickPathExtent);
|
|
|
(void) ConcatenateMagickString(description,GetLocaleExceptionMessage(
|
|
|
wand_view->exception->severity,wand_view->exception->description),
|
|
|
MagickPathExtent);
|
|
|
(void) ConcatenateMagickString(description,")",MagickPathExtent);
|
|
|
}
|
|
|
return(description);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
% G e t W a n d V i e w E x t e n t %
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
%
|
|
|
% GetWandViewExtent() returns the wand view extent.
|
|
|
%
|
|
|
% The format of the GetWandViewExtent method is:
|
|
|
%
|
|
|
% RectangleInfo GetWandViewExtent(const WandView *wand_view)
|
|
|
%
|
|
|
% A description of each parameter follows:
|
|
|
%
|
|
|
% o wand_view: the wand view.
|
|
|
%
|
|
|
*/
|
|
|
WandExport RectangleInfo GetWandViewExtent(const WandView *wand_view)
|
|
|
{
|
|
|
assert(wand_view != (WandView *) NULL);
|
|
|
assert(wand_view->signature == MagickWandSignature);
|
|
|
return(wand_view->extent);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
% G e t W a n d V i e w I t e r a t o r %
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
%
|
|
|
% GetWandViewIterator() iterates over the wand view in parallel and calls
|
|
|
% your get method for each scanline of the view. The pixel extent is
|
|
|
% not confined to the image canvas-- that is you can include negative offsets
|
|
|
% or widths or heights that exceed the image dimension. Any updates to
|
|
|
% the pixels in your callback are ignored.
|
|
|
%
|
|
|
% The callback signature is:
|
|
|
%
|
|
|
% MagickBooleanType GetImageViewMethod(const WandView *source,
|
|
|
% const ssize_t y,const int thread_id,void *context)
|
|
|
%
|
|
|
% Use this pragma if the view is not single threaded:
|
|
|
%
|
|
|
% #pragma omp critical
|
|
|
%
|
|
|
% to define a section of code in your callback get method that must be
|
|
|
% executed by a single thread at a time.
|
|
|
%
|
|
|
% The format of the GetWandViewIterator method is:
|
|
|
%
|
|
|
% MagickBooleanType GetWandViewIterator(WandView *source,
|
|
|
% GetWandViewMethod get,void *context)
|
|
|
%
|
|
|
% A description of each parameter follows:
|
|
|
%
|
|
|
% o source: the source wand view.
|
|
|
%
|
|
|
% o get: the get callback method.
|
|
|
%
|
|
|
% o context: the user defined context.
|
|
|
%
|
|
|
*/
|
|
|
WandExport MagickBooleanType GetWandViewIterator(WandView *source,
|
|
|
GetWandViewMethod get,void *context)
|
|
|
{
|
|
|
Image
|
|
|
*source_image;
|
|
|
|
|
|
MagickBooleanType
|
|
|
status;
|
|
|
|
|
|
MagickOffsetType
|
|
|
progress;
|
|
|
|
|
|
#if defined(MAGICKCORE_OPENMP_SUPPORT)
|
|
|
size_t
|
|
|
height;
|
|
|
#endif
|
|
|
|
|
|
ssize_t
|
|
|
y;
|
|
|
|
|
|
assert(source != (WandView *) NULL);
|
|
|
assert(source->signature == MagickWandSignature);
|
|
|
if (get == (GetWandViewMethod) NULL)
|
|
|
return(MagickFalse);
|
|
|
source_image=source->wand->images;
|
|
|
status=MagickTrue;
|
|
|
progress=0;
|
|
|
#if defined(MAGICKCORE_OPENMP_SUPPORT)
|
|
|
height=source->extent.height-source->extent.y;
|
|
|
#pragma omp parallel for schedule(static) shared(progress,status) \
|
|
|
magick_number_threads(source_image,source_image,height,1)
|
|
|
#endif
|
|
|
for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
|
|
|
{
|
|
|
const int
|
|
|
id = GetOpenMPThreadId();
|
|
|
|
|
|
const Quantum
|
|
|
*pixels;
|
|
|
|
|
|
ssize_t
|
|
|
x;
|
|
|
|
|
|
if (status == MagickFalse)
|
|
|
continue;
|
|
|
pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
|
|
|
source->extent.width,1,source->exception);
|
|
|
if (pixels == (const Quantum *) NULL)
|
|
|
{
|
|
|
status=MagickFalse;
|
|
|
continue;
|
|
|
}
|
|
|
for (x=0; x < (ssize_t) source->extent.width; x++)
|
|
|
{
|
|
|
PixelSetQuantumPixel(source->image,pixels,source->pixel_wands[id][x]);
|
|
|
pixels+=GetPixelChannels(source->image);
|
|
|
}
|
|
|
if (get(source,y,id,context) == MagickFalse)
|
|
|
status=MagickFalse;
|
|
|
if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
|
|
|
{
|
|
|
MagickBooleanType
|
|
|
proceed;
|
|
|
|
|
|
#if defined(MAGICKCORE_OPENMP_SUPPORT)
|
|
|
#pragma omp atomic
|
|
|
#endif
|
|
|
progress++;
|
|
|
proceed=SetImageProgress(source_image,source->description,progress,
|
|
|
source->extent.height);
|
|
|
if (proceed == MagickFalse)
|
|
|
status=MagickFalse;
|
|
|
}
|
|
|
}
|
|
|
return(status);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
% G e t W a n d V i e w P i x e l s %
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
%
|
|
|
% GetWandViewPixels() returns the wand view pixel_wands.
|
|
|
%
|
|
|
% The format of the GetWandViewPixels method is:
|
|
|
%
|
|
|
% PixelWand *GetWandViewPixels(const WandView *wand_view)
|
|
|
%
|
|
|
% A description of each parameter follows:
|
|
|
%
|
|
|
% o wand_view: the wand view.
|
|
|
%
|
|
|
*/
|
|
|
WandExport PixelWand **GetWandViewPixels(const WandView *wand_view)
|
|
|
{
|
|
|
const int
|
|
|
id = GetOpenMPThreadId();
|
|
|
|
|
|
assert(wand_view != (WandView *) NULL);
|
|
|
assert(wand_view->signature == MagickWandSignature);
|
|
|
return(wand_view->pixel_wands[id]);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
% G e t W a n d V i e w W a n d %
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
%
|
|
|
% GetWandViewWand() returns the magick wand associated with the wand view.
|
|
|
%
|
|
|
% The format of the GetWandViewWand method is:
|
|
|
%
|
|
|
% MagickWand *GetWandViewWand(const WandView *wand_view)
|
|
|
%
|
|
|
% A description of each parameter follows:
|
|
|
%
|
|
|
% o wand_view: the wand view.
|
|
|
%
|
|
|
*/
|
|
|
WandExport MagickWand *GetWandViewWand(const WandView *wand_view)
|
|
|
{
|
|
|
assert(wand_view != (WandView *) NULL);
|
|
|
assert(wand_view->signature == MagickWandSignature);
|
|
|
return(wand_view->wand);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
% I s W a n d V i e w %
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
%
|
|
|
% IsWandView() returns MagickTrue if the parameter is verified as a wand
|
|
|
% view object.
|
|
|
%
|
|
|
% The format of the IsWandView method is:
|
|
|
%
|
|
|
% MagickBooleanType IsWandView(const WandView *wand_view)
|
|
|
%
|
|
|
% A description of each parameter follows:
|
|
|
%
|
|
|
% o wand_view: the wand view.
|
|
|
%
|
|
|
*/
|
|
|
WandExport MagickBooleanType IsWandView(const WandView *wand_view)
|
|
|
{
|
|
|
size_t
|
|
|
length;
|
|
|
|
|
|
if (wand_view == (const WandView *) NULL)
|
|
|
return(MagickFalse);
|
|
|
if (wand_view->signature != MagickWandSignature)
|
|
|
return(MagickFalse);
|
|
|
length=strlen(WandViewId);
|
|
|
if (LocaleNCompare(wand_view->name,WandViewId,length) != 0)
|
|
|
return(MagickFalse);
|
|
|
return(MagickTrue);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
% N e w W a n d V i e w %
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
%
|
|
|
% NewWandView() returns a wand view required for all other methods in the
|
|
|
% Wand View API.
|
|
|
%
|
|
|
% The format of the NewWandView method is:
|
|
|
%
|
|
|
% WandView *NewWandView(MagickWand *wand)
|
|
|
%
|
|
|
% A description of each parameter follows:
|
|
|
%
|
|
|
% o wand: the wand.
|
|
|
%
|
|
|
*/
|
|
|
|
|
|
static PixelWand ***AcquirePixelsThreadSet(const size_t number_wands)
|
|
|
{
|
|
|
PixelWand
|
|
|
***pixel_wands;
|
|
|
|
|
|
ssize_t
|
|
|
i;
|
|
|
|
|
|
size_t
|
|
|
number_threads;
|
|
|
|
|
|
number_threads=GetOpenMPMaximumThreads();
|
|
|
pixel_wands=(PixelWand ***) AcquireQuantumMemory(number_threads,
|
|
|
sizeof(*pixel_wands));
|
|
|
if (pixel_wands == (PixelWand ***) NULL)
|
|
|
return((PixelWand ***) NULL);
|
|
|
(void) memset(pixel_wands,0,number_threads*sizeof(*pixel_wands));
|
|
|
for (i=0; i < (ssize_t) number_threads; i++)
|
|
|
{
|
|
|
pixel_wands[i]=NewPixelWands(number_wands);
|
|
|
if (pixel_wands[i] == (PixelWand **) NULL)
|
|
|
return(DestroyPixelsThreadSet(pixel_wands,number_wands));
|
|
|
}
|
|
|
return(pixel_wands);
|
|
|
}
|
|
|
|
|
|
WandExport WandView *NewWandView(MagickWand *wand)
|
|
|
{
|
|
|
ExceptionInfo
|
|
|
*exception;
|
|
|
|
|
|
WandView
|
|
|
*wand_view;
|
|
|
|
|
|
assert(wand != (MagickWand *) NULL);
|
|
|
assert(wand->signature == MagickWandSignature);
|
|
|
wand_view=(WandView *) AcquireCriticalMemory(sizeof(*wand_view));
|
|
|
(void) memset(wand_view,0,sizeof(*wand_view));
|
|
|
wand_view->id=AcquireWandId();
|
|
|
(void) FormatLocaleString(wand_view->name,MagickPathExtent,"%s-%.20g",
|
|
|
WandViewId,(double) wand_view->id);
|
|
|
wand_view->description=ConstantString("WandView");
|
|
|
wand_view->wand=wand;
|
|
|
exception=AcquireExceptionInfo();
|
|
|
wand_view->view=AcquireVirtualCacheView(wand_view->wand->images,exception);
|
|
|
wand_view->extent.width=wand->images->columns;
|
|
|
wand_view->extent.height=wand->images->rows;
|
|
|
wand_view->pixel_wands=AcquirePixelsThreadSet(wand_view->extent.width);
|
|
|
wand_view->exception=exception;
|
|
|
if (wand_view->pixel_wands == (PixelWand ***) NULL)
|
|
|
ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
|
|
|
GetExceptionMessage(errno));
|
|
|
wand_view->debug=IsEventLogging();
|
|
|
wand_view->signature=MagickWandSignature;
|
|
|
return(wand_view);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
% N e w W a n d V i e w E x t e n t %
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
%
|
|
|
% NewWandViewExtent() returns a wand view required for all other methods
|
|
|
% in the Wand View API.
|
|
|
%
|
|
|
% The format of the NewWandViewExtent method is:
|
|
|
%
|
|
|
% WandView *NewWandViewExtent(MagickWand *wand,const ssize_t x,
|
|
|
% const ssize_t y,const size_t width,const size_t height)
|
|
|
%
|
|
|
% A description of each parameter follows:
|
|
|
%
|
|
|
% o wand: the magick wand.
|
|
|
%
|
|
|
% o x,y,columns,rows: These values define the perimeter of a extent of
|
|
|
% pixel_wands view.
|
|
|
%
|
|
|
*/
|
|
|
WandExport WandView *NewWandViewExtent(MagickWand *wand,const ssize_t x,
|
|
|
const ssize_t y,const size_t width,const size_t height)
|
|
|
{
|
|
|
ExceptionInfo
|
|
|
*exception;
|
|
|
|
|
|
WandView
|
|
|
*wand_view;
|
|
|
|
|
|
assert(wand != (MagickWand *) NULL);
|
|
|
assert(wand->signature == MagickWandSignature);
|
|
|
wand_view=(WandView *) AcquireCriticalMemory(sizeof(*wand_view));
|
|
|
(void) memset(wand_view,0,sizeof(*wand_view));
|
|
|
wand_view->id=AcquireWandId();
|
|
|
(void) FormatLocaleString(wand_view->name,MagickPathExtent,"%s-%.20g",
|
|
|
WandViewId,(double) wand_view->id);
|
|
|
wand_view->description=ConstantString("WandView");
|
|
|
exception=AcquireExceptionInfo();
|
|
|
wand_view->view=AcquireVirtualCacheView(wand_view->wand->images,exception);
|
|
|
wand_view->wand=wand;
|
|
|
wand_view->extent.width=width;
|
|
|
wand_view->extent.height=height;
|
|
|
wand_view->extent.x=x;
|
|
|
wand_view->extent.y=y;
|
|
|
wand_view->exception=exception;
|
|
|
wand_view->pixel_wands=AcquirePixelsThreadSet(wand_view->extent.width);
|
|
|
if (wand_view->pixel_wands == (PixelWand ***) NULL)
|
|
|
ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
|
|
|
GetExceptionMessage(errno));
|
|
|
wand_view->debug=IsEventLogging();
|
|
|
wand_view->signature=MagickWandSignature;
|
|
|
return(wand_view);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
% S e t W a n d V i e w D e s c r i p t i o n %
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
%
|
|
|
% SetWandViewDescription() associates a description with an image view.
|
|
|
%
|
|
|
% The format of the SetWandViewDescription method is:
|
|
|
%
|
|
|
% void SetWandViewDescription(WandView *image_view,const char *description)
|
|
|
%
|
|
|
% A description of each parameter follows:
|
|
|
%
|
|
|
% o wand_view: the wand view.
|
|
|
%
|
|
|
% o description: the wand view description.
|
|
|
%
|
|
|
*/
|
|
|
MagickExport void SetWandViewDescription(WandView *wand_view,
|
|
|
const char *description)
|
|
|
{
|
|
|
assert(wand_view != (WandView *) NULL);
|
|
|
assert(wand_view->signature == MagickWandSignature);
|
|
|
wand_view->description=ConstantString(description);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
% S e t W a n d V i e w I t e r a t o r %
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
%
|
|
|
% SetWandViewIterator() iterates over the wand view in parallel and calls
|
|
|
% your set method for each scanline of the view. The pixel extent is
|
|
|
% confined to the image canvas-- that is no negative offsets or widths or
|
|
|
% heights that exceed the image dimension. The pixels are initiallly
|
|
|
% undefined and any settings you make in the callback method are automagically
|
|
|
% synced back to your image.
|
|
|
%
|
|
|
% The callback signature is:
|
|
|
%
|
|
|
% MagickBooleanType SetImageViewMethod(ImageView *destination,
|
|
|
% const ssize_t y,const int thread_id,void *context)
|
|
|
%
|
|
|
% Use this pragma if the view is not single threaded:
|
|
|
%
|
|
|
% #pragma omp critical
|
|
|
%
|
|
|
% to define a section of code in your callback set method that must be
|
|
|
% executed by a single thread at a time.
|
|
|
%
|
|
|
% The format of the SetWandViewIterator method is:
|
|
|
%
|
|
|
% MagickBooleanType SetWandViewIterator(WandView *destination,
|
|
|
% SetWandViewMethod set,void *context)
|
|
|
%
|
|
|
% A description of each parameter follows:
|
|
|
%
|
|
|
% o destination: the wand view.
|
|
|
%
|
|
|
% o set: the set callback method.
|
|
|
%
|
|
|
% o context: the user defined context.
|
|
|
%
|
|
|
*/
|
|
|
WandExport MagickBooleanType SetWandViewIterator(WandView *destination,
|
|
|
SetWandViewMethod set,void *context)
|
|
|
{
|
|
|
Image
|
|
|
*destination_image;
|
|
|
|
|
|
MagickBooleanType
|
|
|
status;
|
|
|
|
|
|
MagickOffsetType
|
|
|
progress;
|
|
|
|
|
|
#if defined(MAGICKCORE_OPENMP_SUPPORT)
|
|
|
size_t
|
|
|
height;
|
|
|
#endif
|
|
|
|
|
|
ssize_t
|
|
|
y;
|
|
|
|
|
|
assert(destination != (WandView *) NULL);
|
|
|
assert(destination->signature == MagickWandSignature);
|
|
|
if (set == (SetWandViewMethod) NULL)
|
|
|
return(MagickFalse);
|
|
|
destination_image=destination->wand->images;
|
|
|
status=SetImageStorageClass(destination_image,DirectClass,
|
|
|
destination->exception);
|
|
|
if (status == MagickFalse)
|
|
|
return(MagickFalse);
|
|
|
status=MagickTrue;
|
|
|
progress=0;
|
|
|
#if defined(MAGICKCORE_OPENMP_SUPPORT)
|
|
|
height=destination->extent.height-destination->extent.y;
|
|
|
#pragma omp parallel for schedule(static) shared(progress,status) \
|
|
|
magick_number_threads(destination_image,destination_image,height,1)
|
|
|
#endif
|
|
|
for (y=destination->extent.y; y < (ssize_t) destination->extent.height; y++)
|
|
|
{
|
|
|
const int
|
|
|
id = GetOpenMPThreadId();
|
|
|
|
|
|
MagickBooleanType
|
|
|
sync;
|
|
|
|
|
|
ssize_t
|
|
|
x;
|
|
|
|
|
|
Quantum
|
|
|
*magick_restrict pixels;
|
|
|
|
|
|
if (status == MagickFalse)
|
|
|
continue;
|
|
|
pixels=GetCacheViewAuthenticPixels(destination->view,destination->extent.x,
|
|
|
y,destination->extent.width,1,destination->exception);
|
|
|
if (pixels == (Quantum *) NULL)
|
|
|
{
|
|
|
status=MagickFalse;
|
|
|
continue;
|
|
|
}
|
|
|
if (set(destination,y,id,context) == MagickFalse)
|
|
|
status=MagickFalse;
|
|
|
for (x=0; x < (ssize_t) destination->extent.width; x++)
|
|
|
{
|
|
|
PixelGetQuantumPixel(destination->image,destination->pixel_wands[id][x],
|
|
|
pixels);
|
|
|
pixels+=GetPixelChannels(destination->image);
|
|
|
}
|
|
|
sync=SyncCacheViewAuthenticPixels(destination->view,destination->exception);
|
|
|
if (sync == MagickFalse)
|
|
|
status=MagickFalse;
|
|
|
if (destination_image->progress_monitor != (MagickProgressMonitor) NULL)
|
|
|
{
|
|
|
MagickBooleanType
|
|
|
proceed;
|
|
|
|
|
|
#if defined(MAGICKCORE_OPENMP_SUPPORT)
|
|
|
#pragma omp atomic
|
|
|
#endif
|
|
|
progress++;
|
|
|
proceed=SetImageProgress(destination_image,destination->description,
|
|
|
progress,destination->extent.height);
|
|
|
if (proceed == MagickFalse)
|
|
|
status=MagickFalse;
|
|
|
}
|
|
|
}
|
|
|
return(status);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
% T r a n s f e r W a n d V i e w I t e r a t o r %
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
%
|
|
|
% TransferWandViewIterator() iterates over two wand views in parallel and
|
|
|
% calls your transfer method for each scanline of the view. The source pixel
|
|
|
% extent is not confined to the image canvas-- that is you can include
|
|
|
% negative offsets or widths or heights that exceed the image dimension.
|
|
|
% However, the destination wand view is confined to the image canvas-- that
|
|
|
% is no negative offsets or widths or heights that exceed the image dimension
|
|
|
% are permitted.
|
|
|
%
|
|
|
% The callback signature is:
|
|
|
%
|
|
|
% MagickBooleanType TransferImageViewMethod(const WandView *source,
|
|
|
% WandView *destination,const ssize_t y,const int thread_id,
|
|
|
% void *context)
|
|
|
%
|
|
|
% Use this pragma if the view is not single threaded:
|
|
|
%
|
|
|
% #pragma omp critical
|
|
|
%
|
|
|
% to define a section of code in your callback transfer method that must be
|
|
|
% executed by a single thread at a time.
|
|
|
%
|
|
|
% The format of the TransferWandViewIterator method is:
|
|
|
%
|
|
|
% MagickBooleanType TransferWandViewIterator(WandView *source,
|
|
|
% WandView *destination,TransferWandViewMethod transfer,void *context)
|
|
|
%
|
|
|
% A description of each parameter follows:
|
|
|
%
|
|
|
% o source: the source wand view.
|
|
|
%
|
|
|
% o destination: the destination wand view.
|
|
|
%
|
|
|
% o transfer: the transfer callback method.
|
|
|
%
|
|
|
% o context: the user defined context.
|
|
|
%
|
|
|
*/
|
|
|
WandExport MagickBooleanType TransferWandViewIterator(WandView *source,
|
|
|
WandView *destination,TransferWandViewMethod transfer,void *context)
|
|
|
{
|
|
|
Image
|
|
|
*destination_image,
|
|
|
*source_image;
|
|
|
|
|
|
MagickBooleanType
|
|
|
status;
|
|
|
|
|
|
MagickOffsetType
|
|
|
progress;
|
|
|
|
|
|
#if defined(MAGICKCORE_OPENMP_SUPPORT)
|
|
|
size_t
|
|
|
height;
|
|
|
#endif
|
|
|
|
|
|
ssize_t
|
|
|
y;
|
|
|
|
|
|
assert(source != (WandView *) NULL);
|
|
|
assert(source->signature == MagickWandSignature);
|
|
|
if (transfer == (TransferWandViewMethod) NULL)
|
|
|
return(MagickFalse);
|
|
|
source_image=source->wand->images;
|
|
|
destination_image=destination->wand->images;
|
|
|
status=SetImageStorageClass(destination_image,DirectClass,
|
|
|
destination->exception);
|
|
|
if (status == MagickFalse)
|
|
|
return(MagickFalse);
|
|
|
status=MagickTrue;
|
|
|
progress=0;
|
|
|
#if defined(MAGICKCORE_OPENMP_SUPPORT)
|
|
|
height=source->extent.height-source->extent.y;
|
|
|
#pragma omp parallel for schedule(static) shared(progress,status) \
|
|
|
magick_number_threads(source_image,destination_image,height,1)
|
|
|
#endif
|
|
|
for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
|
|
|
{
|
|
|
const int
|
|
|
id = GetOpenMPThreadId();
|
|
|
|
|
|
MagickBooleanType
|
|
|
sync;
|
|
|
|
|
|
const Quantum
|
|
|
*magick_restrict pixels;
|
|
|
|
|
|
ssize_t
|
|
|
x;
|
|
|
|
|
|
Quantum
|
|
|
*magick_restrict destination_pixels;
|
|
|
|
|
|
if (status == MagickFalse)
|
|
|
continue;
|
|
|
pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
|
|
|
source->extent.width,1,source->exception);
|
|
|
if (pixels == (const Quantum *) NULL)
|
|
|
{
|
|
|
status=MagickFalse;
|
|
|
continue;
|
|
|
}
|
|
|
for (x=0; x < (ssize_t) source->extent.width; x++)
|
|
|
{
|
|
|
PixelSetQuantumPixel(source->image,pixels,source->pixel_wands[id][x]);
|
|
|
pixels+=GetPixelChannels(source->image);
|
|
|
}
|
|
|
destination_pixels=GetCacheViewAuthenticPixels(destination->view,
|
|
|
destination->extent.x,y,destination->extent.width,1,
|
|
|
destination->exception);
|
|
|
if (destination_pixels == (Quantum *) NULL)
|
|
|
{
|
|
|
status=MagickFalse;
|
|
|
continue;
|
|
|
}
|
|
|
for (x=0; x < (ssize_t) destination->extent.width; x++)
|
|
|
{
|
|
|
PixelSetQuantumPixel(destination->image,destination_pixels,
|
|
|
destination->pixel_wands[id][x]);
|
|
|
destination_pixels+=GetPixelChannels(destination->image);
|
|
|
}
|
|
|
if (transfer(source,destination,y,id,context) == MagickFalse)
|
|
|
status=MagickFalse;
|
|
|
destination_pixels=GetCacheViewAuthenticPixels(destination->view,
|
|
|
destination->extent.x,y,destination->extent.width,1,
|
|
|
destination->exception);
|
|
|
for (x=0; x < (ssize_t) destination->extent.width; x++)
|
|
|
{
|
|
|
PixelGetQuantumPixel(destination->image,destination->pixel_wands[id][x],
|
|
|
destination_pixels);
|
|
|
destination_pixels+=GetPixelChannels(destination->image);
|
|
|
}
|
|
|
sync=SyncCacheViewAuthenticPixels(destination->view,destination->exception);
|
|
|
if (sync == MagickFalse)
|
|
|
status=MagickFalse;
|
|
|
if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
|
|
|
{
|
|
|
MagickBooleanType
|
|
|
proceed;
|
|
|
|
|
|
#if defined(MAGICKCORE_OPENMP_SUPPORT)
|
|
|
#pragma omp atomic
|
|
|
#endif
|
|
|
progress++;
|
|
|
proceed=SetImageProgress(source_image,source->description,progress,
|
|
|
source->extent.height);
|
|
|
if (proceed == MagickFalse)
|
|
|
status=MagickFalse;
|
|
|
}
|
|
|
}
|
|
|
return(status);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
% U p d a t e W a n d V i e w I t e r a t o r %
|
|
|
% %
|
|
|
% %
|
|
|
% %
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
%
|
|
|
% UpdateWandViewIterator() iterates over the wand view in parallel and calls
|
|
|
% your update method for each scanline of the view. The pixel extent is
|
|
|
% confined to the image canvas-- that is no negative offsets or widths or
|
|
|
% heights that exceed the image dimension are permitted. Updates to pixels
|
|
|
% in your callback are automagically synced back to the image.
|
|
|
%
|
|
|
% The callback signature is:
|
|
|
%
|
|
|
% MagickBooleanType UpdateImageViewMethod(WandView *source,const ssize_t y,
|
|
|
% const int thread_id,void *context)
|
|
|
%
|
|
|
% Use this pragma if the view is not single threaded:
|
|
|
%
|
|
|
% #pragma omp critical
|
|
|
%
|
|
|
% to define a section of code in your callback update method that must be
|
|
|
% executed by a single thread at a time.
|
|
|
%
|
|
|
% The format of the UpdateWandViewIterator method is:
|
|
|
%
|
|
|
% MagickBooleanType UpdateWandViewIterator(WandView *source,
|
|
|
% UpdateWandViewMethod update,void *context)
|
|
|
%
|
|
|
% A description of each parameter follows:
|
|
|
%
|
|
|
% o source: the source wand view.
|
|
|
%
|
|
|
% o update: the update callback method.
|
|
|
%
|
|
|
% o context: the user defined context.
|
|
|
%
|
|
|
*/
|
|
|
WandExport MagickBooleanType UpdateWandViewIterator(WandView *source,
|
|
|
UpdateWandViewMethod update,void *context)
|
|
|
{
|
|
|
Image
|
|
|
*source_image;
|
|
|
|
|
|
MagickBooleanType
|
|
|
status;
|
|
|
|
|
|
MagickOffsetType
|
|
|
progress;
|
|
|
|
|
|
#if defined(MAGICKCORE_OPENMP_SUPPORT)
|
|
|
size_t
|
|
|
height;
|
|
|
#endif
|
|
|
|
|
|
ssize_t
|
|
|
y;
|
|
|
|
|
|
assert(source != (WandView *) NULL);
|
|
|
assert(source->signature == MagickWandSignature);
|
|
|
if (update == (UpdateWandViewMethod) NULL)
|
|
|
return(MagickFalse);
|
|
|
source_image=source->wand->images;
|
|
|
status=SetImageStorageClass(source_image,DirectClass,source->exception);
|
|
|
if (status == MagickFalse)
|
|
|
return(MagickFalse);
|
|
|
status=MagickTrue;
|
|
|
progress=0;
|
|
|
#if defined(MAGICKCORE_OPENMP_SUPPORT)
|
|
|
height=source->extent.height-source->extent.y;
|
|
|
#pragma omp parallel for schedule(static) shared(progress,status) \
|
|
|
magick_number_threads(source_image,source_image,height,1)
|
|
|
#endif
|
|
|
for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
|
|
|
{
|
|
|
const int
|
|
|
id = GetOpenMPThreadId();
|
|
|
|
|
|
MagickBooleanType
|
|
|
sync;
|
|
|
|
|
|
ssize_t
|
|
|
x;
|
|
|
|
|
|
Quantum
|
|
|
*magick_restrict pixels;
|
|
|
|
|
|
if (status == MagickFalse)
|
|
|
continue;
|
|
|
pixels=GetCacheViewAuthenticPixels(source->view,source->extent.x,y,
|
|
|
source->extent.width,1,source->exception);
|
|
|
if (pixels == (Quantum *) NULL)
|
|
|
{
|
|
|
status=MagickFalse;
|
|
|
continue;
|
|
|
}
|
|
|
for (x=0; x < (ssize_t) source->extent.width; x++)
|
|
|
{
|
|
|
PixelSetQuantumPixel(source->image,pixels,source->pixel_wands[id][x]);
|
|
|
pixels+=GetPixelChannels(source->image);
|
|
|
}
|
|
|
if (update(source,y,id,context) == MagickFalse)
|
|
|
status=MagickFalse;
|
|
|
for (x=0; x < (ssize_t) source->extent.width; x++)
|
|
|
{
|
|
|
PixelGetQuantumPixel(source->image,source->pixel_wands[id][x],pixels);
|
|
|
pixels+=GetPixelChannels(source->image);
|
|
|
}
|
|
|
sync=SyncCacheViewAuthenticPixels(source->view,source->exception);
|
|
|
if (sync == MagickFalse)
|
|
|
status=MagickFalse;
|
|
|
if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
|
|
|
{
|
|
|
MagickBooleanType
|
|
|
proceed;
|
|
|
|
|
|
#if defined(MAGICKCORE_OPENMP_SUPPORT)
|
|
|
#pragma omp atomic
|
|
|
#endif
|
|
|
progress++;
|
|
|
proceed=SetImageProgress(source_image,source->description,progress,
|
|
|
source->extent.height);
|
|
|
if (proceed == MagickFalse)
|
|
|
status=MagickFalse;
|
|
|
}
|
|
|
}
|
|
|
return(status);
|
|
|
}
|