% August 2007 %
% %
% %
-% Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
+% Copyright 1999-2013 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 %
#include "MagickCore/resample.h"
#include "MagickCore/resize.h"
#include "MagickCore/resize-private.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/token.h"
#include "MagickCore/transform.h"
#include "MagickCore/signature-private.h"
#include "MagickCore/utility.h"
#include "MagickCore/utility-private.h"
+#include "MagickCore/option.h"
/*
EWA Resampling Options
*/
%
% Usage Example...
% resample_filter=AcquireResampleFilter(image,exception);
-% SetResampleFilter(resample_filter, GaussianFilter, 1.0);
+% SetResampleFilter(resample_filter, GaussianFilter);
% for (y=0; y < (ssize_t) image->rows; y++) {
% for (x=0; x < (ssize_t) image->columns; x++) {
% u= ....; v= ....;
resample_filter->exception=exception;
resample_filter->image=ReferenceImage((Image *) image);
- resample_filter->view=AcquireCacheView(resample_filter->image);
+ resample_filter->view=AcquireVirtualCacheView(resample_filter->image,exception);
resample_filter->debug=IsEventLogging();
resample_filter->signature=MagickSignature;
resample_filter->average_defined = MagickFalse;
/* initialise the resampling filter settings */
- SetResampleFilter(resample_filter, image->filter, image->blur);
- (void) SetResampleFilterInterpolateMethod(resample_filter,
- image->interpolate);
+ SetResampleFilter(resample_filter, image->filter);
+ (void) SetResampleFilterInterpolateMethod(resample_filter,image->interpolate);
(void) SetResampleFilterVirtualPixelMethod(resample_filter,
GetImageVirtualPixelMethod(image));
-
return(resample_filter);
}
\f
% The format of the ResamplePixelColor method is:
%
% MagickBooleanType ResamplePixelColor(ResampleFilter *resample_filter,
-% const double u0,const double v0,PixelInfo *pixel)
+% const double u0,const double v0,PixelInfo *pixel,
+% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
%
% o pixel: the resampled pixel is returned here.
%
+% o exception: return any errors or warnings in this structure.
+%
*/
MagickExport MagickBooleanType ResamplePixelColor(
ResampleFilter *resample_filter,const double u0,const double v0,
- PixelInfo *pixel)
+ PixelInfo *pixel,ExceptionInfo *exception)
{
MagickBooleanType
status;
resample_filter->average_defined=MagickTrue;
/* Try to get an averaged pixel color of whole image */
- average_image=ResizeImage(resample_filter->image,1,1,BoxFilter,1.0,
+ average_image=ResizeImage(resample_filter->image,1,1,BoxFilter,
resample_filter->exception);
if (average_image == (Image *) NULL)
{
*pixel=resample_filter->average_pixel; /* FAILED */
break;
}
- average_view=AcquireCacheView(average_image);
+ average_view=AcquireVirtualCacheView(average_image,exception);
pixels=GetCacheViewVirtualPixels(average_view,0,0,1,1,
resample_filter->exception);
if (pixels == (const Quantum *) NULL) {
if ( resample_filter->virtual_pixel == CheckerTileVirtualPixelMethod )
{
- /* CheckerTile is avergae of image average half background */
- /* FUTURE: replace with a 50% blend of both pixels */
+ /* CheckerTile is a alpha blend of the image's average pixel
+ color and the current background color */
- weight = QuantumScale*((MagickRealType)
+ /* image's average pixel color */
+ weight = QuantumScale*((double)
resample_filter->average_pixel.alpha);
resample_filter->average_pixel.red *= weight;
resample_filter->average_pixel.green *= weight;
resample_filter->average_pixel.blue *= weight;
divisor_c = weight;
- weight = QuantumScale*((MagickRealType)
+ /* background color */
+ weight = QuantumScale*((double)
resample_filter->image->background_color.alpha);
resample_filter->average_pixel.red +=
weight*resample_filter->image->background_color.red;
resample_filter->image->background_color.alpha;
divisor_c += weight;
+ /* alpha blend */
resample_filter->average_pixel.red /= divisor_c;
resample_filter->average_pixel.green /= divisor_c;
resample_filter->average_pixel.blue /= divisor_c;
- resample_filter->average_pixel.alpha /= 2;
+ resample_filter->average_pixel.alpha /= 2; /* 50% blend */
}
}
pixel->red = pixel->green = pixel->blue = 0.0;
if (pixel->colorspace == CMYKColorspace)
pixel->black = 0.0;
- if (pixel->matte != MagickFalse)
+ if (pixel->alpha_trait == BlendPixelTrait)
pixel->alpha = 0.0;
/*
pixel->alpha += weight*GetPixelAlpha(resample_filter->image,pixels);
divisor_m += weight;
- if (pixel->matte != MagickFalse)
- weight *= QuantumScale*((MagickRealType) GetPixelAlpha(resample_filter->image,pixels));
+ if (pixel->alpha_trait == BlendPixelTrait)
+ weight *= QuantumScale*((double) GetPixelAlpha(resample_filter->image,pixels));
pixel->red += weight*GetPixelRed(resample_filter->image,pixels);
pixel->green += weight*GetPixelGreen(resample_filter->image,pixels);
pixel->blue += weight*GetPixelBlue(resample_filter->image,pixels);
/*
Result sanity check -- this should NOT happen
*/
- if ( hit == 0 ) {
- /* not enough pixels in resampling, resort to direct interpolation */
+ if ( hit == 0 || divisor_m <= MagickEpsilon || divisor_c <= MagickEpsilon ) {
+ /* not enough pixels, or bad weighting in resampling,
+ resort to direct interpolation */
#if DEBUG_NO_PIXEL_HIT
pixel->alpha = pixel->red = pixel->green = pixel->blue = 0;
pixel->red = QuantumRange; /* show pixels for which EWA fails */
Finialize results of resampling
*/
divisor_m = 1.0/divisor_m;
- pixel->alpha = (MagickRealType) ClampToQuantum(divisor_m*pixel->alpha);
+ pixel->alpha = (double) ClampToQuantum(divisor_m*pixel->alpha);
divisor_c = 1.0/divisor_c;
- pixel->red = (MagickRealType) ClampToQuantum(divisor_c*pixel->red);
- pixel->green = (MagickRealType) ClampToQuantum(divisor_c*pixel->green);
- pixel->blue = (MagickRealType) ClampToQuantum(divisor_c*pixel->blue);
+ pixel->red = (double) ClampToQuantum(divisor_c*pixel->red);
+ pixel->green = (double) ClampToQuantum(divisor_c*pixel->green);
+ pixel->blue = (double) ClampToQuantum(divisor_c*pixel->blue);
if (pixel->colorspace == CMYKColorspace)
- pixel->black = (MagickRealType) ClampToQuantum(divisor_c*pixel->black);
+ pixel->black = (double) ClampToQuantum(divisor_c*pixel->black);
return(MagickTrue);
}
\f
%
% Reference: http://en.wikipedia.org/wiki/Ellipse#Canonical_form
*/
-static inline void ClampUpAxes(const double dux,
- const double dvx,
- const double duy,
- const double dvy,
- double *major_mag,
- double *minor_mag,
- double *major_unit_x,
- double *major_unit_y,
- double *minor_unit_x,
- double *minor_unit_y)
+static inline void ClampUpAxes(const double dux,const double dvx,
+ const double duy,const double dvy,double *major_mag,double *minor_mag,
+ double *major_unit_x,double *major_unit_y,double *minor_unit_x,
+ double *minor_unit_y)
{
/*
* ClampUpAxes takes an input 2x2 matrix
}
/* Scale ellipse to match the filters support
- (that is, multiply F by the square of the support).
+ (that is, multiply F by the square of the support)
+ Simplier to just multiply it by the support twice!
*/
F *= resample_filter->support;
F *= resample_filter->support;
% specific filter. Note that the filter is used as a radial filter not as a
% two pass othogonally aligned resampling filter.
%
-% The default Filter, is Gaussian, which is the standard filter used by the
-% original paper on the Elliptical Weighted Everage Algorithm. However other
-% filters can also be used.
-%
% The format of the SetResampleFilter method is:
%
% void SetResampleFilter(ResampleFilter *resample_filter,
-% const FilterTypes filter,const double blur)
+% const FilterTypes filter)
%
% A description of each parameter follows:
%
%
% o filter: the resize filter for elliptical weighting LUT
%
-% o blur: filter blur factor (radial scaling) for elliptical weighting LUT
-%
*/
MagickExport void SetResampleFilter(ResampleFilter *resample_filter,
- const FilterTypes filter,const double blur)
+ const FilterTypes filter)
{
ResizeFilter
*resize_filter;
resample_filter->do_interpolate = MagickFalse;
resample_filter->filter = filter;
- if ( filter == PointFilter )
- {
- resample_filter->do_interpolate = MagickTrue;
- return; /* EWA turned off - nothing more to do */
- }
-
- /* Set a default cylindrical filter of a 'low blur' Jinc windowed Jinc */
+ /* Default cylindrical filter is a Cubic Keys filter */
if ( filter == UndefinedFilter )
resample_filter->filter = RobidouxFilter;
+ if ( resample_filter->filter == PointFilter ) {
+ resample_filter->do_interpolate = MagickTrue;
+ return; /* EWA turned off - nothing more to do */
+ }
+
resize_filter = AcquireResizeFilter(resample_filter->image,
- resample_filter->filter,blur,MagickTrue,resample_filter->exception);
- if (resize_filter == (ResizeFilter *) NULL)
- {
- (void) ThrowMagickException(resample_filter->exception,GetMagickModule(),
- ModuleError, "UnableToSetFilteringValue",
- "Fall back to default EWA gaussian filter");
- resample_filter->filter = PointFilter;
- }
+ resample_filter->filter,MagickTrue,resample_filter->exception);
+ if (resize_filter == (ResizeFilter *) NULL) {
+ (void) ThrowMagickException(resample_filter->exception,GetMagickModule(),
+ ModuleError, "UnableToSetFilteringValue",
+ "Fall back to Interpolated 'Point' filter");
+ resample_filter->filter = PointFilter;
+ resample_filter->do_interpolate = MagickTrue;
+ return; /* EWA turned off - nothing more to do */
+ }
/* Get the practical working support for the filter,
* after any API call blur factors have been accoded for.
Q;
double
r_scale;
+
/* Scale radius so the filter LUT covers the full support range */
r_scale = resample_filter->support*sqrt(1.0/(double)WLUT_WIDTH);
for(Q=0; Q<WLUT_WIDTH; Q++)
ScaleResampleFilter(resample_filter, 1.0, 0.0, 0.0, 1.0);
#if 0
- /* This is old code kept as a reference only. It is very wrong,
- and I don't understand exactly what it was attempting to do.
- */
/*
+ This is old code kept as a reference only. Basically it generates
+ a Gaussian bell curve, with sigma = 0.5 if the support is 2.0
+
Create Normal Gaussian 2D Filter Weighted Lookup Table.
A normal EWA guassual lookup would use exp(Q*ALPHA)
where Q = distance squared from 0.0 (center) to 1.0 (edge)
The table is of length 1024, and equates to support radius of 2.0
thus needs to be scaled by ALPHA*4/1024 and any blur factor squared
- The above came from some reference code provided by Fred Weinhaus
- and seems to have been a guess that was appropriate for its use
- in a 3d perspective landscape mapping program.
+ The it comes from reference code provided by Fred Weinhaus.
*/
r_scale = -2.77258872223978123767/(WLUT_WIDTH*blur*blur);
for(Q=0; Q<WLUT_WIDTH; Q++)
resample_filter->filter_lut[Q] = exp((double)Q*r_scale);
resample_filter->support = WLUT_WIDTH;
- break;
#endif
#if FILTER_LUT
#if defined(MAGICKCORE_OPENMP_SUPPORT)
#pragma omp single
#endif
- { register int
- Q;
- double
- r_scale;
-
- /* Scale radius so the filter LUT covers the full support range */
- r_scale = resample_filter->support*sqrt(1.0/(double)WLUT_WIDTH);
- if (IsMagickTrue(GetImageArtifact(resample_filter->image,"resample:verbose")) )
+ {
+ if (IfStringTrue(GetImageArtifact(resample_filter->image,
+ "resample:verbose")) )
{
+ register int
+ Q;
+ double
+ r_scale;
+
/* Debug output of the filter weighting LUT
- Gnuplot the LUT with hoizontal adjusted to 'r' using...
- plot [0:2][-.2:1] "lut.dat" using (sqrt($0/1024)*2):1 with lines
- The filter values is normalized for comparision
+ Gnuplot the LUT data, the x scale index has been adjusted
+ plot [0:2][-.2:1] "lut.dat" with lines
+ The filter values should be normalized for comparision
*/
printf("#\n");
- printf("# Resampling Filter LUT (%d values)\n", WLUT_WIDTH);
+ printf("# Resampling Filter LUT (%d values) for '%s' filter\n",
+ WLUT_WIDTH, CommandOptionToMnemonic(MagickFilterOptions,
+ resample_filter->filter) );
printf("#\n");
printf("# Note: values in table are using a squared radius lookup.\n");
- printf("# And the whole table represents the filters support.\n");
- printf("\n"); /* generates a 'break' in gnuplot if multiple outputs */
+ printf("# As such its distribution is not uniform.\n");
+ printf("#\n");
+ printf("# The X value is the support distance for the Y weight\n");
+ printf("# so you can use gnuplot to plot this cylindrical filter\n");
+ printf("# plot [0:2][-.2:1] \"lut.dat\" with lines\n");
+ printf("#\n");
+
+ /* Scale radius so the filter LUT covers the full support range */
+ r_scale = resample_filter->support*sqrt(1.0/(double)WLUT_WIDTH);
for(Q=0; Q<WLUT_WIDTH; Q++)
printf("%8.*g %.*g\n",
- GetMagickPrecision(),sqrt((double)Q)*r_scale,
- GetMagickPrecision(),resample_filter->filter_lut[Q] );
+ GetMagickPrecision(),sqrt((double)Q)*r_scale,
+ GetMagickPrecision(),resample_filter->filter_lut[Q] );
+ printf("\n\n"); /* generate a 'break' in gnuplot if multiple outputs */
}
- /* output the above once only for each image, and each setting */
+ /* Output the above once only for each image, and each setting
(void) DeleteImageArtifact(resample_filter->image,"resample:verbose");
+ */
}
#endif /* FILTER_LUT */
return;