42#include "MagickCore/studio.h"
43#include "MagickCore/accelerate-private.h"
44#include "MagickCore/artifact.h"
45#include "MagickCore/blob.h"
46#include "MagickCore/cache.h"
47#include "MagickCore/cache-view.h"
48#include "MagickCore/channel.h"
49#include "MagickCore/color.h"
50#include "MagickCore/color-private.h"
51#include "MagickCore/colorspace.h"
52#include "MagickCore/colorspace-private.h"
53#include "MagickCore/distort.h"
54#include "MagickCore/draw.h"
55#include "MagickCore/exception.h"
56#include "MagickCore/exception-private.h"
57#include "MagickCore/gem.h"
58#include "MagickCore/image.h"
59#include "MagickCore/image-private.h"
60#include "MagickCore/list.h"
61#include "MagickCore/memory_.h"
62#include "MagickCore/memory-private.h"
63#include "MagickCore/magick.h"
64#include "MagickCore/pixel-accessor.h"
65#include "MagickCore/property.h"
66#include "MagickCore/monitor.h"
67#include "MagickCore/monitor-private.h"
68#include "MagickCore/nt-base-private.h"
69#include "MagickCore/option.h"
70#include "MagickCore/pixel.h"
71#include "MagickCore/profile-private.h"
72#include "MagickCore/quantum-private.h"
73#include "MagickCore/resample.h"
74#include "MagickCore/resample-private.h"
75#include "MagickCore/resize.h"
76#include "MagickCore/resize-private.h"
77#include "MagickCore/resource_.h"
78#include "MagickCore/string_.h"
79#include "MagickCore/string-private.h"
80#include "MagickCore/thread-private.h"
81#include "MagickCore/token.h"
82#include "MagickCore/utility.h"
83#include "MagickCore/utility-private.h"
84#include "MagickCore/version.h"
85#if defined(MAGICKCORE_LQR_DELEGATE)
95 (*filter)(
const double,
const ResizeFilter *),
96 (*window)(
const double,
const ResizeFilter *),
103 ResizeWeightingFunctionType
116 BesselOrderOne(
double),
117 Sinc(
const double,
const ResizeFilter *),
118 SincFast(
const double,
const ResizeFilter *);
152static double Blackman(
const double x,
153 const ResizeFilter *magick_unused(resize_filter))
162 const double cosine = cos((
double) (MagickPI*x));
163 magick_unreferenced(resize_filter);
164 return(0.34+cosine*(0.5+cosine*0.16));
167static double Bohman(
const double x,
168 const ResizeFilter *magick_unused(resize_filter))
178 const double cosine = cos((
double) (MagickPI*x));
179 const double sine=sqrt(1.0-cosine*cosine);
180 magick_unreferenced(resize_filter);
181 return((1.0-x)*cosine+(1.0/MagickPI)*sine);
184static double Box(
const double magick_unused(x),
185 const ResizeFilter *magick_unused(resize_filter))
187 magick_unreferenced(x);
188 magick_unreferenced(resize_filter);
198static double Cosine(
const double x,
199 const ResizeFilter *magick_unused(resize_filter))
201 magick_unreferenced(resize_filter);
207 return(cos((
double) (MagickPI2*x)));
210static double CubicBC(
const double x,
const ResizeFilter *resize_filter)
242 return(resize_filter->coefficient[0]+x*(x*
243 (resize_filter->coefficient[1]+x*resize_filter->coefficient[2])));
245 return(resize_filter->coefficient[3]+x*(resize_filter->coefficient[4]+x*
246 (resize_filter->coefficient[5]+x*resize_filter->coefficient[6])));
250static double CubicSpline(
const double x,
const ResizeFilter *resize_filter)
252 if (resize_filter->support <= 2.0)
258 return(((x-9.0/5.0)*x-1.0/5.0)*x+1.0);
260 return(((-1.0/3.0*(x-1.0)+4.0/5.0)*(x-1.0)-7.0/15.0)*(x-1.0));
263 if (resize_filter->support <= 3.0)
269 return(((13.0/11.0*x-453.0/209.0)*x-3.0/209.0)*x+1.0);
271 return(((-6.0/11.0*(x-1.0)+270.0/209.0)*(x-1.0)-156.0/209.0)*(x-1.0));
273 return(((1.0/11.0*(x-2.0)-45.0/209.0)*(x-2.0)+26.0/209.0)*(x-2.0));
280 return(((49.0/41.0*x-6387.0/2911.0)*x-3.0/2911.0)*x+1.0);
282 return(((-24.0/41.0*(x-1.0)+4032.0/2911.0)*(x-1.0)-2328.0/2911.0)*(x-1.0));
284 return(((6.0/41.0*(x-2.0)-1008.0/2911.0)*(x-2.0)+582.0/2911.0)*(x-2.0));
286 return(((-1.0/41.0*(x-3.0)+168.0/2911.0)*(x-3.0)-97.0/2911.0)*(x-3.0));
290static double Gaussian(
const double x,
const ResizeFilter *resize_filter)
322 return(exp((
double)(-resize_filter->coefficient[1]*x*x)));
325static double Hann(
const double x,
326 const ResizeFilter *magick_unused(resize_filter))
332 const double cosine = cos((
double) (MagickPI*x));
333 magick_unreferenced(resize_filter);
334 return(0.5+0.5*cosine);
337static double Hamming(
const double x,
338 const ResizeFilter *magick_unused(resize_filter))
344 const double cosine = cos((
double) (MagickPI*x));
345 magick_unreferenced(resize_filter);
346 return(0.54+0.46*cosine);
349static double Jinc(
const double x,
350 const ResizeFilter *magick_unused(resize_filter))
352 magick_unreferenced(resize_filter);
363 return(0.5*MagickPI);
364 return(BesselOrderOne(MagickPI*x)/x);
367static double Kaiser(
const double x,
const ResizeFilter *resize_filter)
381 return(resize_filter->coefficient[1]*I0(resize_filter->coefficient[0]*
382 sqrt((
double) (1.0-x*x))));
385static double Lagrange(
const double x,
const ResizeFilter *resize_filter)
407 if (x > resize_filter->support)
409 order=(ssize_t) (2.0*resize_filter->window_support);
410 n=(ssize_t) (resize_filter->window_support+x);
412 for (i=0; i < order; i++)
414 value*=(n-i-x)/(n-i);
418static double MagicKernelSharp2013(
const double x,
419 const ResizeFilter *magick_unused(resize_filter))
421 magick_unreferenced(resize_filter);
430 return(0.625+1.75*(0.5-x)*(0.5+x));
432 return((1.0-x)*(1.75-x));
434 return(-0.125*(2.5-x)*(2.5-x));
438static double MagicKernelSharp2021(
const double x,
439 const ResizeFilter *magick_unused(resize_filter))
441 magick_unreferenced(resize_filter);
450 return(577.0/576.0-239.0/144.0*x*x);
452 return(35.0/36.0*(x-1.0)*(x-239.0/140.0));
454 return(1.0/6.0*(x-2.0)*(65.0/24.0-x));
456 return(1.0/36.0*(x-3.0)*(x-3.75));
458 return(-1.0/288.0*(x-4.5)*(x-4.5));
462static double Quadratic(
const double x,
463 const ResizeFilter *magick_unused(resize_filter))
465 magick_unreferenced(resize_filter);
473 return(0.5*(x-1.5)*(x-1.5));
477static double Sinc(
const double x,
478 const ResizeFilter *magick_unused(resize_filter))
480 magick_unreferenced(resize_filter);
488 const double alpha=(double) (MagickPI*x);
489 return(sin((
double) alpha)/alpha);
491 return((
double) 1.0);
494static double SincFast(
const double x,
495 const ResizeFilter *magick_unused(resize_filter))
497 magick_unreferenced(resize_filter);
525 const double alpha=(double) (MagickPI*x);
526 return(sin((
double) alpha)/alpha);
532 const double xx = x*x;
533#if MAGICKCORE_QUANTUM_DEPTH <= 8
537 const double c0 = 0.173610016489197553621906385078711564924e-2L;
538 const double c1 = -0.384186115075660162081071290162149315834e-3L;
539 const double c2 = 0.393684603287860108352720146121813443561e-4L;
540 const double c3 = -0.248947210682259168029030370205389323899e-5L;
541 const double c4 = 0.107791837839662283066379987646635416692e-6L;
542 const double c5 = -0.324874073895735800961260474028013982211e-8L;
543 const double c6 = 0.628155216606695311524920882748052490116e-10L;
544 const double c7 = -0.586110644039348333520104379959307242711e-12L;
546 c0+xx*(c1+xx*(c2+xx*(c3+xx*(c4+xx*(c5+xx*(c6+xx*c7))))));
547 return((xx-1.0)*(xx-4.0)*(xx-9.0)*(xx-16.0)*p);
548#elif MAGICKCORE_QUANTUM_DEPTH <= 16
552 const double c0 = 0.173611107357320220183368594093166520811e-2L;
553 const double c1 = -0.384240921114946632192116762889211361285e-3L;
554 const double c2 = 0.394201182359318128221229891724947048771e-4L;
555 const double c3 = -0.250963301609117217660068889165550534856e-5L;
556 const double c4 = 0.111902032818095784414237782071368805120e-6L;
557 const double c5 = -0.372895101408779549368465614321137048875e-8L;
558 const double c6 = 0.957694196677572570319816780188718518330e-10L;
559 const double c7 = -0.187208577776590710853865174371617338991e-11L;
560 const double c8 = 0.253524321426864752676094495396308636823e-13L;
561 const double c9 = -0.177084805010701112639035485248501049364e-15L;
563 c0+xx*(c1+xx*(c2+xx*(c3+xx*(c4+xx*(c5+xx*(c6+xx*(c7+xx*(c8+xx*c9))))))));
564 return((xx-1.0)*(xx-4.0)*(xx-9.0)*(xx-16.0)*p);
569 const double c0 = 0.173611111110910715186413700076827593074e-2L;
570 const double c1 = -0.289105544717893415815859968653611245425e-3L;
571 const double c2 = 0.206952161241815727624413291940849294025e-4L;
572 const double c3 = -0.834446180169727178193268528095341741698e-6L;
573 const double c4 = 0.207010104171026718629622453275917944941e-7L;
574 const double c5 = -0.319724784938507108101517564300855542655e-9L;
575 const double c6 = 0.288101675249103266147006509214934493930e-11L;
576 const double c7 = -0.118218971804934245819960233886876537953e-13L;
578 c0+xx*(c1+xx*(c2+xx*(c3+xx*(c4+xx*(c5+xx*(c6+xx*c7))))));
579 const double d0 = 1.0L;
580 const double d1 = 0.547981619622284827495856984100563583948e-1L;
581 const double d2 = 0.134226268835357312626304688047086921806e-2L;
582 const double d3 = 0.178994697503371051002463656833597608689e-4L;
583 const double d4 = 0.114633394140438168641246022557689759090e-6L;
584 const double q = d0+xx*(d1+xx*(d2+xx*(d3+xx*d4)));
585 return((xx-1.0)*(xx-4.0)*(xx-9.0)*(xx-16.0)/q*p);
590static double Triangle(
const double x,
591 const ResizeFilter *magick_unused(resize_filter))
593 magick_unreferenced(resize_filter);
605static double Welch(
const double x,
606 const ResizeFilter *magick_unused(resize_filter))
608 magick_unreferenced(resize_filter);
804MagickPrivate ResizeFilter *AcquireResizeFilter(
const Image *image,
805 const FilterType filter,
const MagickBooleanType cylindrical,
806 ExceptionInfo *exception)
841 }
const mapping[SentinelFilter] =
843 { UndefinedFilter, BoxFilter },
844 { PointFilter, BoxFilter },
845 { BoxFilter, BoxFilter },
846 { TriangleFilter, BoxFilter },
847 { HermiteFilter, BoxFilter },
848 { SincFastFilter, HannFilter },
849 { SincFastFilter, HammingFilter },
850 { SincFastFilter, BlackmanFilter },
851 { GaussianFilter, BoxFilter },
852 { QuadraticFilter, BoxFilter },
853 { CubicFilter, BoxFilter },
854 { CatromFilter, BoxFilter },
855 { MitchellFilter, BoxFilter },
856 { JincFilter, BoxFilter },
857 { SincFilter, BoxFilter },
858 { SincFastFilter, BoxFilter },
859 { SincFastFilter, KaiserFilter },
860 { LanczosFilter, WelchFilter },
861 { SincFastFilter, CubicFilter },
862 { SincFastFilter, BohmanFilter },
863 { SincFastFilter, TriangleFilter },
864 { LagrangeFilter, BoxFilter },
865 { LanczosFilter, LanczosFilter },
866 { LanczosSharpFilter, LanczosSharpFilter },
867 { Lanczos2Filter, Lanczos2Filter },
868 { Lanczos2SharpFilter, Lanczos2SharpFilter },
869 { RobidouxFilter, BoxFilter },
870 { RobidouxSharpFilter, BoxFilter },
871 { LanczosFilter, CosineFilter },
872 { SplineFilter, BoxFilter },
873 { LanczosRadiusFilter, LanczosFilter },
874 { CubicSplineFilter, BoxFilter },
875 { MagicKernelSharp2013Filter, BoxFilter },
876 { MagicKernelSharp2021Filter, BoxFilter },
892 (*function)(
const double,
const ResizeFilter*),
897 ResizeWeightingFunctionType weightingFunctionType;
898 }
const filters[SentinelFilter] =
905 { Box, 0.5, 0.5, 0.0, 0.0, BoxWeightingFunction },
906 { Box, 0.0, 0.5, 0.0, 0.0, BoxWeightingFunction },
907 { Box, 0.5, 0.5, 0.0, 0.0, BoxWeightingFunction },
908 { Triangle, 1.0, 1.0, 0.0, 0.0, TriangleWeightingFunction },
909 { CubicBC, 1.0, 1.0, 0.0, 0.0, CubicBCWeightingFunction },
910 { Hann, 1.0, 1.0, 0.0, 0.0, HannWeightingFunction },
911 { Hamming, 1.0, 1.0, 0.0, 0.0, HammingWeightingFunction },
912 { Blackman, 1.0, 1.0, 0.0, 0.0, BlackmanWeightingFunction },
913 { Gaussian, 2.0, 1.5, 0.0, 0.0, GaussianWeightingFunction },
914 { Quadratic, 1.5, 1.5, 0.0, 0.0, QuadraticWeightingFunction },
915 { CubicBC, 2.0, 2.0, 1.0, 0.0, CubicBCWeightingFunction },
916 { CubicBC, 2.0, 1.0, 0.0, 0.5, CubicBCWeightingFunction },
917 { CubicBC, 2.0, 8.0/7.0, 1./3., 1./3., CubicBCWeightingFunction },
918 { Jinc, 3.0, 1.2196698912665045, 0.0, 0.0, JincWeightingFunction },
919 { Sinc, 4.0, 1.0, 0.0, 0.0, SincWeightingFunction },
920 { SincFast, 4.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
921 { Kaiser, 1.0, 1.0, 0.0, 0.0, KaiserWeightingFunction },
922 { Welch, 1.0, 1.0, 0.0, 0.0, WelchWeightingFunction },
923 { CubicBC, 2.0, 2.0, 1.0, 0.0, CubicBCWeightingFunction },
924 { Bohman, 1.0, 1.0, 0.0, 0.0, BohmanWeightingFunction },
925 { Triangle, 1.0, 1.0, 0.0, 0.0, TriangleWeightingFunction },
926 { Lagrange, 2.0, 1.0, 0.0, 0.0, LagrangeWeightingFunction },
927 { SincFast, 3.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
928 { SincFast, 3.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
929 { SincFast, 2.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
930 { SincFast, 2.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
932 { CubicBC, 2.0, 1.1685777620836932,
933 0.37821575509399867, 0.31089212245300067, CubicBCWeightingFunction },
935 { CubicBC, 2.0, 1.105822933719019,
936 0.2620145123990142, 0.3689927438004929, CubicBCWeightingFunction },
937 { Cosine, 1.0, 1.0, 0.0, 0.0, CosineWeightingFunction },
938 { CubicBC, 2.0, 2.0, 1.0, 0.0, CubicBCWeightingFunction },
939 { SincFast, 3.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
940 { CubicSpline,2.0, 0.5, 0.0, 0.0, BoxWeightingFunction },
941 { MagicKernelSharp2013, 2.5, 1.0, 0.0, 0.0, MagicKernelSharpWeightingFunction },
942 { MagicKernelSharp2021, 4.5, 1.0, 0.0, 0.0, MagicKernelSharpWeightingFunction },
979 assert(image != (
const Image *) NULL);
980 assert(image->signature == MagickCoreSignature);
981 assert(UndefinedFilter < filter && filter < SentinelFilter);
982 assert(exception != (ExceptionInfo *) NULL);
983 assert(exception->signature == MagickCoreSignature);
984 if (IsEventLogging() != MagickFalse)
985 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
987 resize_filter=(ResizeFilter *) AcquireCriticalMemory(
sizeof(*resize_filter));
988 (void) memset(resize_filter,0,
sizeof(*resize_filter));
992 filter_type=mapping[filter].filter;
993 window_type=mapping[filter].window;
994 resize_filter->blur=1.0;
996 if ((cylindrical != MagickFalse) && (filter_type == SincFastFilter) &&
997 (filter != SincFastFilter))
998 filter_type=JincFilter;
1001 artifact=GetImageArtifact(image,
"filter:filter");
1002 if (IsStringTrue(artifact) != MagickFalse)
1007 option=ParseCommandOption(MagickFilterOptions,MagickFalse,artifact);
1008 if ((UndefinedFilter < option) && (option < SentinelFilter))
1010 filter_type=(FilterType) option;
1011 window_type=BoxFilter;
1014 artifact=GetImageArtifact(image,
"filter:window");
1015 if (artifact != (
const char *) NULL)
1017 option=ParseCommandOption(MagickFilterOptions,MagickFalse,artifact);
1018 if ((UndefinedFilter < option) && (option < SentinelFilter))
1019 window_type=(FilterType) option;
1025 artifact=GetImageArtifact(image,
"filter:window");
1026 if (artifact != (
const char *) NULL)
1031 option=ParseCommandOption(MagickFilterOptions,MagickFalse,artifact);
1032 if ((UndefinedFilter < option) && (option < SentinelFilter))
1034 filter_type= cylindrical != MagickFalse ? JincFilter
1036 window_type=(FilterType) option;
1042 resize_filter->filter=filters[filter_type].function;
1043 resize_filter->support=filters[filter_type].support;
1044 resize_filter->filterWeightingType=filters[filter_type].weightingFunctionType;
1045 resize_filter->window=filters[window_type].function;
1046 resize_filter->windowWeightingType=filters[window_type].weightingFunctionType;
1047 resize_filter->scale=filters[window_type].scale;
1048 resize_filter->signature=MagickCoreSignature;
1051 if (cylindrical != MagickFalse)
1052 switch (filter_type)
1056 resize_filter->support=(double) MagickSQ1_2;
1059 case LanczosSharpFilter:
1060 case Lanczos2Filter:
1061 case Lanczos2SharpFilter:
1062 case LanczosRadiusFilter:
1063 resize_filter->filter=filters[JincFilter].function;
1064 resize_filter->window=filters[JincFilter].function;
1065 resize_filter->scale=filters[JincFilter].scale;
1072 switch (filter_type)
1074 case LanczosSharpFilter:
1075 resize_filter->blur *= 0.9812505644269356;
1077 case Lanczos2SharpFilter:
1078 resize_filter->blur *= 0.9549963639785485;
1090 if ((resize_filter->filter == Gaussian) ||
1091 (resize_filter->window == Gaussian) ) {
1093 artifact=GetImageArtifact(image,
"filter:sigma");
1094 if (artifact != (
const char *) NULL)
1095 value=StringToDouble(artifact,(
char **) NULL);
1097 resize_filter->coefficient[0]=value;
1098 resize_filter->coefficient[1]=MagickSafeReciprocal(2.0*value*value);
1099 resize_filter->coefficient[2]=MagickSafeReciprocal(Magick2PI*value*value);
1102 resize_filter->support *= 2*value;
1106 if ((resize_filter->filter == Kaiser) ||
1107 (resize_filter->window == Kaiser) ) {
1109 artifact=GetImageArtifact(image,
"filter:alpha");
1110 if (artifact != (
const char *) NULL)
1111 value=StringToDouble(artifact,(
char **) NULL);
1112 artifact=GetImageArtifact(image,
"filter:kaiser-beta");
1113 if (artifact != (
const char *) NULL)
1114 value=StringToDouble(artifact,(
char **) NULL);
1115 artifact=GetImageArtifact(image,
"filter:kaiser-alpha");
1116 if (artifact != (
const char *) NULL)
1117 value=StringToDouble(artifact,(
char **) NULL)*MagickPI;
1119 resize_filter->coefficient[0]=value;
1120 resize_filter->coefficient[1]=MagickSafeReciprocal(I0(value));
1125 artifact=GetImageArtifact(image,
"filter:lobes");
1126 if (artifact != (
const char *) NULL)
1131 lobes=(ssize_t) StringToLong(artifact);
1134 resize_filter->support=(double) lobes;
1136 if (resize_filter->filter == Jinc)
1141 if (resize_filter->support > 16)
1142 resize_filter->support=jinc_zeros[15];
1144 resize_filter->support=jinc_zeros[((long) resize_filter->support)-1];
1148 if (filter_type == LanczosRadiusFilter)
1149 resize_filter->blur*=floor(resize_filter->support)/
1150 resize_filter->support;
1155 artifact=GetImageArtifact(image,
"filter:blur");
1156 if (artifact != (
const char *) NULL)
1157 resize_filter->blur*=StringToDouble(artifact,(
char **) NULL);
1158 if (resize_filter->blur < MagickEpsilon)
1159 resize_filter->blur=(double) MagickEpsilon;
1163 artifact=GetImageArtifact(image,
"filter:support");
1164 if (artifact != (
const char *) NULL)
1165 resize_filter->support=fabs(StringToDouble(artifact,(
char **) NULL));
1170 resize_filter->window_support=resize_filter->support;
1171 artifact=GetImageArtifact(image,
"filter:win-support");
1172 if (artifact != (
const char *) NULL)
1173 resize_filter->window_support=fabs(StringToDouble(artifact,(
char **) NULL));
1178 resize_filter->scale*=MagickSafeReciprocal(resize_filter->window_support);
1184 if ((resize_filter->filter == CubicBC) ||
1185 (resize_filter->window == CubicBC) )
1187 B=filters[filter_type].B;
1188 C=filters[filter_type].C;
1189 if (filters[window_type].function == CubicBC)
1191 B=filters[window_type].B;
1192 C=filters[window_type].C;
1194 artifact=GetImageArtifact(image,
"filter:b");
1195 if (artifact != (
const char *) NULL)
1197 B=StringToDouble(artifact,(
char **) NULL);
1199 artifact=GetImageArtifact(image,
"filter:c");
1200 if (artifact != (
const char *) NULL)
1201 C=StringToDouble(artifact,(
char **) NULL);
1205 artifact=GetImageArtifact(image,
"filter:c");
1206 if (artifact != (
const char *) NULL)
1208 C=StringToDouble(artifact,(
char **) NULL);
1219 resize_filter->coefficient[0]=1.0-(1.0/3.0)*B;
1220 resize_filter->coefficient[1]=-3.0+twoB+C;
1221 resize_filter->coefficient[2]=2.0-1.5*B-C;
1222 resize_filter->coefficient[3]=(4.0/3.0)*B+4.0*C;
1223 resize_filter->coefficient[4]=-8.0*C-twoB;
1224 resize_filter->coefficient[5]=B+5.0*C;
1225 resize_filter->coefficient[6]=(-1.0/6.0)*B-C;
1232 if (IsStringTrue(GetImageArtifact(image,
"filter:verbose")) != MagickFalse)
1233#if defined(MAGICKCORE_OPENMP_SUPPORT)
1247 if (resize_filter->filter == Box) filter_type=BoxFilter;
1248 if (resize_filter->filter == Sinc) filter_type=SincFilter;
1249 if (resize_filter->filter == SincFast) filter_type=SincFastFilter;
1250 if (resize_filter->filter == Jinc) filter_type=JincFilter;
1251 if (resize_filter->filter == CubicBC) filter_type=CubicFilter;
1252 if (resize_filter->window == Box) window_type=BoxFilter;
1253 if (resize_filter->window == Sinc) window_type=SincFilter;
1254 if (resize_filter->window == SincFast) window_type=SincFastFilter;
1255 if (resize_filter->window == Jinc) window_type=JincFilter;
1256 if (resize_filter->window == CubicBC) window_type=CubicFilter;
1260 support=GetResizeFilterSupport(resize_filter);
1261 (void) FormatLocaleFile(stdout,
"# Resampling Filter (for graphing)\n#\n");
1262 (void) FormatLocaleFile(stdout,
"# filter = %s\n",
1263 CommandOptionToMnemonic(MagickFilterOptions,filter_type));
1264 (void) FormatLocaleFile(stdout,
"# window = %s\n",
1265 CommandOptionToMnemonic(MagickFilterOptions,window_type));
1266 (void) FormatLocaleFile(stdout,
"# support = %.*g\n",
1267 GetMagickPrecision(),(
double) resize_filter->support);
1268 (void) FormatLocaleFile(stdout,
"# window-support = %.*g\n",
1269 GetMagickPrecision(),(
double) resize_filter->window_support);
1270 (void) FormatLocaleFile(stdout,
"# scale-blur = %.*g\n",
1271 GetMagickPrecision(),(
double) resize_filter->blur);
1272 if ((filter_type == GaussianFilter) || (window_type == GaussianFilter))
1273 (void) FormatLocaleFile(stdout,
"# gaussian-sigma = %.*g\n",
1274 GetMagickPrecision(),(
double) resize_filter->coefficient[0]);
1275 if ((filter_type == KaiserFilter) || (window_type == KaiserFilter))
1276 (void) FormatLocaleFile(stdout,
"# kaiser-beta = %.*g\n",
1277 GetMagickPrecision(),(
double) resize_filter->coefficient[0]);
1278 (void) FormatLocaleFile(stdout,
"# practical-support = %.*g\n",
1279 GetMagickPrecision(), (
double) support);
1280 if ((filter_type == CubicFilter) || (window_type == CubicFilter))
1281 (void) FormatLocaleFile(stdout,
"# B,C = %.*g,%.*g\n",
1282 GetMagickPrecision(),(
double) B,GetMagickPrecision(),(
double) C);
1283 (void) FormatLocaleFile(stdout,
"\n");
1287 for (x=0.0; x <= support; x+=0.01)
1288 (
void) FormatLocaleFile(stdout,
"%5.2lf\t%.*g\n",x,GetMagickPrecision(),
1289 (
double) GetResizeFilterWeight(resize_filter,x));
1293 (void) FormatLocaleFile(stdout,
"%5.2lf\t%.*g\n",support,
1294 GetMagickPrecision(),0.0);
1296 (void) DeleteImageArtifact((Image *) image,
"filter:verbose");
1298 return(resize_filter);
1335MagickExport Image *AdaptiveResizeImage(
const Image *image,
1336 const size_t columns,
const size_t rows,ExceptionInfo *exception)
1341 resize_image=InterpolativeResizeImage(image,columns,rows,MeshInterpolatePixel,
1343 return(resize_image);
1386static double I0(
double x)
1402 for (i=2; t > MagickEpsilon; i++)
1405 t*=y/((double) i*i);
1411static double J1(
double x)
1423 0.581199354001606143928050809e+21,
1424 -0.6672106568924916298020941484e+20,
1425 0.2316433580634002297931815435e+19,
1426 -0.3588817569910106050743641413e+17,
1427 0.2908795263834775409737601689e+15,
1428 -0.1322983480332126453125473247e+13,
1429 0.3413234182301700539091292655e+10,
1430 -0.4695753530642995859767162166e+7,
1431 0.270112271089232341485679099e+4
1435 0.11623987080032122878585294e+22,
1436 0.1185770712190320999837113348e+20,
1437 0.6092061398917521746105196863e+17,
1438 0.2081661221307607351240184229e+15,
1439 0.5243710262167649715406728642e+12,
1440 0.1013863514358673989967045588e+10,
1441 0.1501793594998585505921097578e+7,
1442 0.1606931573481487801970916749e+4,
1448 for (i=7; i >= 0; i--)
1457static double P1(
double x)
1469 0.352246649133679798341724373e+5,
1470 0.62758845247161281269005675e+5,
1471 0.313539631109159574238669888e+5,
1472 0.49854832060594338434500455e+4,
1473 0.2111529182853962382105718e+3,
1474 0.12571716929145341558495e+1
1478 0.352246649133679798068390431e+5,
1479 0.626943469593560511888833731e+5,
1480 0.312404063819041039923015703e+5,
1481 0.4930396490181088979386097e+4,
1482 0.2030775189134759322293574e+3,
1488 for (i=4; i >= 0; i--)
1490 p=p*(8.0/x)*(8.0/x)+Pone[i];
1491 q=q*(8.0/x)*(8.0/x)+Qone[i];
1497static double Q1(
double x)
1509 0.3511751914303552822533318e+3,
1510 0.7210391804904475039280863e+3,
1511 0.4259873011654442389886993e+3,
1512 0.831898957673850827325226e+2,
1513 0.45681716295512267064405e+1,
1514 0.3532840052740123642735e-1
1518 0.74917374171809127714519505e+4,
1519 0.154141773392650970499848051e+5,
1520 0.91522317015169922705904727e+4,
1521 0.18111867005523513506724158e+4,
1522 0.1038187585462133728776636e+3,
1528 for (i=4; i >= 0; i--)
1530 p=p*(8.0/x)*(8.0/x)+Pone[i];
1531 q=q*(8.0/x)*(8.0/x)+Qone[i];
1536static double BesselOrderOne(
double x)
1549 q=sqrt((
double) (2.0/(MagickPI*x)))*(P1(x)*(1.0/sqrt(2.0)*(sin(x)-
1550 cos(x)))-8.0/x*Q1(x)*(-1.0/sqrt(2.0)*(sin(x)+cos(x))));
1578MagickPrivate ResizeFilter *DestroyResizeFilter(ResizeFilter *resize_filter)
1580 assert(resize_filter != (ResizeFilter *) NULL);
1581 assert(resize_filter->signature == MagickCoreSignature);
1582 resize_filter->signature=(~MagickCoreSignature);
1583 resize_filter=(ResizeFilter *) RelinquishMagickMemory(resize_filter);
1584 return(resize_filter);
1611MagickPrivate
double *GetResizeFilterCoefficient(
1612 const ResizeFilter *resize_filter)
1614 assert(resize_filter != (ResizeFilter *) NULL);
1615 assert(resize_filter->signature == MagickCoreSignature);
1616 return((
double *) resize_filter->coefficient);
1619MagickPrivate
double GetResizeFilterBlur(
const ResizeFilter *resize_filter)
1621 assert(resize_filter != (ResizeFilter *) NULL);
1622 assert(resize_filter->signature == MagickCoreSignature);
1623 return(resize_filter->blur);
1626MagickPrivate
double GetResizeFilterScale(
const ResizeFilter *resize_filter)
1628 assert(resize_filter != (ResizeFilter *) NULL);
1629 assert(resize_filter->signature == MagickCoreSignature);
1630 return(resize_filter->scale);
1633MagickPrivate
double GetResizeFilterWindowSupport(
1634 const ResizeFilter *resize_filter)
1636 assert(resize_filter != (ResizeFilter *) NULL);
1637 assert(resize_filter->signature == MagickCoreSignature);
1638 return(resize_filter->window_support);
1641MagickPrivate ResizeWeightingFunctionType GetResizeFilterWeightingType(
1642 const ResizeFilter *resize_filter)
1644 assert(resize_filter != (ResizeFilter *) NULL);
1645 assert(resize_filter->signature == MagickCoreSignature);
1646 return(resize_filter->filterWeightingType);
1649MagickPrivate ResizeWeightingFunctionType GetResizeFilterWindowWeightingType(
1650 const ResizeFilter *resize_filter)
1652 assert(resize_filter != (ResizeFilter *) NULL);
1653 assert(resize_filter->signature == MagickCoreSignature);
1654 return(resize_filter->windowWeightingType);
1657MagickPrivate
double GetResizeFilterSupport(
const ResizeFilter *resize_filter)
1659 assert(resize_filter != (ResizeFilter *) NULL);
1660 assert(resize_filter->signature == MagickCoreSignature);
1661 return(resize_filter->support*resize_filter->blur);
1691MagickPrivate
double GetResizeFilterWeight(
const ResizeFilter *resize_filter,
1702 assert(resize_filter != (ResizeFilter *) NULL);
1703 assert(resize_filter->signature == MagickCoreSignature);
1704 x_blur=fabs((
double) x)*MagickSafeReciprocal(resize_filter->blur);
1705 if ((resize_filter->window_support < MagickEpsilon) ||
1706 (resize_filter->window == Box))
1710 scale=resize_filter->scale;
1711 scale=resize_filter->window(x_blur*scale,resize_filter);
1713 weight=scale*resize_filter->filter(x_blur,resize_filter);
1750MagickExport Image *InterpolativeResizeImage(
const Image *image,
1751 const size_t columns,
const size_t rows,
const PixelInterpolateMethod method,
1752 ExceptionInfo *exception)
1754#define InterpolativeResizeImageTag "Resize/Image"
1778 assert(image != (
const Image *) NULL);
1779 assert(image->signature == MagickCoreSignature);
1780 assert(exception != (ExceptionInfo *) NULL);
1781 assert(exception->signature == MagickCoreSignature);
1782 if (IsEventLogging() != MagickFalse)
1783 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1784 if ((columns == 0) || (rows == 0))
1785 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
1786 if ((columns == image->columns) && (rows == image->rows))
1787 return(CloneImage(image,0,0,MagickTrue,exception));
1788 resize_image=CloneImage(image,columns,rows,MagickTrue,exception);
1789 if (resize_image == (Image *) NULL)
1790 return((Image *) NULL);
1791 if (SetImageStorageClass(resize_image,DirectClass,exception) == MagickFalse)
1793 resize_image=DestroyImage(resize_image);
1794 return((Image *) NULL);
1798 image_view=AcquireVirtualCacheView(image,exception);
1799 resize_view=AcquireAuthenticCacheView(resize_image,exception);
1800 scale.x=(double) image->columns/resize_image->columns;
1801 scale.y=(double) image->rows/resize_image->rows;
1802#if defined(MAGICKCORE_OPENMP_SUPPORT)
1803 #pragma omp parallel for schedule(static) shared(progress,status) \
1804 magick_number_threads(image,resize_image,resize_image->rows,1)
1806 for (y=0; y < (ssize_t) resize_image->rows; y++)
1817 if (status == MagickFalse)
1819 q=QueueCacheViewAuthenticPixels(resize_view,0,y,resize_image->columns,1,
1821 if (q == (Quantum *) NULL)
1823 offset.y=((double) y+0.5)*scale.y-0.5;
1824 for (x=0; x < (ssize_t) resize_image->columns; x++)
1829 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1838 channel=GetPixelChannelChannel(image,i);
1839 traits=GetPixelChannelTraits(image,channel);
1840 resize_traits=GetPixelChannelTraits(resize_image,channel);
1841 if ((traits == UndefinedPixelTrait) ||
1842 (resize_traits == UndefinedPixelTrait))
1844 offset.x=((double) x+0.5)*scale.x-0.5;
1845 status=InterpolatePixelChannels(image,image_view,resize_image,method,
1846 offset.x,offset.y,q,exception);
1847 if (status == MagickFalse)
1850 q+=(ptrdiff_t) GetPixelChannels(resize_image);
1852 if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
1854 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1859#if defined(MAGICKCORE_OPENMP_SUPPORT)
1863 proceed=SetImageProgress(image,InterpolativeResizeImageTag,progress,
1865 if (proceed == MagickFalse)
1869 resize_view=DestroyCacheView(resize_view);
1870 image_view=DestroyCacheView(image_view);
1871 if (status == MagickFalse)
1872 resize_image=DestroyImage(resize_image);
1873 return(resize_image);
1875#if defined(MAGICKCORE_LQR_DELEGATE)
1911MagickExport Image *LiquidRescaleImage(
const Image *image,
const size_t columns,
1912 const size_t rows,
const double delta_x,
const double rigidity,
1913 ExceptionInfo *exception)
1915#define LiquidRescaleImageTag "Rescale/Image"
1953 assert(image != (
const Image *) NULL);
1954 assert(image->signature == MagickCoreSignature);
1955 assert(exception != (ExceptionInfo *) NULL);
1956 assert(exception->signature == MagickCoreSignature);
1957 if (IsEventLogging() != MagickFalse)
1958 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1959 if ((columns == 0) || (rows == 0))
1960 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
1961 if ((columns == image->columns) && (rows == image->rows))
1962 return(CloneImage(image,0,0,MagickTrue,exception));
1963 if ((columns <= 2) || (rows <= 2))
1964 return(ResizeImage(image,columns,rows,image->filter,exception));
1965 pixel_info=AcquireVirtualMemory(image->columns,image->rows*MaxPixelChannels*
1967 if (pixel_info == (MemoryInfo *) NULL)
1968 return((Image *) NULL);
1969 pixels=(gfloat *) GetVirtualMemoryBlob(pixel_info);
1972 image_view=AcquireVirtualCacheView(image,exception);
1973 for (y=0; y < (ssize_t) image->rows; y++)
1981 if (status == MagickFalse)
1983 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1984 if (p == (
const Quantum *) NULL)
1989 for (x=0; x < (ssize_t) image->columns; x++)
1994 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1995 *q++=(gfloat) (QuantumScale*(double) p[i]);
1996 p+=(ptrdiff_t) GetPixelChannels(image);
1999 image_view=DestroyCacheView(image_view);
2000 carver=lqr_carver_new_ext(pixels,(
int) image->columns,(
int) image->rows,
2001 (
int) GetPixelChannels(image),LQR_COLDEPTH_32F);
2002 if (carver == (LqrCarver *) NULL)
2004 pixel_info=RelinquishVirtualMemory(pixel_info);
2005 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2007 lqr_carver_set_preserve_input_image(carver);
2008 lqr_status=lqr_carver_init(carver,(gint) delta_x,(gfloat) rigidity);
2009 lqr_status=lqr_carver_resize(carver,(gint) columns,(gint) rows);
2011 rescale_image=CloneImage(image,(
size_t) lqr_carver_get_width(carver),
2012 (
size_t) lqr_carver_get_height(carver),MagickTrue,exception);
2013 if (rescale_image == (Image *) NULL)
2015 lqr_carver_destroy(carver);
2016 pixel_info=RelinquishVirtualMemory(pixel_info);
2017 return((Image *) NULL);
2019 if (SetImageStorageClass(rescale_image,DirectClass,exception) == MagickFalse)
2021 lqr_carver_destroy(carver);
2022 pixel_info=RelinquishVirtualMemory(pixel_info);
2023 rescale_image=DestroyImage(rescale_image);
2024 return((Image *) NULL);
2026 rescale_view=AcquireAuthenticCacheView(rescale_image,exception);
2027 (void) lqr_carver_scan_reset(carver);
2028 while (lqr_carver_scan_ext(carver,&x_offset,&y_offset,(
void **) &packet) != 0)
2036 p=QueueCacheViewAuthenticPixels(rescale_view,x_offset,y_offset,1,1,
2038 if (p == (Quantum *) NULL)
2040 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2049 channel=GetPixelChannelChannel(image,i);
2050 traits=GetPixelChannelTraits(image,channel);
2051 rescale_traits=GetPixelChannelTraits(rescale_image,channel);
2052 if ((traits == UndefinedPixelTrait) ||
2053 (rescale_traits == UndefinedPixelTrait))
2055 SetPixelChannel(rescale_image,channel,ClampToQuantum(QuantumRange*
2058 if (SyncCacheViewAuthenticPixels(rescale_view,exception) == MagickFalse)
2061 rescale_view=DestroyCacheView(rescale_view);
2062 pixel_info=RelinquishVirtualMemory(pixel_info);
2063 lqr_carver_destroy(carver);
2064 return(rescale_image);
2067MagickExport Image *LiquidRescaleImage(
const Image *image,
2068 const size_t magick_unused(columns),
const size_t magick_unused(rows),
2069 const double magick_unused(delta_x),
const double magick_unused(rigidity),
2070 ExceptionInfo *exception)
2072 assert(image != (
const Image *) NULL);
2073 assert(image->signature == MagickCoreSignature);
2074 assert(exception != (ExceptionInfo *) NULL);
2075 assert(exception->signature == MagickCoreSignature);
2076 magick_unreferenced(columns);
2077 magick_unreferenced(rows);
2078 magick_unreferenced(delta_x);
2079 magick_unreferenced(rigidity);
2080 if (IsEventLogging() != MagickFalse)
2081 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2082 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
2083 "DelegateLibrarySupportNotBuiltIn",
"'%s' (LQR)",image->filename);
2084 return((Image *) NULL);
2114static inline void CopyPixels(
const Quantum *source,
const ssize_t source_offset,
2115 Quantum *destination,
const ssize_t destination_offset,
const size_t channels)
2120 for (i=0; i < (ssize_t) channels; i++)
2121 destination[(ssize_t) channels*destination_offset+i]=
2122 source[source_offset*(ssize_t) channels+i];
2125static inline void MixPixels(
const Quantum *source,
const ssize_t *source_offset,
2126 const size_t source_size,Quantum *destination,
2127 const ssize_t destination_offset,
const size_t channels)
2132 for (i=0; i < (ssize_t) channels; i++)
2138 for (j=0; j < (ssize_t) source_size; j++)
2139 sum+=(ssize_t) source[source_offset[j]*(ssize_t) channels+i];
2140 destination[(ssize_t) channels*destination_offset+i]=(Quantum) (sum/
2141 (ssize_t) source_size);
2145static inline void Mix2Pixels(
const Quantum *source,
2146 const ssize_t source_offset1,
const ssize_t source_offset2,
2147 Quantum *destination,
const ssize_t destination_offset,
const size_t channels)
2150 offsets[2] = { source_offset1, source_offset2 };
2152 MixPixels(source,offsets,2,destination,destination_offset,channels);
2155static inline int PixelsEqual(
const Quantum *source1,ssize_t offset1,
2156 const Quantum *source2,ssize_t offset2,
const size_t channels)
2161 offset1*=(ssize_t) channels;
2162 offset2*=(ssize_t) channels;
2163 for (i=0; i < (ssize_t) channels; i++)
2164 if (source1[offset1+i] != source2[offset2+i])
2169static inline void Eagle2X(
const Image *source,
const Quantum *pixels,
2170 Quantum *result,
const size_t channels)
2176 for (i=0; i < 4; i++)
2177 CopyPixels(pixels,4,result,i,channels);
2178 if (PixelsEqual(pixels,0,pixels,1,channels) &&
2179 PixelsEqual(pixels,1,pixels,3,channels))
2180 CopyPixels(pixels,0,result,0,channels);
2181 if (PixelsEqual(pixels,1,pixels,2,channels) &&
2182 PixelsEqual(pixels,2,pixels,5,channels))
2183 CopyPixels(pixels,2,result,1,channels);
2184 if (PixelsEqual(pixels,3,pixels,6,channels) &&
2185 PixelsEqual(pixels,6,pixels,7,channels))
2186 CopyPixels(pixels,6,result,2,channels);
2187 if (PixelsEqual(pixels,5,pixels,8,channels) &&
2188 PixelsEqual(pixels,8,pixels,7,channels))
2189 CopyPixels(pixels,8,result,3,channels);
2192static void Hq2XHelper(
const unsigned int rule,
const Quantum *source,
2193 Quantum *destination,
const ssize_t destination_offset,
const size_t channels,
2194 const ssize_t e,
const ssize_t a,
const ssize_t b,
const ssize_t d,
2195 const ssize_t f,
const ssize_t h)
2197#define caseA(N,A,B,C,D) \
2201 offsets[4] = { A, B, C, D }; \
2203 MixPixels(source,offsets,4,destination,destination_offset,channels);\
2206#define caseB(N,A,B,C,D,E,F,G,H) \
2210 offsets[8] = { A, B, C, D, E, F, G, H }; \
2212 MixPixels(source,offsets,8,destination,destination_offset,channels);\
2220 CopyPixels(source,e,destination,destination_offset,channels);
2229 caseB(7,e,e,e,e,e,b,b,d)
2230 caseB(8,e,e,e,e,e,d,d,b)
2231 caseB(9,e,e,e,e,e,e,d,b)
2232 caseB(10,e,e,d,d,d,b,b,b)
2236 offsets[16] = { e, e, e, e, e, e, e, e, e, e, e, e, e, e, d, b };
2238 MixPixels(source,offsets,16,destination,destination_offset,channels);
2243 if (PixelsEqual(source,b,source,d,channels))
2246 offsets[4] = { e, e, d, b };
2248 MixPixels(source,offsets,4,destination,destination_offset,channels);
2251 CopyPixels(source,e,destination,destination_offset,channels);
2256 if (PixelsEqual(source,b,source,d,channels))
2259 offsets[8] = { e, e, d, d, d, b, b, b };
2261 MixPixels(source,offsets,8,destination,destination_offset,channels);
2264 CopyPixels(source,e,destination,destination_offset,channels);
2269 if (PixelsEqual(source,b,source,d,channels))
2272 offsets[16] = { e, e, e, e, e, e, e, e, e, e, e, e, e, e, d, b };
2274 MixPixels(source,offsets,16,destination,destination_offset,channels);
2277 CopyPixels(source,e,destination,destination_offset,channels);
2282 if (PixelsEqual(source,b,source,d,channels))
2285 offsets[4] = { e, e, d, b };
2287 MixPixels(source,offsets,4,destination,destination_offset,channels);
2292 offsets[4] = { e, e, e, a };
2294 MixPixels(source,offsets,4,destination,destination_offset,channels);
2300 if (PixelsEqual(source,b,source,d,channels))
2303 offsets[8] = { e, e, e, e, e, e, d, b };
2305 MixPixels(source,offsets,8,destination,destination_offset,channels);
2310 offsets[4] = { e, e, e, a };
2312 MixPixels(source,offsets,4,destination,destination_offset,channels);
2318 if (PixelsEqual(source,b,source,d,channels))
2321 offsets[8] = { e, e, d, d, d, b, b, b };
2323 MixPixels(source,offsets,8,destination,destination_offset,channels);
2328 offsets[4] = { e, e, e, a };
2330 MixPixels(source,offsets,4,destination,destination_offset,channels);
2336 if (PixelsEqual(source,b,source,f,channels))
2339 offsets[8] = { e, e, e, e, e, b, b, d };
2341 MixPixels(source,offsets,8,destination,destination_offset,channels);
2346 offsets[4] = { e, e, e, d };
2348 MixPixels(source,offsets,4,destination,destination_offset,channels);
2354 if (PixelsEqual(source,d,source,h,channels))
2357 offsets[8] = { e, e, e, e, e, d, d, b };
2359 MixPixels(source,offsets,8,destination,destination_offset,channels);
2364 offsets[4] = { e, e, e, b };
2366 MixPixels(source,offsets,4,destination,destination_offset,channels);
2375static inline unsigned int Hq2XPatternToNumber(
const int *pattern)
2386 for (i=7; i >= 0; i--)
2388 result+=order*(
unsigned int) pattern[i];
2394static inline void Hq2X(
const Image *source,
const Quantum *pixels,
2395 Quantum *result,
const size_t channels)
2397 static const unsigned int
2400 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
2401 4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 12, 12, 5, 3, 1, 12,
2402 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14,
2403 4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 16, 12, 5, 3, 1, 14,
2404 4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 12, 12, 5, 19, 16, 12,
2405 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12,
2406 4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 1, 12, 5, 19, 1, 14,
2407 4, 4, 6, 2, 4, 4, 6, 18, 5, 3, 16, 12, 5, 19, 1, 14,
2408 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
2409 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12,
2410 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14,
2411 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 13, 5, 3, 1, 14,
2412 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 13,
2413 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 12,
2414 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 14,
2415 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 1, 12, 5, 3, 1, 14
2421 !PixelsEqual(pixels,4,pixels,8,channels),
2422 !PixelsEqual(pixels,4,pixels,7,channels),
2423 !PixelsEqual(pixels,4,pixels,6,channels),
2424 !PixelsEqual(pixels,4,pixels,5,channels),
2425 !PixelsEqual(pixels,4,pixels,3,channels),
2426 !PixelsEqual(pixels,4,pixels,2,channels),
2427 !PixelsEqual(pixels,4,pixels,1,channels),
2428 !PixelsEqual(pixels,4,pixels,0,channels)
2431#define Rotated(p) p[2], p[4], p[7], p[1], p[6], p[0], p[3], p[5]
2432 const int pattern2[] = { Rotated(pattern1) };
2433 const int pattern3[] = { Rotated(pattern2) };
2434 const int pattern4[] = { Rotated(pattern3) };
2437 Hq2XHelper(Hq2XTable[Hq2XPatternToNumber(pattern1)],pixels,result,0,
2438 channels,4,0,1,3,5,7);
2439 Hq2XHelper(Hq2XTable[Hq2XPatternToNumber(pattern2)],pixels,result,1,
2440 channels,4,2,5,1,7,3);
2441 Hq2XHelper(Hq2XTable[Hq2XPatternToNumber(pattern3)],pixels,result,3,
2442 channels,4,8,7,5,3,1);
2443 Hq2XHelper(Hq2XTable[Hq2XPatternToNumber(pattern4)],pixels,result,2,
2444 channels,4,6,3,7,1,5);
2447static void Fish2X(
const Image *source,
const Quantum *pixels,Quantum *result,
2448 const size_t channels)
2450#define Corner(A,B,C,D) \
2452 if (intensities[B] > intensities[A]) \
2455 offsets[3] = { B, C, D }; \
2457 MixPixels(pixels,offsets,3,result,3,channels); \
2462 offsets[3] = { A, B, C }; \
2464 MixPixels(pixels,offsets,3,result,3,channels); \
2468#define Line(A,B,C,D) \
2470 if (intensities[C] > intensities[A]) \
2471 Mix2Pixels(pixels,C,D,result,3,channels); \
2473 Mix2Pixels(pixels,A,B,result,3,channels); \
2477 pixels_offsets[4] = { 0, 1, 3, 4 };
2493 for (i=0; i < 9; i++)
2494 intensities[i]=(MagickFloatType) GetPixelIntensity(source,pixels+
2495 i*(ssize_t) channels);
2496 CopyPixels(pixels,0,result,0,channels);
2497 CopyPixels(pixels,(ssize_t) (intensities[0] > intensities[1] ? 0 : 1),result,
2499 CopyPixels(pixels,(ssize_t) (intensities[0] > intensities[3] ? 0 : 3),result,
2501 ae=PixelsEqual(pixels,0,pixels,4,channels);
2502 bd=PixelsEqual(pixels,1,pixels,3,channels);
2503 ab=PixelsEqual(pixels,0,pixels,1,channels);
2504 de=PixelsEqual(pixels,3,pixels,4,channels);
2505 ad=PixelsEqual(pixels,0,pixels,3,channels);
2506 be=PixelsEqual(pixels,1,pixels,4,channels);
2509 CopyPixels(pixels,0,result,3,channels);
2512 if (ad && de && !ab)
2517 if (be && de && !ab)
2522 if (ad && ab && !be)
2527 if (ab && be && !ad)
2532 if (ae && (!bd || intensities[1] > intensities[0]))
2534 Mix2Pixels(pixels,0,4,result,3,channels);
2537 if (bd && (!ae || intensities[0] > intensities[1]))
2539 Mix2Pixels(pixels,1,3,result,3,channels);
2562 MixPixels(pixels,pixels_offsets,4,result,3,channels);
2567static void Xbr2X(
const Image *magick_unused(source),
const Quantum *pixels,
2568 Quantum *result,
const size_t channels)
2570#define WeightVar(M,N) const int w_##M##_##N = \
2571 PixelsEqual(pixels,M,pixels,N,channels) ? 0 : 1;
2603 magick_unreferenced(source);
2606 w_12_16 + w_12_8 + w_6_10 + w_6_2 + (4 * w_11_7) <
2607 w_11_17 + w_11_5 + w_7_13 + w_7_1 + (4 * w_12_6)
2609 Mix2Pixels(pixels,(ssize_t) (w_12_11 <= w_12_7 ? 11 : 7),12,result,0,
2612 CopyPixels(pixels,12,result,0,channels);
2614 w_12_18 + w_12_6 + w_8_14 + w_8_2 + (4 * w_7_13) <
2615 w_13_17 + w_13_9 + w_11_7 + w_7_3 + (4 * w_12_8)
2617 Mix2Pixels(pixels,(ssize_t) (w_12_7 <= w_12_13 ? 7 : 13),12,result,1,
2620 CopyPixels(pixels,12,result,1,channels);
2622 w_12_6 + w_12_18 + w_16_10 + w_16_22 + (4 * w_11_17) <
2623 w_11_7 + w_11_15 + w_13_17 + w_17_21 + (4 * w_12_16)
2625 Mix2Pixels(pixels,(ssize_t) (w_12_11 <= w_12_17 ? 11 : 17),12,result,2,
2628 CopyPixels(pixels,12,result,2,channels);
2630 w_12_8 + w_12_16 + w_18_14 + w_18_22 + (4 * w_13_17) <
2631 w_11_17 + w_17_23 + w_17_19 + w_7_13 + (4 * w_12_18)
2633 Mix2Pixels(pixels,(ssize_t) (w_12_13 <= w_12_17 ? 13 : 17),12,result,3,
2636 CopyPixels(pixels,12,result,3,channels);
2639static void Scale2X(
const Image *magick_unused(source),
const Quantum *pixels,
2640 Quantum *result,
const size_t channels)
2642 magick_unreferenced(source);
2644 if (PixelsEqual(pixels,1,pixels,7,channels) ||
2645 PixelsEqual(pixels,3,pixels,5,channels))
2650 for (i=0; i < 4; i++)
2651 CopyPixels(pixels,4,result,i,channels);
2654 if (PixelsEqual(pixels,1,pixels,3,channels))
2655 CopyPixels(pixels,3,result,0,channels);
2657 CopyPixels(pixels,4,result,0,channels);
2658 if (PixelsEqual(pixels,1,pixels,5,channels))
2659 CopyPixels(pixels,5,result,1,channels);
2661 CopyPixels(pixels,4,result,1,channels);
2662 if (PixelsEqual(pixels,3,pixels,7,channels))
2663 CopyPixels(pixels,3,result,2,channels);
2665 CopyPixels(pixels,4,result,2,channels);
2666 if (PixelsEqual(pixels,5,pixels,7,channels))
2667 CopyPixels(pixels,5,result,3,channels);
2669 CopyPixels(pixels,4,result,3,channels);
2672static void Epbx2X(
const Image *magick_unused(source),
const Quantum *pixels,
2673 Quantum *result,
const size_t channels)
2675#define HelperCond(a,b,c,d,e,f,g) ( \
2676 PixelsEqual(pixels,a,pixels,b,channels) && ( \
2677 PixelsEqual(pixels,c,pixels,d,channels) || \
2678 PixelsEqual(pixels,c,pixels,e,channels) || \
2679 PixelsEqual(pixels,a,pixels,f,channels) || \
2680 PixelsEqual(pixels,b,pixels,g,channels) \
2687 magick_unreferenced(source);
2689 for (i=0; i < 4; i++)
2690 CopyPixels(pixels,4,result,i,channels);
2692 !PixelsEqual(pixels,3,pixels,5,channels) &&
2693 !PixelsEqual(pixels,1,pixels,7,channels) &&
2695 PixelsEqual(pixels,4,pixels,3,channels) ||
2696 PixelsEqual(pixels,4,pixels,7,channels) ||
2697 PixelsEqual(pixels,4,pixels,5,channels) ||
2698 PixelsEqual(pixels,4,pixels,1,channels) ||
2701 !PixelsEqual(pixels,0,pixels,8,channels) ||
2702 PixelsEqual(pixels,4,pixels,6,channels) ||
2703 PixelsEqual(pixels,3,pixels,2,channels)
2706 !PixelsEqual(pixels,6,pixels,2,channels) ||
2707 PixelsEqual(pixels,4,pixels,0,channels) ||
2708 PixelsEqual(pixels,4,pixels,8,channels)
2714 if (HelperCond(1,3,4,0,8,2,6))
2715 Mix2Pixels(pixels,1,3,result,0,channels);
2716 if (HelperCond(5,1,4,2,6,8,0))
2717 Mix2Pixels(pixels,5,1,result,1,channels);
2718 if (HelperCond(3,7,4,6,2,0,8))
2719 Mix2Pixels(pixels,3,7,result,2,channels);
2720 if (HelperCond(7,5,4,8,0,6,2))
2721 Mix2Pixels(pixels,7,5,result,3,channels);
2727static inline void Eagle3X(
const Image *magick_unused(source),
2728 const Quantum *pixels,Quantum *result,
const size_t channels)
2736 magick_unreferenced(source);
2738 corner_tl=PixelsEqual(pixels,0,pixels,1,channels) &&
2739 PixelsEqual(pixels,0,pixels,3,channels);
2740 corner_tr=PixelsEqual(pixels,1,pixels,2,channels) &&
2741 PixelsEqual(pixels,2,pixels,5,channels);
2742 corner_bl=PixelsEqual(pixels,3,pixels,6,channels) &&
2743 PixelsEqual(pixels,6,pixels,7,channels);
2744 corner_br=PixelsEqual(pixels,5,pixels,7,channels) &&
2745 PixelsEqual(pixels,7,pixels,8,channels);
2746 CopyPixels(pixels,(ssize_t) (corner_tl ? 0 : 4),result,0,channels);
2747 if (corner_tl && corner_tr)
2748 Mix2Pixels(pixels,0,2,result,1,channels);
2750 CopyPixels(pixels,4,result,1,channels);
2751 CopyPixels(pixels,(ssize_t) (corner_tr ? 1 : 4),result,2,channels);
2752 if (corner_tl && corner_bl)
2753 Mix2Pixels(pixels,0,6,result,3,channels);
2755 CopyPixels(pixels,4,result,3,channels);
2756 CopyPixels(pixels,4,result,4,channels);
2757 if (corner_tr && corner_br)
2758 Mix2Pixels(pixels,2,8,result,5,channels);
2760 CopyPixels(pixels,4,result,5,channels);
2761 CopyPixels(pixels,(ssize_t) (corner_bl ? 3 : 4),result,6,channels);
2762 if (corner_bl && corner_br)
2763 Mix2Pixels(pixels,6,8,result,7,channels);
2765 CopyPixels(pixels,4,result,7,channels);
2766 CopyPixels(pixels,(ssize_t) (corner_br ? 5 : 4),result,8,channels);
2769static inline void Eagle3XB(
const Image *magick_unused(source),
2770 const Quantum *pixels,Quantum *result,
const size_t channels)
2778 magick_unreferenced(source);
2780 corner_tl=PixelsEqual(pixels,0,pixels,1,channels) &&
2781 PixelsEqual(pixels,0,pixels,3,channels);
2782 corner_tr=PixelsEqual(pixels,1,pixels,2,channels) &&
2783 PixelsEqual(pixels,2,pixels,5,channels);
2784 corner_bl=PixelsEqual(pixels,3,pixels,6,channels) &&
2785 PixelsEqual(pixels,6,pixels,7,channels);
2786 corner_br=PixelsEqual(pixels,5,pixels,7,channels) &&
2787 PixelsEqual(pixels,7,pixels,8,channels);
2788 CopyPixels(pixels,(ssize_t) (corner_tl ? 0 : 4),result,0,channels);
2789 CopyPixels(pixels,4,result,1,channels);
2790 CopyPixels(pixels,(ssize_t) (corner_tr ? 1 : 4),result,2,channels);
2791 CopyPixels(pixels,4,result,3,channels);
2792 CopyPixels(pixels,4,result,4,channels);
2793 CopyPixels(pixels,4,result,5,channels);
2794 CopyPixels(pixels,(ssize_t) (corner_bl ? 3 : 4),result,6,channels);
2795 CopyPixels(pixels,4,result,7,channels);
2796 CopyPixels(pixels,(ssize_t) (corner_br ? 5 : 4),result,8,channels);
2799static inline void Scale3X(
const Image *magick_unused(source),
2800 const Quantum *pixels,Quantum *result,
const size_t channels)
2802 magick_unreferenced(source);
2804 if (!PixelsEqual(pixels,1,pixels,7,channels) &&
2805 !PixelsEqual(pixels,3,pixels,5,channels))
2807 if (PixelsEqual(pixels,3,pixels,1,channels))
2808 CopyPixels(pixels,3,result,0,channels);
2810 CopyPixels(pixels,4,result,0,channels);
2814 PixelsEqual(pixels,3,pixels,1,channels) &&
2815 !PixelsEqual(pixels,4,pixels,2,channels)
2818 PixelsEqual(pixels,5,pixels,1,channels) &&
2819 !PixelsEqual(pixels,4,pixels,0,channels)
2822 CopyPixels(pixels,1,result,1,channels);
2824 CopyPixels(pixels,4,result,1,channels);
2825 if (PixelsEqual(pixels,5,pixels,1,channels))
2826 CopyPixels(pixels,5,result,2,channels);
2828 CopyPixels(pixels,4,result,2,channels);
2831 PixelsEqual(pixels,3,pixels,1,channels) &&
2832 !PixelsEqual(pixels,4,pixels,6,channels)
2835 PixelsEqual(pixels,3,pixels,7,channels) &&
2836 !PixelsEqual(pixels,4,pixels,0,channels)
2839 CopyPixels(pixels,3,result,3,channels);
2841 CopyPixels(pixels,4,result,3,channels);
2842 CopyPixels(pixels,4,result,4,channels);
2845 PixelsEqual(pixels,5,pixels,1,channels) &&
2846 !PixelsEqual(pixels,4,pixels,8,channels)
2849 PixelsEqual(pixels,5,pixels,7,channels) &&
2850 !PixelsEqual(pixels,4,pixels,2,channels)
2853 CopyPixels(pixels,5,result,5,channels);
2855 CopyPixels(pixels,4,result,5,channels);
2856 if (PixelsEqual(pixels,3,pixels,7,channels))
2857 CopyPixels(pixels,3,result,6,channels);
2859 CopyPixels(pixels,4,result,6,channels);
2862 PixelsEqual(pixels,3,pixels,7,channels) &&
2863 !PixelsEqual(pixels,4,pixels,8,channels)
2866 PixelsEqual(pixels,5,pixels,7,channels) &&
2867 !PixelsEqual(pixels,4,pixels,6,channels)
2870 CopyPixels(pixels,7,result,7,channels);
2872 CopyPixels(pixels,4,result,7,channels);
2873 if (PixelsEqual(pixels,5,pixels,7,channels))
2874 CopyPixels(pixels,5,result,8,channels);
2876 CopyPixels(pixels,4,result,8,channels);
2883 for (i=0; i < 9; i++)
2884 CopyPixels(pixels,4,result,i,channels);
2888MagickExport Image *MagnifyImage(
const Image *image,ExceptionInfo *exception)
2890#define MagnifyImageTag "Magnify/Image"
2891#define MaxMagnification 9
2924 (*scaling_method)(
const Image *,
const Quantum *,Quantum *,size_t);
2929 assert(image != (
const Image *) NULL);
2930 assert(image->signature == MagickCoreSignature);
2931 assert(exception != (ExceptionInfo *) NULL);
2932 assert(exception->signature == MagickCoreSignature);
2933 if (IsEventLogging() != MagickFalse)
2934 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2935 option=GetImageOption(image->image_info,
"magnify:method");
2936 if (option == (
char *) NULL)
2938 scaling_method=Scale2X;
2945 if (LocaleCompare(option,
"eagle2x") == 0)
2947 scaling_method=Eagle2X;
2952 if (LocaleCompare(option,
"eagle3x") == 0)
2954 scaling_method=Eagle3X;
2959 if (LocaleCompare(option,
"eagle3xb") == 0)
2961 scaling_method=Eagle3XB;
2966 if (LocaleCompare(option,
"epbx2x") == 0)
2968 scaling_method=Epbx2X;
2977 if (LocaleCompare(option,
"fish2x") == 0)
2979 scaling_method=Fish2X;
2988 if (LocaleCompare(option,
"hq2x") == 0)
2990 scaling_method=Hq2X;
2999 if (LocaleCompare(option,
"scale2x") == 0)
3001 scaling_method=Scale2X;
3006 if (LocaleCompare(option,
"scale3x") == 0)
3008 scaling_method=Scale3X;
3017 if (LocaleCompare(option,
"xbr2x") == 0)
3019 scaling_method=Xbr2X;
3028 assert((magnification*magnification) <= MaxMagnification);
3032 source_image=CloneImage(image,image->columns,image->rows,MagickTrue,
3034 if (source_image == (Image *) NULL)
3035 return((Image *) NULL);
3040 rectangle.width=image->columns;
3041 rectangle.height=image->rows;
3042 (void) CopyImagePixels(source_image,image,&rectangle,&offset,exception);
3043 if (IssRGBCompatibleColorspace(source_image->colorspace) == MagickFalse)
3044 (void) TransformImageColorspace(source_image,sRGBColorspace,exception);
3045 magnify_image=CloneImage(source_image,magnification*source_image->columns,
3046 magnification*source_image->rows,MagickTrue,exception);
3047 if (magnify_image == (Image *) NULL)
3049 source_image=DestroyImage(source_image);
3050 return((Image *) NULL);
3057 image_view=AcquireVirtualCacheView(source_image,exception);
3058 magnify_view=AcquireAuthenticCacheView(magnify_image,exception);
3059#if defined(MAGICKCORE_OPENMP_SUPPORT)
3060 #pragma omp parallel for schedule(static) shared(progress,status) \
3061 magick_number_threads(source_image,magnify_image,source_image->rows,1)
3063 for (y=0; y < (ssize_t) source_image->rows; y++)
3066 r[MaxMagnification*MaxPixelChannels];
3074 if (status == MagickFalse)
3076 q=QueueCacheViewAuthenticPixels(magnify_view,0,magnification*y,
3077 magnify_image->columns,magnification,exception);
3078 if (q == (Quantum *) NULL)
3086 for (x=0; x < (ssize_t) source_image->columns; x++)
3098 p=GetCacheViewVirtualPixels(image_view,x-width/2,y-width/2,width,width,
3100 if (p == (Quantum *) NULL)
3105 channels=GetPixelChannels(source_image);
3106 scaling_method(source_image,p,r,channels);
3110 for (j=0; j < (ssize_t) magnification; j++)
3111 for (i=0; i < (ssize_t) (channels*magnification); i++)
3112 q[j*(ssize_t) channels*(ssize_t) magnify_image->columns+i]=
3113 r[j*magnification*(ssize_t) channels+i];
3114 q+=(ptrdiff_t) magnification*GetPixelChannels(magnify_image);
3116 if (SyncCacheViewAuthenticPixels(magnify_view,exception) == MagickFalse)
3118 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3123#if defined(MAGICKCORE_OPENMP_SUPPORT)
3127 proceed=SetImageProgress(image,MagnifyImageTag,progress,image->rows);
3128 if (proceed == MagickFalse)
3132 magnify_view=DestroyCacheView(magnify_view);
3133 image_view=DestroyCacheView(image_view);
3134 source_image=DestroyImage(source_image);
3135 if (status == MagickFalse)
3136 magnify_image=DestroyImage(magnify_image);
3137 return(magnify_image);
3165MagickExport Image *MinifyImage(
const Image *image,ExceptionInfo *exception)
3170 assert(image != (Image *) NULL);
3171 assert(image->signature == MagickCoreSignature);
3172 assert(exception != (ExceptionInfo *) NULL);
3173 assert(exception->signature == MagickCoreSignature);
3174 if (IsEventLogging() != MagickFalse)
3175 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3176 minify_image=ResizeImage(image,image->columns/2,image->rows/2,SplineFilter,
3178 return(minify_image);
3215MagickExport Image *ResampleImage(
const Image *image,
const double x_resolution,
3216 const double y_resolution,
const FilterType filter,ExceptionInfo *exception)
3218#define ResampleImageTag "Resample/Image"
3230 assert(image != (
const Image *) NULL);
3231 assert(image->signature == MagickCoreSignature);
3232 assert(exception != (ExceptionInfo *) NULL);
3233 assert(exception->signature == MagickCoreSignature);
3234 if (IsEventLogging() != MagickFalse)
3235 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3236 width=(size_t) (x_resolution*image->columns/(image->resolution.x == 0.0 ?
3237 DefaultResolution : image->resolution.x)+0.5);
3238 height=(size_t) (y_resolution*image->rows/(image->resolution.y == 0.0 ?
3239 DefaultResolution : image->resolution.y)+0.5);
3240 resample_image=ResizeImage(image,width,height,filter,exception);
3241 if (resample_image != (Image *) NULL)
3243 resample_image->resolution.x=x_resolution;
3244 resample_image->resolution.y=y_resolution;
3246 return(resample_image);
3297static ContributionInfo **DestroyContributionTLS(
3298 ContributionInfo **contribution)
3303 assert(contribution != (ContributionInfo **) NULL);
3304 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
3305 if (contribution[i] != (ContributionInfo *) NULL)
3306 contribution[i]=(ContributionInfo *) RelinquishAlignedMemory(
3308 contribution=(ContributionInfo **) RelinquishMagickMemory(contribution);
3309 return(contribution);
3312static ContributionInfo **AcquireContributionTLS(
const size_t count)
3323 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
3324 contribution=(ContributionInfo **) AcquireQuantumMemory(number_threads,
3325 sizeof(*contribution));
3326 if (contribution == (ContributionInfo **) NULL)
3327 return((ContributionInfo **) NULL);
3328 (void) memset(contribution,0,number_threads*
sizeof(*contribution));
3329 for (i=0; i < (ssize_t) number_threads; i++)
3331 contribution[i]=(ContributionInfo *) MagickAssumeAligned(
3332 AcquireAlignedMemory(count,
sizeof(**contribution)));
3333 if (contribution[i] == (ContributionInfo *) NULL)
3334 return(DestroyContributionTLS(contribution));
3336 return(contribution);
3339static MagickBooleanType HorizontalFilter(
3340 const ResizeFilter *magick_restrict resize_filter,
3341 const Image *magick_restrict image,Image *magick_restrict resize_image,
3342 const double x_factor,
const MagickSizeType span,
3343 MagickOffsetType *magick_restrict progress,ExceptionInfo *exception)
3345#define ResizeImageTag "Resize/Image"
3355 **magick_restrict contributions;
3370 scale=MagickMax(1.0/x_factor+MagickEpsilon,1.0);
3371 support=scale*GetResizeFilterSupport(resize_filter);
3372 storage_class=support > 0.5 ? DirectClass : image->storage_class;
3373 if (SetImageStorageClass(resize_image,storage_class,exception) == MagickFalse)
3374 return(MagickFalse);
3380 support=(double) 0.5;
3383 contributions=AcquireContributionTLS((
size_t) (2.0*support+3.0));
3384 if (contributions == (ContributionInfo **) NULL)
3386 (void) ThrowMagickException(exception,GetMagickModule(),
3387 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",image->filename);
3388 return(MagickFalse);
3391 scale=MagickSafeReciprocal(scale);
3392 image_view=AcquireVirtualCacheView(image,exception);
3393 resize_view=AcquireAuthenticCacheView(resize_image,exception);
3394#if defined(MAGICKCORE_OPENMP_SUPPORT)
3395 #pragma omp parallel for schedule(static) shared(progress,status) \
3396 magick_number_threads(image,resize_image,resize_image->columns,1)
3398 for (x=0; x < (ssize_t) resize_image->columns; x++)
3401 id = GetOpenMPThreadId();
3407 *magick_restrict contribution;
3422 if (status == MagickFalse)
3424 bisect=(double) (x+0.5)/x_factor+MagickEpsilon;
3425 start=(ssize_t) MagickMax(bisect-support+0.5,0.0);
3426 stop=(ssize_t) MagickMin(bisect+support+0.5,(
double) image->columns);
3428 contribution=contributions[id];
3429 for (n=0; n < (stop-start); n++)
3431 contribution[n].pixel=start+n;
3432 contribution[n].weight=GetResizeFilterWeight(resize_filter,scale*
3433 ((
double) (start+n)-bisect+0.5));
3434 density+=contribution[n].weight;
3438 if ((density != 0.0) && (density != 1.0))
3446 density=MagickSafeReciprocal(density);
3447 for (i=0; i < n; i++)
3448 contribution[i].weight*=density;
3450 p=GetCacheViewVirtualPixels(image_view,contribution[0].pixel,0,(
size_t)
3451 (contribution[n-1].pixel-contribution[0].pixel+1),image->rows,exception);
3452 q=QueueCacheViewAuthenticPixels(resize_view,x,0,1,resize_image->rows,
3454 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3459 for (y=0; y < (ssize_t) resize_image->rows; y++)
3464 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3482 channel=GetPixelChannelChannel(image,i);
3483 traits=GetPixelChannelTraits(image,channel);
3484 resize_traits=GetPixelChannelTraits(resize_image,channel);
3485 if ((traits == UndefinedPixelTrait) ||
3486 (resize_traits == UndefinedPixelTrait))
3488 if (((resize_traits & CopyPixelTrait) != 0) ||
3489 (GetPixelWriteMask(resize_image,q) <= (QuantumRange/2)))
3491 j=(ssize_t) (MagickMin(MagickMax(bisect,(
double) start),(
double)
3493 k=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
3494 (contribution[j-start].pixel-contribution[0].pixel);
3495 SetPixelChannel(resize_image,channel,
3496 p[k*(ssize_t) GetPixelChannels(image)+i],q);
3500 if ((resize_traits & BlendPixelTrait) == 0)
3505 for (j=0; j < n; j++)
3507 k=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
3508 (contribution[j].pixel-contribution[0].pixel);
3509 alpha=contribution[j].weight;
3510 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3512 SetPixelChannel(resize_image,channel,ClampToQuantum(pixel),q);
3519 for (j=0; j < n; j++)
3521 k=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
3522 (contribution[j].pixel-contribution[0].pixel);
3523 alpha=contribution[j].weight*QuantumScale*
3524 (double) GetPixelAlpha(image,p+k*(ssize_t) GetPixelChannels(image));
3525 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3528 gamma=MagickSafeReciprocal(gamma);
3529 SetPixelChannel(resize_image,channel,ClampToQuantum(gamma*pixel),q);
3531 q+=(ptrdiff_t) GetPixelChannels(resize_image);
3533 if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
3535 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3540#if defined(MAGICKCORE_OPENMP_SUPPORT)
3544 proceed=SetImageProgress(image,ResizeImageTag,*progress,span);
3545 if (proceed == MagickFalse)
3549 resize_view=DestroyCacheView(resize_view);
3550 image_view=DestroyCacheView(image_view);
3551 contributions=DestroyContributionTLS(contributions);
3555static MagickBooleanType VerticalFilter(
3556 const ResizeFilter *magick_restrict resize_filter,
3557 const Image *magick_restrict image,Image *magick_restrict resize_image,
3558 const double y_factor,
const MagickSizeType span,
3559 MagickOffsetType *magick_restrict progress,ExceptionInfo *exception)
3569 **magick_restrict contributions;
3584 scale=MagickMax(1.0/y_factor+MagickEpsilon,1.0);
3585 support=scale*GetResizeFilterSupport(resize_filter);
3586 storage_class=support > 0.5 ? DirectClass : image->storage_class;
3587 if (SetImageStorageClass(resize_image,storage_class,exception) == MagickFalse)
3588 return(MagickFalse);
3594 support=(double) 0.5;
3597 contributions=AcquireContributionTLS((
size_t) (2.0*support+3.0));
3598 if (contributions == (ContributionInfo **) NULL)
3600 (void) ThrowMagickException(exception,GetMagickModule(),
3601 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",image->filename);
3602 return(MagickFalse);
3605 scale=MagickSafeReciprocal(scale);
3606 image_view=AcquireVirtualCacheView(image,exception);
3607 resize_view=AcquireAuthenticCacheView(resize_image,exception);
3608#if defined(MAGICKCORE_OPENMP_SUPPORT)
3609 #pragma omp parallel for schedule(static) shared(progress,status) \
3610 magick_number_threads(image,resize_image,resize_image->rows,1)
3612 for (y=0; y < (ssize_t) resize_image->rows; y++)
3615 id = GetOpenMPThreadId();
3621 *magick_restrict contribution;
3636 if (status == MagickFalse)
3638 bisect=(double) (y+0.5)/y_factor+MagickEpsilon;
3639 start=(ssize_t) MagickMax(bisect-support+0.5,0.0);
3640 stop=(ssize_t) MagickMin(bisect+support+0.5,(
double) image->rows);
3642 contribution=contributions[id];
3643 for (n=0; n < (stop-start); n++)
3645 contribution[n].pixel=start+n;
3646 contribution[n].weight=GetResizeFilterWeight(resize_filter,scale*
3647 ((
double) (start+n)-bisect+0.5));
3648 density+=contribution[n].weight;
3652 if ((density != 0.0) && (density != 1.0))
3660 density=MagickSafeReciprocal(density);
3661 for (i=0; i < n; i++)
3662 contribution[i].weight*=density;
3664 p=GetCacheViewVirtualPixels(image_view,0,contribution[0].pixel,
3665 image->columns,(
size_t) (contribution[n-1].pixel-contribution[0].pixel+1),
3667 q=QueueCacheViewAuthenticPixels(resize_view,0,y,resize_image->columns,1,
3669 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3674 for (x=0; x < (ssize_t) resize_image->columns; x++)
3679 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3697 channel=GetPixelChannelChannel(image,i);
3698 traits=GetPixelChannelTraits(image,channel);
3699 resize_traits=GetPixelChannelTraits(resize_image,channel);
3700 if ((traits == UndefinedPixelTrait) ||
3701 (resize_traits == UndefinedPixelTrait))
3703 if (((resize_traits & CopyPixelTrait) != 0) ||
3704 (GetPixelWriteMask(resize_image,q) <= (QuantumRange/2)))
3706 j=(ssize_t) (MagickMin(MagickMax(bisect,(
double) start),(
double)
3708 k=(ssize_t) ((contribution[j-start].pixel-contribution[0].pixel)*
3709 (ssize_t) image->columns+x);
3710 SetPixelChannel(resize_image,channel,p[k*(ssize_t)
3711 GetPixelChannels(image)+i],q);
3715 if ((resize_traits & BlendPixelTrait) == 0)
3720 for (j=0; j < n; j++)
3722 k=(ssize_t) ((contribution[j].pixel-contribution[0].pixel)*
3723 (ssize_t) image->columns+x);
3724 alpha=contribution[j].weight;
3725 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3727 SetPixelChannel(resize_image,channel,ClampToQuantum(pixel),q);
3731 for (j=0; j < n; j++)
3733 k=(ssize_t) ((contribution[j].pixel-contribution[0].pixel)*
3734 (ssize_t) image->columns+x);
3735 alpha=contribution[j].weight*QuantumScale*(double)
3736 GetPixelAlpha(image,p+k*(ssize_t) GetPixelChannels(image));
3737 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3740 gamma=MagickSafeReciprocal(gamma);
3741 SetPixelChannel(resize_image,channel,ClampToQuantum(gamma*pixel),q);
3743 q+=(ptrdiff_t) GetPixelChannels(resize_image);
3745 if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
3747 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3752#if defined(MAGICKCORE_OPENMP_SUPPORT)
3756 proceed=SetImageProgress(image,ResizeImageTag,*progress,span);
3757 if (proceed == MagickFalse)
3761 resize_view=DestroyCacheView(resize_view);
3762 image_view=DestroyCacheView(image_view);
3763 contributions=DestroyContributionTLS(contributions);
3767MagickExport Image *ResizeImage(
const Image *image,
const size_t columns,
3768 const size_t rows,
const FilterType filter,ExceptionInfo *exception)
3796 assert(image != (Image *) NULL);
3797 assert(image->signature == MagickCoreSignature);
3798 assert(exception != (ExceptionInfo *) NULL);
3799 assert(exception->signature == MagickCoreSignature);
3800 if (IsEventLogging() != MagickFalse)
3801 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3802 if ((columns == 0) || (rows == 0))
3803 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
3804 if ((columns == image->columns) && (rows == image->rows) &&
3805 (filter == UndefinedFilter))
3806 return(CloneImage(image,0,0,MagickTrue,exception));
3810 x_factor=(double) (columns*MagickSafeReciprocal((
double) image->columns));
3811 y_factor=(double) (rows*MagickSafeReciprocal((
double) image->rows));
3812 filter_type=LanczosFilter;
3813 if (filter != UndefinedFilter)
3816 if ((x_factor == 1.0) && (y_factor == 1.0))
3817 filter_type=PointFilter;
3819 if ((image->storage_class == PseudoClass) ||
3820 (image->alpha_trait != UndefinedPixelTrait) ||
3821 ((x_factor*y_factor) > 1.0))
3822 filter_type=MitchellFilter;
3823 resize_filter=AcquireResizeFilter(image,filter_type,MagickFalse,exception);
3824#if defined(MAGICKCORE_OPENCL_SUPPORT)
3825 resize_image=AccelerateResizeImage(image,columns,rows,resize_filter,
3827 if (resize_image != (Image *) NULL)
3829 resize_filter=DestroyResizeFilter(resize_filter);
3830 goto record_resize_transform;
3833 resize_image=CloneImage(image,columns,rows,MagickTrue,exception);
3834 if (resize_image == (Image *) NULL)
3836 resize_filter=DestroyResizeFilter(resize_filter);
3837 return(resize_image);
3839 if (x_factor > y_factor)
3840 filter_image=CloneImage(image,columns,image->rows,MagickTrue,exception);
3842 filter_image=CloneImage(image,image->columns,rows,MagickTrue,exception);
3843 if (filter_image == (Image *) NULL)
3845 resize_filter=DestroyResizeFilter(resize_filter);
3846 return(DestroyImage(resize_image));
3852 if (x_factor > y_factor)
3854 span=(MagickSizeType) (filter_image->columns+rows);
3855 status=HorizontalFilter(resize_filter,image,filter_image,x_factor,span,
3857 status&=(MagickStatusType) VerticalFilter(resize_filter,filter_image,
3858 resize_image,y_factor,span,&offset,exception);
3862 span=(MagickSizeType) (filter_image->rows+columns);
3863 status=VerticalFilter(resize_filter,image,filter_image,y_factor,span,
3865 status&=(MagickStatusType) HorizontalFilter(resize_filter,filter_image,
3866 resize_image,x_factor,span,&offset,exception);
3871 filter_image=DestroyImage(filter_image);
3872 resize_filter=DestroyResizeFilter(resize_filter);
3873 if (status == MagickFalse)
3875 resize_image=DestroyImage(resize_image);
3876 return((Image *) NULL);
3878 resize_image->type=image->type;
3879#if defined(MAGICKCORE_OPENCL_SUPPORT)
3880record_resize_transform:
3884 transform[MagickPathExtent];
3886 (void) FormatLocaleString(transform,MagickPathExtent,
3887 "resize %.17gx%.17g %.17gx%.17g %d",(
double) image->columns,
3888 (
double) image->rows,(
double) resize_image->columns,
3889 (
double) resize_image->rows,(
int) filter_type);
3890 AppendImageProfileProperty(resize_image,
"hdrgm",
"hdrgm:Transform",
3891 transform,exception);
3893 return(resize_image);
3927MagickExport Image *SampleImage(
const Image *image,
const size_t columns,
3928 const size_t rows,ExceptionInfo *exception)
3930#define SampleImageTag "Sample/Image"
3954 assert(image != (
const Image *) NULL);
3955 assert(image->signature == MagickCoreSignature);
3956 assert(exception != (ExceptionInfo *) NULL);
3957 assert(exception->signature == MagickCoreSignature);
3958 if (IsEventLogging() != MagickFalse)
3959 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3960 if ((columns == 0) || (rows == 0))
3961 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
3962 if ((columns == image->columns) && (rows == image->rows))
3963 return(CloneImage(image,0,0,MagickTrue,exception));
3964 sample_image=CloneImage(image,columns,rows,MagickTrue,exception);
3965 if (sample_image == (Image *) NULL)
3966 return((Image *) NULL);
3970 sample_offset.x=0.5-MagickEpsilon;
3971 sample_offset.y=sample_offset.x;
3976 value=GetImageArtifact(image,
"sample:offset");
3977 if (value != (
char *) NULL)
3985 (void) ParseGeometry(value,&geometry_info);
3986 flags=ParseGeometry(value,&geometry_info);
3987 sample_offset.x=sample_offset.y=geometry_info.rho/100.0-MagickEpsilon;
3988 if ((flags & SigmaValue) != 0)
3989 sample_offset.y=geometry_info.sigma/100.0-MagickEpsilon;
3997 image_view=AcquireVirtualCacheView(image,exception);
3998 sample_view=AcquireAuthenticCacheView(sample_image,exception);
3999#if defined(MAGICKCORE_OPENMP_SUPPORT)
4000 #pragma omp parallel for schedule(static) shared(status) \
4001 magick_number_threads(image,sample_image,sample_image->rows,2)
4003 for (y=0; y < (ssize_t) sample_image->rows; y++)
4011 if (status == MagickFalse)
4013 q=QueueCacheViewAuthenticPixels(sample_view,0,y,sample_image->columns,1,
4015 if (q == (Quantum *) NULL)
4023 for (x=0; x < (ssize_t) sample_image->columns; x++)
4033 if (GetPixelWriteMask(sample_image,q) <= (QuantumRange/2))
4035 q+=(ptrdiff_t) GetPixelChannels(sample_image);
4038 x_offset=(ssize_t) ((((
double) x+sample_offset.x)*image->columns)/
4039 sample_image->columns);
4040 y_offset=(ssize_t) ((((
double) y+sample_offset.y)*image->rows)/
4041 sample_image->rows);
4042 p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,1,1,exception);
4043 if (p == (
const Quantum *) NULL)
4048 for (i=0; i < (ssize_t) GetPixelChannels(sample_image); i++)
4057 channel=GetPixelChannelChannel(sample_image,i);
4058 traits=GetPixelChannelTraits(sample_image,channel);
4059 image_traits=GetPixelChannelTraits(image,channel);
4060 if ((traits == UndefinedPixelTrait) ||
4061 (image_traits == UndefinedPixelTrait))
4063 SetPixelChannel(sample_image,channel,p[i],q);
4065 q+=(ptrdiff_t) GetPixelChannels(sample_image);
4067 if (SyncCacheViewAuthenticPixels(sample_view,exception) == MagickFalse)
4069 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4074 proceed=SetImageProgress(image,SampleImageTag,progress++,image->rows);
4075 if (proceed == MagickFalse)
4079 image_view=DestroyCacheView(image_view);
4080 sample_view=DestroyCacheView(sample_view);
4081 sample_image->type=image->type;
4082 if (status == MagickFalse)
4083 sample_image=DestroyImage(sample_image);
4084 return(sample_image);
4116MagickExport Image *ScaleImage(
const Image *image,
const size_t columns,
4117 const size_t rows,ExceptionInfo *exception)
4119#define ScaleImageTag "Scale/Image"
4127 pixel[CompositePixelChannel],
4158 assert(image != (
const Image *) NULL);
4159 assert(image->signature == MagickCoreSignature);
4160 assert(exception != (ExceptionInfo *) NULL);
4161 assert(exception->signature == MagickCoreSignature);
4162 if (IsEventLogging() != MagickFalse)
4163 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4164 if ((columns == 0) || (rows == 0))
4165 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
4166 if ((columns == image->columns) && (rows == image->rows))
4167 return(CloneImage(image,0,0,MagickTrue,exception));
4168 scale_image=CloneImage(image,columns,rows,MagickTrue,exception);
4169 if (scale_image == (Image *) NULL)
4170 return((Image *) NULL);
4171 if (SetImageStorageClass(scale_image,DirectClass,exception) == MagickFalse)
4173 scale_image=DestroyImage(scale_image);
4174 return((Image *) NULL);
4179 x_vector=(
double *) AcquireQuantumMemory((
size_t) image->columns,
4180 MaxPixelChannels*
sizeof(*x_vector));
4182 if (image->rows != scale_image->rows)
4183 scanline=(
double *) AcquireQuantumMemory((
size_t) image->columns,
4184 MaxPixelChannels*
sizeof(*scanline));
4185 scale_scanline=(
double *) AcquireQuantumMemory((
size_t) scale_image->columns,
4186 MaxPixelChannels*
sizeof(*scale_scanline));
4187 y_vector=(
double *) AcquireQuantumMemory((
size_t) image->columns,
4188 MaxPixelChannels*
sizeof(*y_vector));
4189 if ((scanline == (
double *) NULL) || (scale_scanline == (
double *) NULL) ||
4190 (x_vector == (
double *) NULL) || (y_vector == (
double *) NULL))
4192 if ((image->rows != scale_image->rows) && (scanline != (
double *) NULL))
4193 scanline=(
double *) RelinquishMagickMemory(scanline);
4194 if (scale_scanline != (
double *) NULL)
4195 scale_scanline=(
double *) RelinquishMagickMemory(scale_scanline);
4196 if (x_vector != (
double *) NULL)
4197 x_vector=(
double *) RelinquishMagickMemory(x_vector);
4198 if (y_vector != (
double *) NULL)
4199 y_vector=(
double *) RelinquishMagickMemory(y_vector);
4200 scale_image=DestroyImage(scale_image);
4201 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
4207 next_row=MagickTrue;
4209 scale.y=(double) scale_image->rows/(
double) image->rows;
4210 (void) memset(y_vector,0,(
size_t) MaxPixelChannels*image->columns*
4214 image_view=AcquireVirtualCacheView(image,exception);
4215 scale_view=AcquireAuthenticCacheView(scale_image,exception);
4216 for (y=0; y < (ssize_t) scale_image->rows; y++)
4227 if (status == MagickFalse)
4229 q=QueueCacheViewAuthenticPixels(scale_view,0,y,scale_image->columns,1,
4231 if (q == (Quantum *) NULL)
4237 if (scale_image->rows == image->rows)
4242 p=GetCacheViewVirtualPixels(image_view,0,n++,image->columns,1,
4244 if (p == (
const Quantum *) NULL)
4249 for (x=0; x < (ssize_t) image->columns; x++)
4251 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
4253 p+=(ptrdiff_t) GetPixelChannels(image);
4256 if (image->alpha_trait != UndefinedPixelTrait)
4257 alpha=QuantumScale*(double) GetPixelAlpha(image,p);
4258 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4260 PixelChannel channel = GetPixelChannelChannel(image,i);
4261 PixelTrait traits = GetPixelChannelTraits(image,channel);
4262 if ((traits & BlendPixelTrait) == 0)
4264 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=(double) p[i];
4267 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=alpha*(double) p[i];
4269 p+=(ptrdiff_t) GetPixelChannels(image);
4277 while (scale.y < span.y)
4279 if ((next_row != MagickFalse) &&
4280 (number_rows < (ssize_t) image->rows))
4285 p=GetCacheViewVirtualPixels(image_view,0,n++,image->columns,1,
4287 if (p == (
const Quantum *) NULL)
4292 for (x=0; x < (ssize_t) image->columns; x++)
4294 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
4296 p+=(ptrdiff_t) GetPixelChannels(image);
4299 if (image->alpha_trait != UndefinedPixelTrait)
4300 alpha=QuantumScale*(double) GetPixelAlpha(image,p);
4301 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4303 PixelChannel channel = GetPixelChannelChannel(image,i);
4304 PixelTrait traits = GetPixelChannelTraits(image,channel);
4305 if ((traits & BlendPixelTrait) == 0)
4307 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=
4311 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=alpha*
4314 p+=(ptrdiff_t) GetPixelChannels(image);
4318 for (x=0; x < (ssize_t) image->columns; x++)
4319 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4320 y_vector[x*(ssize_t) GetPixelChannels(image)+i]+=scale.y*
4321 x_vector[x*(ssize_t) GetPixelChannels(image)+i];
4323 scale.y=(double) scale_image->rows/(
double) image->rows;
4324 next_row=MagickTrue;
4326 if ((next_row != MagickFalse) && (number_rows < (ssize_t) image->rows))
4331 p=GetCacheViewVirtualPixels(image_view,0,n++,image->columns,1,
4333 if (p == (
const Quantum *) NULL)
4338 for (x=0; x < (ssize_t) image->columns; x++)
4340 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
4342 p+=(ptrdiff_t) GetPixelChannels(image);
4345 if (image->alpha_trait != UndefinedPixelTrait)
4346 alpha=QuantumScale*(double) GetPixelAlpha(image,p);
4347 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4349 PixelChannel channel = GetPixelChannelChannel(image,i);
4350 PixelTrait traits = GetPixelChannelTraits(image,channel);
4351 if ((traits & BlendPixelTrait) == 0)
4353 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=
4357 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=alpha*
4360 p+=(ptrdiff_t) GetPixelChannels(image);
4363 next_row=MagickFalse;
4365 for (x=0; x < (ssize_t) image->columns; x++)
4367 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4369 pixel[i]=y_vector[x*(ssize_t) GetPixelChannels(image)+i]+span.y*
4370 x_vector[x*(ssize_t) GetPixelChannels(image)+i];
4371 scanline[x*(ssize_t) GetPixelChannels(image)+i]=pixel[i];
4372 y_vector[x*(ssize_t) GetPixelChannels(image)+i]=0.0;
4378 scale.y=(double) scale_image->rows/(
double) image->rows;
4379 next_row=MagickTrue;
4383 if (scale_image->columns == image->columns)
4388 for (x=0; x < (ssize_t) scale_image->columns; x++)
4390 if (GetPixelWriteMask(scale_image,q) <= (QuantumRange/2))
4392 q+=(ptrdiff_t) GetPixelChannels(scale_image);
4395 if (image->alpha_trait != UndefinedPixelTrait)
4397 alpha=QuantumScale*scanline[x*(ssize_t) GetPixelChannels(image)+
4398 GetPixelChannelOffset(image,AlphaPixelChannel)];
4399 alpha=MagickSafeReciprocal(alpha);
4401 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4403 PixelChannel channel = GetPixelChannelChannel(image,i);
4404 PixelTrait traits = GetPixelChannelTraits(image,channel);
4405 scale_traits=GetPixelChannelTraits(scale_image,channel);
4406 if ((traits == UndefinedPixelTrait) ||
4407 (scale_traits == UndefinedPixelTrait))
4409 if ((traits & BlendPixelTrait) == 0)
4411 SetPixelChannel(scale_image,channel,ClampToQuantum(
4412 scanline[x*(ssize_t) GetPixelChannels(image)+i]),q);
4415 SetPixelChannel(scale_image,channel,ClampToQuantum(alpha*scanline[
4416 x*(ssize_t) GetPixelChannels(image)+i]),q);
4418 q+=(ptrdiff_t) GetPixelChannels(scale_image);
4429 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4431 next_column=MagickFalse;
4434 for (x=0; x < (ssize_t) image->columns; x++)
4436 scale.x=(double) scale_image->columns/(
double) image->columns;
4437 while (scale.x >= span.x)
4439 if (next_column != MagickFalse)
4441 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4445 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4447 PixelChannel channel = GetPixelChannelChannel(image,i);
4448 PixelTrait traits = GetPixelChannelTraits(image,channel);
4449 if (traits == UndefinedPixelTrait)
4451 pixel[i]+=span.x*scanline[x*(ssize_t) GetPixelChannels(image)+i];
4452 scale_scanline[t*(ssize_t) GetPixelChannels(image)+i]=pixel[i];
4456 next_column=MagickTrue;
4460 if (next_column != MagickFalse)
4462 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4464 next_column=MagickFalse;
4467 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4468 pixel[i]+=scale.x*scanline[x*(ssize_t)
4469 GetPixelChannels(image)+i];
4475 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4477 scanline[(x-1)*(ssize_t) GetPixelChannels(image)+i];
4479 if ((next_column == MagickFalse) && (t < (ssize_t) scale_image->columns))
4480 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4481 scale_scanline[t*(ssize_t) GetPixelChannels(image)+i]=pixel[i];
4485 for (x=0; x < (ssize_t) scale_image->columns; x++)
4487 if (GetPixelWriteMask(scale_image,q) <= (QuantumRange/2))
4489 q+=(ptrdiff_t) GetPixelChannels(scale_image);
4492 if (image->alpha_trait != UndefinedPixelTrait)
4494 alpha=QuantumScale*scale_scanline[x*(ssize_t)
4495 GetPixelChannels(image)+
4496 GetPixelChannelOffset(image,AlphaPixelChannel)];
4497 alpha=MagickSafeReciprocal(alpha);
4499 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4501 PixelChannel channel = GetPixelChannelChannel(image,i);
4502 PixelTrait traits = GetPixelChannelTraits(image,channel);
4503 scale_traits=GetPixelChannelTraits(scale_image,channel);
4504 if ((traits == UndefinedPixelTrait) ||
4505 (scale_traits == UndefinedPixelTrait))
4507 if ((traits & BlendPixelTrait) == 0)
4509 SetPixelChannel(scale_image,channel,ClampToQuantum(
4510 scale_scanline[x*(ssize_t) GetPixelChannels(image)+i]),q);
4513 SetPixelChannel(scale_image,channel,ClampToQuantum(alpha*
4514 scale_scanline[x*(ssize_t) GetPixelChannels(image)+i]),q);
4516 q+=(ptrdiff_t) GetPixelChannels(scale_image);
4519 if (SyncCacheViewAuthenticPixels(scale_view,exception) == MagickFalse)
4524 proceed=SetImageProgress(image,ScaleImageTag,(MagickOffsetType) y,
4526 if (proceed == MagickFalse)
4532 scale_view=DestroyCacheView(scale_view);
4533 image_view=DestroyCacheView(image_view);
4537 y_vector=(
double *) RelinquishMagickMemory(y_vector);
4538 scale_scanline=(
double *) RelinquishMagickMemory(scale_scanline);
4539 if (scale_image->rows != image->rows)
4540 scanline=(
double *) RelinquishMagickMemory(scanline);
4541 x_vector=(
double *) RelinquishMagickMemory(x_vector);
4542 scale_image->type=image->type;
4543 if (status == MagickFalse)
4544 scale_image=DestroyImage(scale_image);
4545 return(scale_image);
4580static void url_encode(
const char *uri,
char *encode_uri)
4586 *hex =
"0123456789ABCDEF";
4588 for (p=encode_uri; *uri !=
'\0'; uri++)
4589 if (((
'a' <= *uri) && (*uri <=
'z')) || ((
'A' <= *uri) && (*uri <=
'Z')) ||
4590 ((
'0' <= *uri) && (*uri <=
'9')) || (strchr(
"/-_.~",*uri) != 0))
4595 *p++=hex[(*uri >> 4) & 0xF];
4596 *p++=hex[*uri & 0xF];
4601MagickExport Image *ThumbnailImage(
const Image *image,
const size_t columns,
4602 const size_t rows,ExceptionInfo *exception)
4604#define SampleFactor 5
4607 encode_uri[3*MagickPathExtent+1] =
"/0";
4619 assert(image != (Image *) NULL);
4620 assert(image->signature == MagickCoreSignature);
4621 assert(exception != (ExceptionInfo *) NULL);
4622 assert(exception->signature == MagickCoreSignature);
4623 if (IsEventLogging() != MagickFalse)
4624 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4625 thumbnail_image=CloneImage(image,0,0,MagickTrue,exception);
4626 if (thumbnail_image == (Image *) NULL)
4627 return(thumbnail_image);
4628 if ((columns != image->columns) || (rows != image->rows))
4631 *clone_image = thumbnail_image;
4637 x_factor=(ssize_t) (image->columns*MagickSafeReciprocal((
double)
4639 y_factor=(ssize_t) (image->rows*MagickSafeReciprocal((
double) rows));
4640 if ((x_factor > 4) && (y_factor > 4))
4642 thumbnail_image=SampleImage(clone_image,4*columns,4*rows,exception);
4643 if (thumbnail_image != (Image *) NULL)
4645 clone_image=DestroyImage(clone_image);
4646 clone_image=thumbnail_image;
4649 if ((x_factor > 2) && (y_factor > 2))
4651 thumbnail_image=ResizeImage(clone_image,2*columns,2*rows,BoxFilter,
4653 if (thumbnail_image != (Image *) NULL)
4655 clone_image=DestroyImage(clone_image);
4656 clone_image=thumbnail_image;
4659 thumbnail_image=ResizeImage(clone_image,columns,rows,image->filter ==
4660 UndefinedFilter ? LanczosSharpFilter : image->filter,exception);
4661 clone_image=DestroyImage(clone_image);
4662 if (thumbnail_image == (Image *) NULL)
4663 return(thumbnail_image);
4665 (void) ParseAbsoluteGeometry(
"0x0+0+0",&thumbnail_image->page);
4666 thumbnail_image->depth=8;
4667 thumbnail_image->interlace=NoInterlace;
4671 ResetImageProfileIterator(thumbnail_image);
4672 for (name=GetNextImageProfile(thumbnail_image); name != (
const char *) NULL; )
4674 if ((LocaleCompare(name,
"icc") != 0) && (LocaleCompare(name,
"icm") != 0))
4676 (void) DeleteImageProfile(thumbnail_image,name);
4677 ResetImageProfileIterator(thumbnail_image);
4679 name=GetNextImageProfile(thumbnail_image);
4681 (void) DeleteImageProperty(thumbnail_image,
"comment");
4682 url_encode(image->filename,encode_uri);
4683 if (*image->filename !=
'/')
4684 (void) FormatImageProperty(thumbnail_image,
"Thumb::URI",
"./%s",encode_uri);
4686 (
void) FormatImageProperty(thumbnail_image,
"Thumb::URI",
"file://%s",
4688 if (GetPathAttributes(image->filename,&attributes) != MagickFalse )
4689 (void) FormatImageProperty(thumbnail_image,
"Thumb::MTime",
"%.17g",(
double)
4690 attributes.st_mtime);
4691 (void) FormatImageProperty(thumbnail_image,
"Thumb::Size",
"%.17g",
4692 (
double) GetBlobSize(image));
4693 mime_type=GetImageProperty(image,
"mime:type",exception);
4694 if (mime_type != (
const char *) NULL)
4695 (void) SetImageProperty(thumbnail_image,
"Thumb::Mimetype",mime_type,
4697 (void) SetImageProperty(thumbnail_image,
"software",MagickAuthoritativeURL,
4699 (void) FormatImageProperty(thumbnail_image,
"Thumb::Image::Width",
"%.17g",
4700 (
double) image->magick_columns);
4701 (void) FormatImageProperty(thumbnail_image,
"Thumb::Image::Height",
"%.17g",
4702 (
double) image->magick_rows);
4703 (void) FormatImageProperty(thumbnail_image,
"Thumb::Document::Pages",
"%.17g",
4704 (
double) GetImageListLength(image));
4705 return(thumbnail_image);