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/quantum-private.h"
72#include "MagickCore/resample.h"
73#include "MagickCore/resample-private.h"
74#include "MagickCore/resize.h"
75#include "MagickCore/resize-private.h"
76#include "MagickCore/resource_.h"
77#include "MagickCore/string_.h"
78#include "MagickCore/string-private.h"
79#include "MagickCore/thread-private.h"
80#include "MagickCore/token.h"
81#include "MagickCore/utility.h"
82#include "MagickCore/utility-private.h"
83#include "MagickCore/version.h"
84#if defined(MAGICKCORE_LQR_DELEGATE)
94 (*filter)(
const double,
const ResizeFilter *),
95 (*window)(
const double,
const ResizeFilter *),
102 ResizeWeightingFunctionType
115 BesselOrderOne(
double),
116 Sinc(
const double,
const ResizeFilter *),
117 SincFast(
const double,
const ResizeFilter *);
151static double Blackman(
const double x,
152 const ResizeFilter *magick_unused(resize_filter))
161 const double cosine = cos((
double) (MagickPI*x));
162 magick_unreferenced(resize_filter);
163 return(0.34+cosine*(0.5+cosine*0.16));
166static double Bohman(
const double x,
167 const ResizeFilter *magick_unused(resize_filter))
177 const double cosine = cos((
double) (MagickPI*x));
178 const double sine=sqrt(1.0-cosine*cosine);
179 magick_unreferenced(resize_filter);
180 return((1.0-x)*cosine+(1.0/MagickPI)*sine);
183static double Box(
const double magick_unused(x),
184 const ResizeFilter *magick_unused(resize_filter))
186 magick_unreferenced(x);
187 magick_unreferenced(resize_filter);
197static double Cosine(
const double x,
198 const ResizeFilter *magick_unused(resize_filter))
200 magick_unreferenced(resize_filter);
206 return(cos((
double) (MagickPI2*x)));
209static double CubicBC(
const double x,
const ResizeFilter *resize_filter)
241 return(resize_filter->coefficient[0]+x*(x*
242 (resize_filter->coefficient[1]+x*resize_filter->coefficient[2])));
244 return(resize_filter->coefficient[3]+x*(resize_filter->coefficient[4]+x*
245 (resize_filter->coefficient[5]+x*resize_filter->coefficient[6])));
249static double CubicSpline(
const double x,
const ResizeFilter *resize_filter)
251 if (resize_filter->support <= 2.0)
257 return(((x-9.0/5.0)*x-1.0/5.0)*x+1.0);
259 return(((-1.0/3.0*(x-1.0)+4.0/5.0)*(x-1.0)-7.0/15.0)*(x-1.0));
262 if (resize_filter->support <= 3.0)
268 return(((13.0/11.0*x-453.0/209.0)*x-3.0/209.0)*x+1.0);
270 return(((-6.0/11.0*(x-1.0)+270.0/209.0)*(x-1.0)-156.0/209.0)*(x-1.0));
272 return(((1.0/11.0*(x-2.0)-45.0/209.0)*(x-2.0)+26.0/209.0)*(x-2.0));
279 return(((49.0/41.0*x-6387.0/2911.0)*x-3.0/2911.0)*x+1.0);
281 return(((-24.0/41.0*(x-1.0)+4032.0/2911.0)*(x-1.0)-2328.0/2911.0)*(x-1.0));
283 return(((6.0/41.0*(x-2.0)-1008.0/2911.0)*(x-2.0)+582.0/2911.0)*(x-2.0));
285 return(((-1.0/41.0*(x-3.0)+168.0/2911.0)*(x-3.0)-97.0/2911.0)*(x-3.0));
289static double Gaussian(
const double x,
const ResizeFilter *resize_filter)
321 return(exp((
double)(-resize_filter->coefficient[1]*x*x)));
324static double Hann(
const double x,
325 const ResizeFilter *magick_unused(resize_filter))
331 const double cosine = cos((
double) (MagickPI*x));
332 magick_unreferenced(resize_filter);
333 return(0.5+0.5*cosine);
336static double Hamming(
const double x,
337 const ResizeFilter *magick_unused(resize_filter))
343 const double cosine = cos((
double) (MagickPI*x));
344 magick_unreferenced(resize_filter);
345 return(0.54+0.46*cosine);
348static double Jinc(
const double x,
349 const ResizeFilter *magick_unused(resize_filter))
351 magick_unreferenced(resize_filter);
362 return(0.5*MagickPI);
363 return(BesselOrderOne(MagickPI*x)/x);
366static double Kaiser(
const double x,
const ResizeFilter *resize_filter)
380 return(resize_filter->coefficient[1]*I0(resize_filter->coefficient[0]*
381 sqrt((
double) (1.0-x*x))));
384static double Lagrange(
const double x,
const ResizeFilter *resize_filter)
406 if (x > resize_filter->support)
408 order=(ssize_t) (2.0*resize_filter->window_support);
409 n=(ssize_t) (resize_filter->window_support+x);
411 for (i=0; i < order; i++)
413 value*=(n-i-x)/(n-i);
417static double MagicKernelSharp2013(
const double x,
418 const ResizeFilter *magick_unused(resize_filter))
420 magick_unreferenced(resize_filter);
429 return(0.625+1.75*(0.5-x)*(0.5+x));
431 return((1.0-x)*(1.75-x));
433 return(-0.125*(2.5-x)*(2.5-x));
437static double MagicKernelSharp2021(
const double x,
438 const ResizeFilter *magick_unused(resize_filter))
440 magick_unreferenced(resize_filter);
449 return(577.0/576.0-239.0/144.0*x*x);
451 return(35.0/36.0*(x-1.0)*(x-239.0/140.0));
453 return(1.0/6.0*(x-2.0)*(65.0/24.0-x));
455 return(1.0/36.0*(x-3.0)*(x-3.75));
457 return(-1.0/288.0*(x-4.5)*(x-4.5));
461static double Quadratic(
const double x,
462 const ResizeFilter *magick_unused(resize_filter))
464 magick_unreferenced(resize_filter);
472 return(0.5*(x-1.5)*(x-1.5));
476static double Sinc(
const double x,
477 const ResizeFilter *magick_unused(resize_filter))
479 magick_unreferenced(resize_filter);
487 const double alpha=(double) (MagickPI*x);
488 return(sin((
double) alpha)/alpha);
490 return((
double) 1.0);
493static double SincFast(
const double x,
494 const ResizeFilter *magick_unused(resize_filter))
496 magick_unreferenced(resize_filter);
524 const double alpha=(double) (MagickPI*x);
525 return(sin((
double) alpha)/alpha);
531 const double xx = x*x;
532#if MAGICKCORE_QUANTUM_DEPTH <= 8
536 const double c0 = 0.173610016489197553621906385078711564924e-2L;
537 const double c1 = -0.384186115075660162081071290162149315834e-3L;
538 const double c2 = 0.393684603287860108352720146121813443561e-4L;
539 const double c3 = -0.248947210682259168029030370205389323899e-5L;
540 const double c4 = 0.107791837839662283066379987646635416692e-6L;
541 const double c5 = -0.324874073895735800961260474028013982211e-8L;
542 const double c6 = 0.628155216606695311524920882748052490116e-10L;
543 const double c7 = -0.586110644039348333520104379959307242711e-12L;
545 c0+xx*(c1+xx*(c2+xx*(c3+xx*(c4+xx*(c5+xx*(c6+xx*c7))))));
546 return((xx-1.0)*(xx-4.0)*(xx-9.0)*(xx-16.0)*p);
547#elif MAGICKCORE_QUANTUM_DEPTH <= 16
551 const double c0 = 0.173611107357320220183368594093166520811e-2L;
552 const double c1 = -0.384240921114946632192116762889211361285e-3L;
553 const double c2 = 0.394201182359318128221229891724947048771e-4L;
554 const double c3 = -0.250963301609117217660068889165550534856e-5L;
555 const double c4 = 0.111902032818095784414237782071368805120e-6L;
556 const double c5 = -0.372895101408779549368465614321137048875e-8L;
557 const double c6 = 0.957694196677572570319816780188718518330e-10L;
558 const double c7 = -0.187208577776590710853865174371617338991e-11L;
559 const double c8 = 0.253524321426864752676094495396308636823e-13L;
560 const double c9 = -0.177084805010701112639035485248501049364e-15L;
562 c0+xx*(c1+xx*(c2+xx*(c3+xx*(c4+xx*(c5+xx*(c6+xx*(c7+xx*(c8+xx*c9))))))));
563 return((xx-1.0)*(xx-4.0)*(xx-9.0)*(xx-16.0)*p);
568 const double c0 = 0.173611111110910715186413700076827593074e-2L;
569 const double c1 = -0.289105544717893415815859968653611245425e-3L;
570 const double c2 = 0.206952161241815727624413291940849294025e-4L;
571 const double c3 = -0.834446180169727178193268528095341741698e-6L;
572 const double c4 = 0.207010104171026718629622453275917944941e-7L;
573 const double c5 = -0.319724784938507108101517564300855542655e-9L;
574 const double c6 = 0.288101675249103266147006509214934493930e-11L;
575 const double c7 = -0.118218971804934245819960233886876537953e-13L;
577 c0+xx*(c1+xx*(c2+xx*(c3+xx*(c4+xx*(c5+xx*(c6+xx*c7))))));
578 const double d0 = 1.0L;
579 const double d1 = 0.547981619622284827495856984100563583948e-1L;
580 const double d2 = 0.134226268835357312626304688047086921806e-2L;
581 const double d3 = 0.178994697503371051002463656833597608689e-4L;
582 const double d4 = 0.114633394140438168641246022557689759090e-6L;
583 const double q = d0+xx*(d1+xx*(d2+xx*(d3+xx*d4)));
584 return((xx-1.0)*(xx-4.0)*(xx-9.0)*(xx-16.0)/q*p);
589static double Triangle(
const double x,
590 const ResizeFilter *magick_unused(resize_filter))
592 magick_unreferenced(resize_filter);
604static double Welch(
const double x,
605 const ResizeFilter *magick_unused(resize_filter))
607 magick_unreferenced(resize_filter);
803MagickPrivate ResizeFilter *AcquireResizeFilter(
const Image *image,
804 const FilterType filter,
const MagickBooleanType cylindrical,
805 ExceptionInfo *exception)
840 }
const mapping[SentinelFilter] =
842 { UndefinedFilter, BoxFilter },
843 { PointFilter, BoxFilter },
844 { BoxFilter, BoxFilter },
845 { TriangleFilter, BoxFilter },
846 { HermiteFilter, BoxFilter },
847 { SincFastFilter, HannFilter },
848 { SincFastFilter, HammingFilter },
849 { SincFastFilter, BlackmanFilter },
850 { GaussianFilter, BoxFilter },
851 { QuadraticFilter, BoxFilter },
852 { CubicFilter, BoxFilter },
853 { CatromFilter, BoxFilter },
854 { MitchellFilter, BoxFilter },
855 { JincFilter, BoxFilter },
856 { SincFilter, BoxFilter },
857 { SincFastFilter, BoxFilter },
858 { SincFastFilter, KaiserFilter },
859 { LanczosFilter, WelchFilter },
860 { SincFastFilter, CubicFilter },
861 { SincFastFilter, BohmanFilter },
862 { SincFastFilter, TriangleFilter },
863 { LagrangeFilter, BoxFilter },
864 { LanczosFilter, LanczosFilter },
865 { LanczosSharpFilter, LanczosSharpFilter },
866 { Lanczos2Filter, Lanczos2Filter },
867 { Lanczos2SharpFilter, Lanczos2SharpFilter },
868 { RobidouxFilter, BoxFilter },
869 { RobidouxSharpFilter, BoxFilter },
870 { LanczosFilter, CosineFilter },
871 { SplineFilter, BoxFilter },
872 { LanczosRadiusFilter, LanczosFilter },
873 { CubicSplineFilter, BoxFilter },
874 { MagicKernelSharp2013Filter, BoxFilter },
875 { MagicKernelSharp2021Filter, BoxFilter },
891 (*function)(
const double,
const ResizeFilter*),
896 ResizeWeightingFunctionType weightingFunctionType;
897 }
const filters[SentinelFilter] =
904 { Box, 0.5, 0.5, 0.0, 0.0, BoxWeightingFunction },
905 { Box, 0.0, 0.5, 0.0, 0.0, BoxWeightingFunction },
906 { Box, 0.5, 0.5, 0.0, 0.0, BoxWeightingFunction },
907 { Triangle, 1.0, 1.0, 0.0, 0.0, TriangleWeightingFunction },
908 { CubicBC, 1.0, 1.0, 0.0, 0.0, CubicBCWeightingFunction },
909 { Hann, 1.0, 1.0, 0.0, 0.0, HannWeightingFunction },
910 { Hamming, 1.0, 1.0, 0.0, 0.0, HammingWeightingFunction },
911 { Blackman, 1.0, 1.0, 0.0, 0.0, BlackmanWeightingFunction },
912 { Gaussian, 2.0, 1.5, 0.0, 0.0, GaussianWeightingFunction },
913 { Quadratic, 1.5, 1.5, 0.0, 0.0, QuadraticWeightingFunction },
914 { CubicBC, 2.0, 2.0, 1.0, 0.0, CubicBCWeightingFunction },
915 { CubicBC, 2.0, 1.0, 0.0, 0.5, CubicBCWeightingFunction },
916 { CubicBC, 2.0, 8.0/7.0, 1./3., 1./3., CubicBCWeightingFunction },
917 { Jinc, 3.0, 1.2196698912665045, 0.0, 0.0, JincWeightingFunction },
918 { Sinc, 4.0, 1.0, 0.0, 0.0, SincWeightingFunction },
919 { SincFast, 4.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
920 { Kaiser, 1.0, 1.0, 0.0, 0.0, KaiserWeightingFunction },
921 { Welch, 1.0, 1.0, 0.0, 0.0, WelchWeightingFunction },
922 { CubicBC, 2.0, 2.0, 1.0, 0.0, CubicBCWeightingFunction },
923 { Bohman, 1.0, 1.0, 0.0, 0.0, BohmanWeightingFunction },
924 { Triangle, 1.0, 1.0, 0.0, 0.0, TriangleWeightingFunction },
925 { Lagrange, 2.0, 1.0, 0.0, 0.0, LagrangeWeightingFunction },
926 { SincFast, 3.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
927 { SincFast, 3.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
928 { SincFast, 2.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
929 { SincFast, 2.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
931 { CubicBC, 2.0, 1.1685777620836932,
932 0.37821575509399867, 0.31089212245300067, CubicBCWeightingFunction },
934 { CubicBC, 2.0, 1.105822933719019,
935 0.2620145123990142, 0.3689927438004929, CubicBCWeightingFunction },
936 { Cosine, 1.0, 1.0, 0.0, 0.0, CosineWeightingFunction },
937 { CubicBC, 2.0, 2.0, 1.0, 0.0, CubicBCWeightingFunction },
938 { SincFast, 3.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
939 { CubicSpline,2.0, 0.5, 0.0, 0.0, BoxWeightingFunction },
940 { MagicKernelSharp2013, 2.5, 1.0, 0.0, 0.0, MagicKernelSharpWeightingFunction },
941 { MagicKernelSharp2021, 4.5, 1.0, 0.0, 0.0, MagicKernelSharpWeightingFunction },
978 assert(image != (
const Image *) NULL);
979 assert(image->signature == MagickCoreSignature);
980 assert(UndefinedFilter < filter && filter < SentinelFilter);
981 assert(exception != (ExceptionInfo *) NULL);
982 assert(exception->signature == MagickCoreSignature);
983 if (IsEventLogging() != MagickFalse)
984 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
986 resize_filter=(ResizeFilter *) AcquireCriticalMemory(
sizeof(*resize_filter));
987 (void) memset(resize_filter,0,
sizeof(*resize_filter));
991 filter_type=mapping[filter].filter;
992 window_type=mapping[filter].window;
993 resize_filter->blur=1.0;
995 if ((cylindrical != MagickFalse) && (filter_type == SincFastFilter) &&
996 (filter != SincFastFilter))
997 filter_type=JincFilter;
1000 artifact=GetImageArtifact(image,
"filter:filter");
1001 if (IsStringTrue(artifact) != MagickFalse)
1006 option=ParseCommandOption(MagickFilterOptions,MagickFalse,artifact);
1007 if ((UndefinedFilter < option) && (option < SentinelFilter))
1009 filter_type=(FilterType) option;
1010 window_type=BoxFilter;
1013 artifact=GetImageArtifact(image,
"filter:window");
1014 if (artifact != (
const char *) NULL)
1016 option=ParseCommandOption(MagickFilterOptions,MagickFalse,artifact);
1017 if ((UndefinedFilter < option) && (option < SentinelFilter))
1018 window_type=(FilterType) option;
1024 artifact=GetImageArtifact(image,
"filter:window");
1025 if (artifact != (
const char *) NULL)
1030 option=ParseCommandOption(MagickFilterOptions,MagickFalse,artifact);
1031 if ((UndefinedFilter < option) && (option < SentinelFilter))
1033 filter_type= cylindrical != MagickFalse ? JincFilter
1035 window_type=(FilterType) option;
1041 resize_filter->filter=filters[filter_type].function;
1042 resize_filter->support=filters[filter_type].support;
1043 resize_filter->filterWeightingType=filters[filter_type].weightingFunctionType;
1044 resize_filter->window=filters[window_type].function;
1045 resize_filter->windowWeightingType=filters[window_type].weightingFunctionType;
1046 resize_filter->scale=filters[window_type].scale;
1047 resize_filter->signature=MagickCoreSignature;
1050 if (cylindrical != MagickFalse)
1051 switch (filter_type)
1055 resize_filter->support=(double) MagickSQ1_2;
1058 case LanczosSharpFilter:
1059 case Lanczos2Filter:
1060 case Lanczos2SharpFilter:
1061 case LanczosRadiusFilter:
1062 resize_filter->filter=filters[JincFilter].function;
1063 resize_filter->window=filters[JincFilter].function;
1064 resize_filter->scale=filters[JincFilter].scale;
1071 switch (filter_type)
1073 case LanczosSharpFilter:
1074 resize_filter->blur *= 0.9812505644269356;
1076 case Lanczos2SharpFilter:
1077 resize_filter->blur *= 0.9549963639785485;
1089 if ((resize_filter->filter == Gaussian) ||
1090 (resize_filter->window == Gaussian) ) {
1092 artifact=GetImageArtifact(image,
"filter:sigma");
1093 if (artifact != (
const char *) NULL)
1094 value=StringToDouble(artifact,(
char **) NULL);
1096 resize_filter->coefficient[0]=value;
1097 resize_filter->coefficient[1]=MagickSafeReciprocal(2.0*value*value);
1098 resize_filter->coefficient[2]=MagickSafeReciprocal(Magick2PI*value*value);
1101 resize_filter->support *= 2*value;
1105 if ((resize_filter->filter == Kaiser) ||
1106 (resize_filter->window == Kaiser) ) {
1108 artifact=GetImageArtifact(image,
"filter:alpha");
1109 if (artifact != (
const char *) NULL)
1110 value=StringToDouble(artifact,(
char **) NULL);
1111 artifact=GetImageArtifact(image,
"filter:kaiser-beta");
1112 if (artifact != (
const char *) NULL)
1113 value=StringToDouble(artifact,(
char **) NULL);
1114 artifact=GetImageArtifact(image,
"filter:kaiser-alpha");
1115 if (artifact != (
const char *) NULL)
1116 value=StringToDouble(artifact,(
char **) NULL)*MagickPI;
1118 resize_filter->coefficient[0]=value;
1119 resize_filter->coefficient[1]=MagickSafeReciprocal(I0(value));
1124 artifact=GetImageArtifact(image,
"filter:lobes");
1125 if (artifact != (
const char *) NULL)
1130 lobes=(ssize_t) StringToLong(artifact);
1133 resize_filter->support=(double) lobes;
1135 if (resize_filter->filter == Jinc)
1140 if (resize_filter->support > 16)
1141 resize_filter->support=jinc_zeros[15];
1143 resize_filter->support=jinc_zeros[((long) resize_filter->support)-1];
1147 if (filter_type == LanczosRadiusFilter)
1148 resize_filter->blur*=floor(resize_filter->support)/
1149 resize_filter->support;
1154 artifact=GetImageArtifact(image,
"filter:blur");
1155 if (artifact != (
const char *) NULL)
1156 resize_filter->blur*=StringToDouble(artifact,(
char **) NULL);
1157 if (resize_filter->blur < MagickEpsilon)
1158 resize_filter->blur=(double) MagickEpsilon;
1162 artifact=GetImageArtifact(image,
"filter:support");
1163 if (artifact != (
const char *) NULL)
1164 resize_filter->support=fabs(StringToDouble(artifact,(
char **) NULL));
1169 resize_filter->window_support=resize_filter->support;
1170 artifact=GetImageArtifact(image,
"filter:win-support");
1171 if (artifact != (
const char *) NULL)
1172 resize_filter->window_support=fabs(StringToDouble(artifact,(
char **) NULL));
1177 resize_filter->scale*=MagickSafeReciprocal(resize_filter->window_support);
1183 if ((resize_filter->filter == CubicBC) ||
1184 (resize_filter->window == CubicBC) )
1186 B=filters[filter_type].B;
1187 C=filters[filter_type].C;
1188 if (filters[window_type].function == CubicBC)
1190 B=filters[window_type].B;
1191 C=filters[window_type].C;
1193 artifact=GetImageArtifact(image,
"filter:b");
1194 if (artifact != (
const char *) NULL)
1196 B=StringToDouble(artifact,(
char **) NULL);
1198 artifact=GetImageArtifact(image,
"filter:c");
1199 if (artifact != (
const char *) NULL)
1200 C=StringToDouble(artifact,(
char **) NULL);
1204 artifact=GetImageArtifact(image,
"filter:c");
1205 if (artifact != (
const char *) NULL)
1207 C=StringToDouble(artifact,(
char **) NULL);
1218 resize_filter->coefficient[0]=1.0-(1.0/3.0)*B;
1219 resize_filter->coefficient[1]=-3.0+twoB+C;
1220 resize_filter->coefficient[2]=2.0-1.5*B-C;
1221 resize_filter->coefficient[3]=(4.0/3.0)*B+4.0*C;
1222 resize_filter->coefficient[4]=-8.0*C-twoB;
1223 resize_filter->coefficient[5]=B+5.0*C;
1224 resize_filter->coefficient[6]=(-1.0/6.0)*B-C;
1231 if (IsStringTrue(GetImageArtifact(image,
"filter:verbose")) != MagickFalse)
1232#if defined(MAGICKCORE_OPENMP_SUPPORT)
1246 if (resize_filter->filter == Box) filter_type=BoxFilter;
1247 if (resize_filter->filter == Sinc) filter_type=SincFilter;
1248 if (resize_filter->filter == SincFast) filter_type=SincFastFilter;
1249 if (resize_filter->filter == Jinc) filter_type=JincFilter;
1250 if (resize_filter->filter == CubicBC) filter_type=CubicFilter;
1251 if (resize_filter->window == Box) window_type=BoxFilter;
1252 if (resize_filter->window == Sinc) window_type=SincFilter;
1253 if (resize_filter->window == SincFast) window_type=SincFastFilter;
1254 if (resize_filter->window == Jinc) window_type=JincFilter;
1255 if (resize_filter->window == CubicBC) window_type=CubicFilter;
1259 support=GetResizeFilterSupport(resize_filter);
1260 (void) FormatLocaleFile(stdout,
"# Resampling Filter (for graphing)\n#\n");
1261 (void) FormatLocaleFile(stdout,
"# filter = %s\n",
1262 CommandOptionToMnemonic(MagickFilterOptions,filter_type));
1263 (void) FormatLocaleFile(stdout,
"# window = %s\n",
1264 CommandOptionToMnemonic(MagickFilterOptions,window_type));
1265 (void) FormatLocaleFile(stdout,
"# support = %.*g\n",
1266 GetMagickPrecision(),(
double) resize_filter->support);
1267 (void) FormatLocaleFile(stdout,
"# window-support = %.*g\n",
1268 GetMagickPrecision(),(
double) resize_filter->window_support);
1269 (void) FormatLocaleFile(stdout,
"# scale-blur = %.*g\n",
1270 GetMagickPrecision(),(
double) resize_filter->blur);
1271 if ((filter_type == GaussianFilter) || (window_type == GaussianFilter))
1272 (void) FormatLocaleFile(stdout,
"# gaussian-sigma = %.*g\n",
1273 GetMagickPrecision(),(
double) resize_filter->coefficient[0]);
1274 if ((filter_type == KaiserFilter) || (window_type == KaiserFilter))
1275 (void) FormatLocaleFile(stdout,
"# kaiser-beta = %.*g\n",
1276 GetMagickPrecision(),(
double) resize_filter->coefficient[0]);
1277 (void) FormatLocaleFile(stdout,
"# practical-support = %.*g\n",
1278 GetMagickPrecision(), (
double) support);
1279 if ((filter_type == CubicFilter) || (window_type == CubicFilter))
1280 (void) FormatLocaleFile(stdout,
"# B,C = %.*g,%.*g\n",
1281 GetMagickPrecision(),(
double) B,GetMagickPrecision(),(
double) C);
1282 (void) FormatLocaleFile(stdout,
"\n");
1286 for (x=0.0; x <= support; x+=0.01)
1287 (
void) FormatLocaleFile(stdout,
"%5.2lf\t%.*g\n",x,GetMagickPrecision(),
1288 (
double) GetResizeFilterWeight(resize_filter,x));
1292 (void) FormatLocaleFile(stdout,
"%5.2lf\t%.*g\n",support,
1293 GetMagickPrecision(),0.0);
1295 (void) DeleteImageArtifact((Image *) image,
"filter:verbose");
1297 return(resize_filter);
1334MagickExport Image *AdaptiveResizeImage(
const Image *image,
1335 const size_t columns,
const size_t rows,ExceptionInfo *exception)
1340 resize_image=InterpolativeResizeImage(image,columns,rows,MeshInterpolatePixel,
1342 return(resize_image);
1385static double I0(
double x)
1401 for (i=2; t > MagickEpsilon; i++)
1404 t*=y/((double) i*i);
1410static double J1(
double x)
1422 0.581199354001606143928050809e+21,
1423 -0.6672106568924916298020941484e+20,
1424 0.2316433580634002297931815435e+19,
1425 -0.3588817569910106050743641413e+17,
1426 0.2908795263834775409737601689e+15,
1427 -0.1322983480332126453125473247e+13,
1428 0.3413234182301700539091292655e+10,
1429 -0.4695753530642995859767162166e+7,
1430 0.270112271089232341485679099e+4
1434 0.11623987080032122878585294e+22,
1435 0.1185770712190320999837113348e+20,
1436 0.6092061398917521746105196863e+17,
1437 0.2081661221307607351240184229e+15,
1438 0.5243710262167649715406728642e+12,
1439 0.1013863514358673989967045588e+10,
1440 0.1501793594998585505921097578e+7,
1441 0.1606931573481487801970916749e+4,
1447 for (i=7; i >= 0; i--)
1456static double P1(
double x)
1468 0.352246649133679798341724373e+5,
1469 0.62758845247161281269005675e+5,
1470 0.313539631109159574238669888e+5,
1471 0.49854832060594338434500455e+4,
1472 0.2111529182853962382105718e+3,
1473 0.12571716929145341558495e+1
1477 0.352246649133679798068390431e+5,
1478 0.626943469593560511888833731e+5,
1479 0.312404063819041039923015703e+5,
1480 0.4930396490181088979386097e+4,
1481 0.2030775189134759322293574e+3,
1487 for (i=4; i >= 0; i--)
1489 p=p*(8.0/x)*(8.0/x)+Pone[i];
1490 q=q*(8.0/x)*(8.0/x)+Qone[i];
1496static double Q1(
double x)
1508 0.3511751914303552822533318e+3,
1509 0.7210391804904475039280863e+3,
1510 0.4259873011654442389886993e+3,
1511 0.831898957673850827325226e+2,
1512 0.45681716295512267064405e+1,
1513 0.3532840052740123642735e-1
1517 0.74917374171809127714519505e+4,
1518 0.154141773392650970499848051e+5,
1519 0.91522317015169922705904727e+4,
1520 0.18111867005523513506724158e+4,
1521 0.1038187585462133728776636e+3,
1527 for (i=4; i >= 0; i--)
1529 p=p*(8.0/x)*(8.0/x)+Pone[i];
1530 q=q*(8.0/x)*(8.0/x)+Qone[i];
1535static double BesselOrderOne(
double x)
1548 q=sqrt((
double) (2.0/(MagickPI*x)))*(P1(x)*(1.0/sqrt(2.0)*(sin(x)-
1549 cos(x)))-8.0/x*Q1(x)*(-1.0/sqrt(2.0)*(sin(x)+cos(x))));
1577MagickPrivate ResizeFilter *DestroyResizeFilter(ResizeFilter *resize_filter)
1579 assert(resize_filter != (ResizeFilter *) NULL);
1580 assert(resize_filter->signature == MagickCoreSignature);
1581 resize_filter->signature=(~MagickCoreSignature);
1582 resize_filter=(ResizeFilter *) RelinquishMagickMemory(resize_filter);
1583 return(resize_filter);
1610MagickPrivate
double *GetResizeFilterCoefficient(
1611 const ResizeFilter *resize_filter)
1613 assert(resize_filter != (ResizeFilter *) NULL);
1614 assert(resize_filter->signature == MagickCoreSignature);
1615 return((
double *) resize_filter->coefficient);
1618MagickPrivate
double GetResizeFilterBlur(
const ResizeFilter *resize_filter)
1620 assert(resize_filter != (ResizeFilter *) NULL);
1621 assert(resize_filter->signature == MagickCoreSignature);
1622 return(resize_filter->blur);
1625MagickPrivate
double GetResizeFilterScale(
const ResizeFilter *resize_filter)
1627 assert(resize_filter != (ResizeFilter *) NULL);
1628 assert(resize_filter->signature == MagickCoreSignature);
1629 return(resize_filter->scale);
1632MagickPrivate
double GetResizeFilterWindowSupport(
1633 const ResizeFilter *resize_filter)
1635 assert(resize_filter != (ResizeFilter *) NULL);
1636 assert(resize_filter->signature == MagickCoreSignature);
1637 return(resize_filter->window_support);
1640MagickPrivate ResizeWeightingFunctionType GetResizeFilterWeightingType(
1641 const ResizeFilter *resize_filter)
1643 assert(resize_filter != (ResizeFilter *) NULL);
1644 assert(resize_filter->signature == MagickCoreSignature);
1645 return(resize_filter->filterWeightingType);
1648MagickPrivate ResizeWeightingFunctionType GetResizeFilterWindowWeightingType(
1649 const ResizeFilter *resize_filter)
1651 assert(resize_filter != (ResizeFilter *) NULL);
1652 assert(resize_filter->signature == MagickCoreSignature);
1653 return(resize_filter->windowWeightingType);
1656MagickPrivate
double GetResizeFilterSupport(
const ResizeFilter *resize_filter)
1658 assert(resize_filter != (ResizeFilter *) NULL);
1659 assert(resize_filter->signature == MagickCoreSignature);
1660 return(resize_filter->support*resize_filter->blur);
1690MagickPrivate
double GetResizeFilterWeight(
const ResizeFilter *resize_filter,
1701 assert(resize_filter != (ResizeFilter *) NULL);
1702 assert(resize_filter->signature == MagickCoreSignature);
1703 x_blur=fabs((
double) x)*MagickSafeReciprocal(resize_filter->blur);
1704 if ((resize_filter->window_support < MagickEpsilon) ||
1705 (resize_filter->window == Box))
1709 scale=resize_filter->scale;
1710 scale=resize_filter->window(x_blur*scale,resize_filter);
1712 weight=scale*resize_filter->filter(x_blur,resize_filter);
1749MagickExport Image *InterpolativeResizeImage(
const Image *image,
1750 const size_t columns,
const size_t rows,
const PixelInterpolateMethod method,
1751 ExceptionInfo *exception)
1753#define InterpolativeResizeImageTag "Resize/Image"
1777 assert(image != (
const Image *) NULL);
1778 assert(image->signature == MagickCoreSignature);
1779 assert(exception != (ExceptionInfo *) NULL);
1780 assert(exception->signature == MagickCoreSignature);
1781 if (IsEventLogging() != MagickFalse)
1782 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1783 if ((columns == 0) || (rows == 0))
1784 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
1785 if ((columns == image->columns) && (rows == image->rows))
1786 return(CloneImage(image,0,0,MagickTrue,exception));
1787 resize_image=CloneImage(image,columns,rows,MagickTrue,exception);
1788 if (resize_image == (Image *) NULL)
1789 return((Image *) NULL);
1790 if (SetImageStorageClass(resize_image,DirectClass,exception) == MagickFalse)
1792 resize_image=DestroyImage(resize_image);
1793 return((Image *) NULL);
1797 image_view=AcquireVirtualCacheView(image,exception);
1798 resize_view=AcquireAuthenticCacheView(resize_image,exception);
1799 scale.x=(double) image->columns/resize_image->columns;
1800 scale.y=(double) image->rows/resize_image->rows;
1801#if defined(MAGICKCORE_OPENMP_SUPPORT)
1802 #pragma omp parallel for schedule(static) shared(progress,status) \
1803 magick_number_threads(image,resize_image,resize_image->rows,1)
1805 for (y=0; y < (ssize_t) resize_image->rows; y++)
1816 if (status == MagickFalse)
1818 q=QueueCacheViewAuthenticPixels(resize_view,0,y,resize_image->columns,1,
1820 if (q == (Quantum *) NULL)
1822 offset.y=((double) y+0.5)*scale.y-0.5;
1823 for (x=0; x < (ssize_t) resize_image->columns; x++)
1828 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1837 channel=GetPixelChannelChannel(image,i);
1838 traits=GetPixelChannelTraits(image,channel);
1839 resize_traits=GetPixelChannelTraits(resize_image,channel);
1840 if ((traits == UndefinedPixelTrait) ||
1841 (resize_traits == UndefinedPixelTrait))
1843 offset.x=((double) x+0.5)*scale.x-0.5;
1844 status=InterpolatePixelChannels(image,image_view,resize_image,method,
1845 offset.x,offset.y,q,exception);
1846 if (status == MagickFalse)
1849 q+=(ptrdiff_t) GetPixelChannels(resize_image);
1851 if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
1853 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1858#if defined(MAGICKCORE_OPENMP_SUPPORT)
1862 proceed=SetImageProgress(image,InterpolativeResizeImageTag,progress,
1864 if (proceed == MagickFalse)
1868 resize_view=DestroyCacheView(resize_view);
1869 image_view=DestroyCacheView(image_view);
1870 if (status == MagickFalse)
1871 resize_image=DestroyImage(resize_image);
1872 return(resize_image);
1874#if defined(MAGICKCORE_LQR_DELEGATE)
1910MagickExport Image *LiquidRescaleImage(
const Image *image,
const size_t columns,
1911 const size_t rows,
const double delta_x,
const double rigidity,
1912 ExceptionInfo *exception)
1914#define LiquidRescaleImageTag "Rescale/Image"
1952 assert(image != (
const Image *) NULL);
1953 assert(image->signature == MagickCoreSignature);
1954 assert(exception != (ExceptionInfo *) NULL);
1955 assert(exception->signature == MagickCoreSignature);
1956 if (IsEventLogging() != MagickFalse)
1957 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1958 if ((columns == 0) || (rows == 0))
1959 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
1960 if ((columns == image->columns) && (rows == image->rows))
1961 return(CloneImage(image,0,0,MagickTrue,exception));
1962 if ((columns <= 2) || (rows <= 2))
1963 return(ResizeImage(image,columns,rows,image->filter,exception));
1964 pixel_info=AcquireVirtualMemory(image->columns,image->rows*MaxPixelChannels*
1966 if (pixel_info == (MemoryInfo *) NULL)
1967 return((Image *) NULL);
1968 pixels=(gfloat *) GetVirtualMemoryBlob(pixel_info);
1971 image_view=AcquireVirtualCacheView(image,exception);
1972 for (y=0; y < (ssize_t) image->rows; y++)
1980 if (status == MagickFalse)
1982 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1983 if (p == (
const Quantum *) NULL)
1988 for (x=0; x < (ssize_t) image->columns; x++)
1993 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1994 *q++=(gfloat) (QuantumScale*(double) p[i]);
1995 p+=(ptrdiff_t) GetPixelChannels(image);
1998 image_view=DestroyCacheView(image_view);
1999 carver=lqr_carver_new_ext(pixels,(
int) image->columns,(
int) image->rows,
2000 (
int) GetPixelChannels(image),LQR_COLDEPTH_32F);
2001 if (carver == (LqrCarver *) NULL)
2003 pixel_info=RelinquishVirtualMemory(pixel_info);
2004 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2006 lqr_carver_set_preserve_input_image(carver);
2007 lqr_status=lqr_carver_init(carver,(gint) delta_x,(gfloat) rigidity);
2008 lqr_status=lqr_carver_resize(carver,(gint) columns,(gint) rows);
2010 rescale_image=CloneImage(image,(
size_t) lqr_carver_get_width(carver),
2011 (
size_t) lqr_carver_get_height(carver),MagickTrue,exception);
2012 if (rescale_image == (Image *) NULL)
2014 pixel_info=RelinquishVirtualMemory(pixel_info);
2015 return((Image *) NULL);
2017 if (SetImageStorageClass(rescale_image,DirectClass,exception) == MagickFalse)
2019 pixel_info=RelinquishVirtualMemory(pixel_info);
2020 rescale_image=DestroyImage(rescale_image);
2021 return((Image *) NULL);
2023 rescale_view=AcquireAuthenticCacheView(rescale_image,exception);
2024 (void) lqr_carver_scan_reset(carver);
2025 while (lqr_carver_scan_ext(carver,&x_offset,&y_offset,(
void **) &packet) != 0)
2033 p=QueueCacheViewAuthenticPixels(rescale_view,x_offset,y_offset,1,1,
2035 if (p == (Quantum *) NULL)
2037 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2046 channel=GetPixelChannelChannel(image,i);
2047 traits=GetPixelChannelTraits(image,channel);
2048 rescale_traits=GetPixelChannelTraits(rescale_image,channel);
2049 if ((traits == UndefinedPixelTrait) ||
2050 (rescale_traits == UndefinedPixelTrait))
2052 SetPixelChannel(rescale_image,channel,ClampToQuantum(QuantumRange*
2055 if (SyncCacheViewAuthenticPixels(rescale_view,exception) == MagickFalse)
2058 rescale_view=DestroyCacheView(rescale_view);
2059 pixel_info=RelinquishVirtualMemory(pixel_info);
2060 lqr_carver_destroy(carver);
2061 return(rescale_image);
2064MagickExport Image *LiquidRescaleImage(
const Image *image,
2065 const size_t magick_unused(columns),
const size_t magick_unused(rows),
2066 const double magick_unused(delta_x),
const double magick_unused(rigidity),
2067 ExceptionInfo *exception)
2069 assert(image != (
const Image *) NULL);
2070 assert(image->signature == MagickCoreSignature);
2071 assert(exception != (ExceptionInfo *) NULL);
2072 assert(exception->signature == MagickCoreSignature);
2073 magick_unreferenced(columns);
2074 magick_unreferenced(rows);
2075 magick_unreferenced(delta_x);
2076 magick_unreferenced(rigidity);
2077 if (IsEventLogging() != MagickFalse)
2078 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2079 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
2080 "DelegateLibrarySupportNotBuiltIn",
"'%s' (LQR)",image->filename);
2081 return((Image *) NULL);
2111static inline void CopyPixels(
const Quantum *source,
const ssize_t source_offset,
2112 Quantum *destination,
const ssize_t destination_offset,
const size_t channels)
2117 for (i=0; i < (ssize_t) channels; i++)
2118 destination[(ssize_t) channels*destination_offset+i]=
2119 source[source_offset*(ssize_t) channels+i];
2122static inline void MixPixels(
const Quantum *source,
const ssize_t *source_offset,
2123 const size_t source_size,Quantum *destination,
2124 const ssize_t destination_offset,
const size_t channels)
2129 for (i=0; i < (ssize_t) channels; i++)
2135 for (j=0; j < (ssize_t) source_size; j++)
2136 sum+=(ssize_t) source[source_offset[j]*(ssize_t) channels+i];
2137 destination[(ssize_t) channels*destination_offset+i]=(Quantum) (sum/
2138 (ssize_t) source_size);
2142static inline void Mix2Pixels(
const Quantum *source,
2143 const ssize_t source_offset1,
const ssize_t source_offset2,
2144 Quantum *destination,
const ssize_t destination_offset,
const size_t channels)
2147 offsets[2] = { source_offset1, source_offset2 };
2149 MixPixels(source,offsets,2,destination,destination_offset,channels);
2152static inline int PixelsEqual(
const Quantum *source1,ssize_t offset1,
2153 const Quantum *source2,ssize_t offset2,
const size_t channels)
2158 offset1*=(ssize_t) channels;
2159 offset2*=(ssize_t) channels;
2160 for (i=0; i < (ssize_t) channels; i++)
2161 if (source1[offset1+i] != source2[offset2+i])
2166static inline void Eagle2X(
const Image *source,
const Quantum *pixels,
2167 Quantum *result,
const size_t channels)
2173 for (i=0; i < 4; i++)
2174 CopyPixels(pixels,4,result,i,channels);
2175 if (PixelsEqual(pixels,0,pixels,1,channels) &&
2176 PixelsEqual(pixels,1,pixels,3,channels))
2177 CopyPixels(pixels,0,result,0,channels);
2178 if (PixelsEqual(pixels,1,pixels,2,channels) &&
2179 PixelsEqual(pixels,2,pixels,5,channels))
2180 CopyPixels(pixels,2,result,1,channels);
2181 if (PixelsEqual(pixels,3,pixels,6,channels) &&
2182 PixelsEqual(pixels,6,pixels,7,channels))
2183 CopyPixels(pixels,6,result,2,channels);
2184 if (PixelsEqual(pixels,5,pixels,8,channels) &&
2185 PixelsEqual(pixels,8,pixels,7,channels))
2186 CopyPixels(pixels,8,result,3,channels);
2189static void Hq2XHelper(
const unsigned int rule,
const Quantum *source,
2190 Quantum *destination,
const ssize_t destination_offset,
const size_t channels,
2191 const ssize_t e,
const ssize_t a,
const ssize_t b,
const ssize_t d,
2192 const ssize_t f,
const ssize_t h)
2194#define caseA(N,A,B,C,D) \
2198 offsets[4] = { A, B, C, D }; \
2200 MixPixels(source,offsets,4,destination,destination_offset,channels);\
2203#define caseB(N,A,B,C,D,E,F,G,H) \
2207 offsets[8] = { A, B, C, D, E, F, G, H }; \
2209 MixPixels(source,offsets,8,destination,destination_offset,channels);\
2217 CopyPixels(source,e,destination,destination_offset,channels);
2226 caseB(7,e,e,e,e,e,b,b,d)
2227 caseB(8,e,e,e,e,e,d,d,b)
2228 caseB(9,e,e,e,e,e,e,d,b)
2229 caseB(10,e,e,d,d,d,b,b,b)
2233 offsets[16] = { e, e, e, e, e, e, e, e, e, e, e, e, e, e, d, b };
2235 MixPixels(source,offsets,16,destination,destination_offset,channels);
2240 if (PixelsEqual(source,b,source,d,channels))
2243 offsets[4] = { e, e, d, b };
2245 MixPixels(source,offsets,4,destination,destination_offset,channels);
2248 CopyPixels(source,e,destination,destination_offset,channels);
2253 if (PixelsEqual(source,b,source,d,channels))
2256 offsets[8] = { e, e, d, d, d, b, b, b };
2258 MixPixels(source,offsets,8,destination,destination_offset,channels);
2261 CopyPixels(source,e,destination,destination_offset,channels);
2266 if (PixelsEqual(source,b,source,d,channels))
2269 offsets[16] = { e, e, e, e, e, e, e, e, e, e, e, e, e, e, d, b };
2271 MixPixels(source,offsets,16,destination,destination_offset,channels);
2274 CopyPixels(source,e,destination,destination_offset,channels);
2279 if (PixelsEqual(source,b,source,d,channels))
2282 offsets[4] = { e, e, d, b };
2284 MixPixels(source,offsets,4,destination,destination_offset,channels);
2289 offsets[4] = { e, e, e, a };
2291 MixPixels(source,offsets,4,destination,destination_offset,channels);
2297 if (PixelsEqual(source,b,source,d,channels))
2300 offsets[8] = { e, e, e, e, e, e, d, b };
2302 MixPixels(source,offsets,8,destination,destination_offset,channels);
2307 offsets[4] = { e, e, e, a };
2309 MixPixels(source,offsets,4,destination,destination_offset,channels);
2315 if (PixelsEqual(source,b,source,d,channels))
2318 offsets[8] = { e, e, d, d, d, b, b, b };
2320 MixPixels(source,offsets,8,destination,destination_offset,channels);
2325 offsets[4] = { e, e, e, a };
2327 MixPixels(source,offsets,4,destination,destination_offset,channels);
2333 if (PixelsEqual(source,b,source,f,channels))
2336 offsets[8] = { e, e, e, e, e, b, b, d };
2338 MixPixels(source,offsets,8,destination,destination_offset,channels);
2343 offsets[4] = { e, e, e, d };
2345 MixPixels(source,offsets,4,destination,destination_offset,channels);
2351 if (PixelsEqual(source,d,source,h,channels))
2354 offsets[8] = { e, e, e, e, e, d, d, b };
2356 MixPixels(source,offsets,8,destination,destination_offset,channels);
2361 offsets[4] = { e, e, e, b };
2363 MixPixels(source,offsets,4,destination,destination_offset,channels);
2372static inline unsigned int Hq2XPatternToNumber(
const int *pattern)
2383 for (i=7; i >= 0; i--)
2385 result+=order*(
unsigned int) pattern[i];
2391static inline void Hq2X(
const Image *source,
const Quantum *pixels,
2392 Quantum *result,
const size_t channels)
2394 static const unsigned int
2397 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
2398 4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 12, 12, 5, 3, 1, 12,
2399 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14,
2400 4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 16, 12, 5, 3, 1, 14,
2401 4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 12, 12, 5, 19, 16, 12,
2402 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12,
2403 4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 1, 12, 5, 19, 1, 14,
2404 4, 4, 6, 2, 4, 4, 6, 18, 5, 3, 16, 12, 5, 19, 1, 14,
2405 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
2406 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12,
2407 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14,
2408 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 13, 5, 3, 1, 14,
2409 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 13,
2410 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 12,
2411 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 14,
2412 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 1, 12, 5, 3, 1, 14
2418 !PixelsEqual(pixels,4,pixels,8,channels),
2419 !PixelsEqual(pixels,4,pixels,7,channels),
2420 !PixelsEqual(pixels,4,pixels,6,channels),
2421 !PixelsEqual(pixels,4,pixels,5,channels),
2422 !PixelsEqual(pixels,4,pixels,3,channels),
2423 !PixelsEqual(pixels,4,pixels,2,channels),
2424 !PixelsEqual(pixels,4,pixels,1,channels),
2425 !PixelsEqual(pixels,4,pixels,0,channels)
2428#define Rotated(p) p[2], p[4], p[7], p[1], p[6], p[0], p[3], p[5]
2429 const int pattern2[] = { Rotated(pattern1) };
2430 const int pattern3[] = { Rotated(pattern2) };
2431 const int pattern4[] = { Rotated(pattern3) };
2434 Hq2XHelper(Hq2XTable[Hq2XPatternToNumber(pattern1)],pixels,result,0,
2435 channels,4,0,1,3,5,7);
2436 Hq2XHelper(Hq2XTable[Hq2XPatternToNumber(pattern2)],pixels,result,1,
2437 channels,4,2,5,1,7,3);
2438 Hq2XHelper(Hq2XTable[Hq2XPatternToNumber(pattern3)],pixels,result,3,
2439 channels,4,8,7,5,3,1);
2440 Hq2XHelper(Hq2XTable[Hq2XPatternToNumber(pattern4)],pixels,result,2,
2441 channels,4,6,3,7,1,5);
2444static void Fish2X(
const Image *source,
const Quantum *pixels,Quantum *result,
2445 const size_t channels)
2447#define Corner(A,B,C,D) \
2449 if (intensities[B] > intensities[A]) \
2452 offsets[3] = { B, C, D }; \
2454 MixPixels(pixels,offsets,3,result,3,channels); \
2459 offsets[3] = { A, B, C }; \
2461 MixPixels(pixels,offsets,3,result,3,channels); \
2465#define Line(A,B,C,D) \
2467 if (intensities[C] > intensities[A]) \
2468 Mix2Pixels(pixels,C,D,result,3,channels); \
2470 Mix2Pixels(pixels,A,B,result,3,channels); \
2474 pixels_offsets[4] = { 0, 1, 3, 4 };
2490 for (i=0; i < 9; i++)
2491 intensities[i]=(MagickFloatType) GetPixelIntensity(source,pixels+
2492 i*(ssize_t) channels);
2493 CopyPixels(pixels,0,result,0,channels);
2494 CopyPixels(pixels,(ssize_t) (intensities[0] > intensities[1] ? 0 : 1),result,
2496 CopyPixels(pixels,(ssize_t) (intensities[0] > intensities[3] ? 0 : 3),result,
2498 ae=PixelsEqual(pixels,0,pixels,4,channels);
2499 bd=PixelsEqual(pixels,1,pixels,3,channels);
2500 ab=PixelsEqual(pixels,0,pixels,1,channels);
2501 de=PixelsEqual(pixels,3,pixels,4,channels);
2502 ad=PixelsEqual(pixels,0,pixels,3,channels);
2503 be=PixelsEqual(pixels,1,pixels,4,channels);
2506 CopyPixels(pixels,0,result,3,channels);
2509 if (ad && de && !ab)
2514 if (be && de && !ab)
2519 if (ad && ab && !be)
2524 if (ab && be && !ad)
2529 if (ae && (!bd || intensities[1] > intensities[0]))
2531 Mix2Pixels(pixels,0,4,result,3,channels);
2534 if (bd && (!ae || intensities[0] > intensities[1]))
2536 Mix2Pixels(pixels,1,3,result,3,channels);
2559 MixPixels(pixels,pixels_offsets,4,result,3,channels);
2564static void Xbr2X(
const Image *magick_unused(source),
const Quantum *pixels,
2565 Quantum *result,
const size_t channels)
2567#define WeightVar(M,N) const int w_##M##_##N = \
2568 PixelsEqual(pixels,M,pixels,N,channels) ? 0 : 1;
2600 magick_unreferenced(source);
2603 w_12_16 + w_12_8 + w_6_10 + w_6_2 + (4 * w_11_7) <
2604 w_11_17 + w_11_5 + w_7_13 + w_7_1 + (4 * w_12_6)
2606 Mix2Pixels(pixels,(ssize_t) (w_12_11 <= w_12_7 ? 11 : 7),12,result,0,
2609 CopyPixels(pixels,12,result,0,channels);
2611 w_12_18 + w_12_6 + w_8_14 + w_8_2 + (4 * w_7_13) <
2612 w_13_17 + w_13_9 + w_11_7 + w_7_3 + (4 * w_12_8)
2614 Mix2Pixels(pixels,(ssize_t) (w_12_7 <= w_12_13 ? 7 : 13),12,result,1,
2617 CopyPixels(pixels,12,result,1,channels);
2619 w_12_6 + w_12_18 + w_16_10 + w_16_22 + (4 * w_11_17) <
2620 w_11_7 + w_11_15 + w_13_17 + w_17_21 + (4 * w_12_16)
2622 Mix2Pixels(pixels,(ssize_t) (w_12_11 <= w_12_17 ? 11 : 17),12,result,2,
2625 CopyPixels(pixels,12,result,2,channels);
2627 w_12_8 + w_12_16 + w_18_14 + w_18_22 + (4 * w_13_17) <
2628 w_11_17 + w_17_23 + w_17_19 + w_7_13 + (4 * w_12_18)
2630 Mix2Pixels(pixels,(ssize_t) (w_12_13 <= w_12_17 ? 13 : 17),12,result,3,
2633 CopyPixels(pixels,12,result,3,channels);
2636static void Scale2X(
const Image *magick_unused(source),
const Quantum *pixels,
2637 Quantum *result,
const size_t channels)
2639 magick_unreferenced(source);
2641 if (PixelsEqual(pixels,1,pixels,7,channels) ||
2642 PixelsEqual(pixels,3,pixels,5,channels))
2647 for (i=0; i < 4; i++)
2648 CopyPixels(pixels,4,result,i,channels);
2651 if (PixelsEqual(pixels,1,pixels,3,channels))
2652 CopyPixels(pixels,3,result,0,channels);
2654 CopyPixels(pixels,4,result,0,channels);
2655 if (PixelsEqual(pixels,1,pixels,5,channels))
2656 CopyPixels(pixels,5,result,1,channels);
2658 CopyPixels(pixels,4,result,1,channels);
2659 if (PixelsEqual(pixels,3,pixels,7,channels))
2660 CopyPixels(pixels,3,result,2,channels);
2662 CopyPixels(pixels,4,result,2,channels);
2663 if (PixelsEqual(pixels,5,pixels,7,channels))
2664 CopyPixels(pixels,5,result,3,channels);
2666 CopyPixels(pixels,4,result,3,channels);
2669static void Epbx2X(
const Image *magick_unused(source),
const Quantum *pixels,
2670 Quantum *result,
const size_t channels)
2672#define HelperCond(a,b,c,d,e,f,g) ( \
2673 PixelsEqual(pixels,a,pixels,b,channels) && ( \
2674 PixelsEqual(pixels,c,pixels,d,channels) || \
2675 PixelsEqual(pixels,c,pixels,e,channels) || \
2676 PixelsEqual(pixels,a,pixels,f,channels) || \
2677 PixelsEqual(pixels,b,pixels,g,channels) \
2684 magick_unreferenced(source);
2686 for (i=0; i < 4; i++)
2687 CopyPixels(pixels,4,result,i,channels);
2689 !PixelsEqual(pixels,3,pixels,5,channels) &&
2690 !PixelsEqual(pixels,1,pixels,7,channels) &&
2692 PixelsEqual(pixels,4,pixels,3,channels) ||
2693 PixelsEqual(pixels,4,pixels,7,channels) ||
2694 PixelsEqual(pixels,4,pixels,5,channels) ||
2695 PixelsEqual(pixels,4,pixels,1,channels) ||
2698 !PixelsEqual(pixels,0,pixels,8,channels) ||
2699 PixelsEqual(pixels,4,pixels,6,channels) ||
2700 PixelsEqual(pixels,3,pixels,2,channels)
2703 !PixelsEqual(pixels,6,pixels,2,channels) ||
2704 PixelsEqual(pixels,4,pixels,0,channels) ||
2705 PixelsEqual(pixels,4,pixels,8,channels)
2711 if (HelperCond(1,3,4,0,8,2,6))
2712 Mix2Pixels(pixels,1,3,result,0,channels);
2713 if (HelperCond(5,1,4,2,6,8,0))
2714 Mix2Pixels(pixels,5,1,result,1,channels);
2715 if (HelperCond(3,7,4,6,2,0,8))
2716 Mix2Pixels(pixels,3,7,result,2,channels);
2717 if (HelperCond(7,5,4,8,0,6,2))
2718 Mix2Pixels(pixels,7,5,result,3,channels);
2724static inline void Eagle3X(
const Image *magick_unused(source),
2725 const Quantum *pixels,Quantum *result,
const size_t channels)
2733 magick_unreferenced(source);
2735 corner_tl=PixelsEqual(pixels,0,pixels,1,channels) &&
2736 PixelsEqual(pixels,0,pixels,3,channels);
2737 corner_tr=PixelsEqual(pixels,1,pixels,2,channels) &&
2738 PixelsEqual(pixels,2,pixels,5,channels);
2739 corner_bl=PixelsEqual(pixels,3,pixels,6,channels) &&
2740 PixelsEqual(pixels,6,pixels,7,channels);
2741 corner_br=PixelsEqual(pixels,5,pixels,7,channels) &&
2742 PixelsEqual(pixels,7,pixels,8,channels);
2743 CopyPixels(pixels,(ssize_t) (corner_tl ? 0 : 4),result,0,channels);
2744 if (corner_tl && corner_tr)
2745 Mix2Pixels(pixels,0,2,result,1,channels);
2747 CopyPixels(pixels,4,result,1,channels);
2748 CopyPixels(pixels,(ssize_t) (corner_tr ? 1 : 4),result,2,channels);
2749 if (corner_tl && corner_bl)
2750 Mix2Pixels(pixels,0,6,result,3,channels);
2752 CopyPixels(pixels,4,result,3,channels);
2753 CopyPixels(pixels,4,result,4,channels);
2754 if (corner_tr && corner_br)
2755 Mix2Pixels(pixels,2,8,result,5,channels);
2757 CopyPixels(pixels,4,result,5,channels);
2758 CopyPixels(pixels,(ssize_t) (corner_bl ? 3 : 4),result,6,channels);
2759 if (corner_bl && corner_br)
2760 Mix2Pixels(pixels,6,8,result,7,channels);
2762 CopyPixels(pixels,4,result,7,channels);
2763 CopyPixels(pixels,(ssize_t) (corner_br ? 5 : 4),result,8,channels);
2766static inline void Eagle3XB(
const Image *magick_unused(source),
2767 const Quantum *pixels,Quantum *result,
const size_t channels)
2775 magick_unreferenced(source);
2777 corner_tl=PixelsEqual(pixels,0,pixels,1,channels) &&
2778 PixelsEqual(pixels,0,pixels,3,channels);
2779 corner_tr=PixelsEqual(pixels,1,pixels,2,channels) &&
2780 PixelsEqual(pixels,2,pixels,5,channels);
2781 corner_bl=PixelsEqual(pixels,3,pixels,6,channels) &&
2782 PixelsEqual(pixels,6,pixels,7,channels);
2783 corner_br=PixelsEqual(pixels,5,pixels,7,channels) &&
2784 PixelsEqual(pixels,7,pixels,8,channels);
2785 CopyPixels(pixels,(ssize_t) (corner_tl ? 0 : 4),result,0,channels);
2786 CopyPixels(pixels,4,result,1,channels);
2787 CopyPixels(pixels,(ssize_t) (corner_tr ? 1 : 4),result,2,channels);
2788 CopyPixels(pixels,4,result,3,channels);
2789 CopyPixels(pixels,4,result,4,channels);
2790 CopyPixels(pixels,4,result,5,channels);
2791 CopyPixels(pixels,(ssize_t) (corner_bl ? 3 : 4),result,6,channels);
2792 CopyPixels(pixels,4,result,7,channels);
2793 CopyPixels(pixels,(ssize_t) (corner_br ? 5 : 4),result,8,channels);
2796static inline void Scale3X(
const Image *magick_unused(source),
2797 const Quantum *pixels,Quantum *result,
const size_t channels)
2799 magick_unreferenced(source);
2801 if (!PixelsEqual(pixels,1,pixels,7,channels) &&
2802 !PixelsEqual(pixels,3,pixels,5,channels))
2804 if (PixelsEqual(pixels,3,pixels,1,channels))
2805 CopyPixels(pixels,3,result,0,channels);
2807 CopyPixels(pixels,4,result,0,channels);
2811 PixelsEqual(pixels,3,pixels,1,channels) &&
2812 !PixelsEqual(pixels,4,pixels,2,channels)
2815 PixelsEqual(pixels,5,pixels,1,channels) &&
2816 !PixelsEqual(pixels,4,pixels,0,channels)
2819 CopyPixels(pixels,1,result,1,channels);
2821 CopyPixels(pixels,4,result,1,channels);
2822 if (PixelsEqual(pixels,5,pixels,1,channels))
2823 CopyPixels(pixels,5,result,2,channels);
2825 CopyPixels(pixels,4,result,2,channels);
2828 PixelsEqual(pixels,3,pixels,1,channels) &&
2829 !PixelsEqual(pixels,4,pixels,6,channels)
2832 PixelsEqual(pixels,3,pixels,7,channels) &&
2833 !PixelsEqual(pixels,4,pixels,0,channels)
2836 CopyPixels(pixels,3,result,3,channels);
2838 CopyPixels(pixels,4,result,3,channels);
2839 CopyPixels(pixels,4,result,4,channels);
2842 PixelsEqual(pixels,5,pixels,1,channels) &&
2843 !PixelsEqual(pixels,4,pixels,8,channels)
2846 PixelsEqual(pixels,5,pixels,7,channels) &&
2847 !PixelsEqual(pixels,4,pixels,2,channels)
2850 CopyPixels(pixels,5,result,5,channels);
2852 CopyPixels(pixels,4,result,5,channels);
2853 if (PixelsEqual(pixels,3,pixels,7,channels))
2854 CopyPixels(pixels,3,result,6,channels);
2856 CopyPixels(pixels,4,result,6,channels);
2859 PixelsEqual(pixels,3,pixels,7,channels) &&
2860 !PixelsEqual(pixels,4,pixels,8,channels)
2863 PixelsEqual(pixels,5,pixels,7,channels) &&
2864 !PixelsEqual(pixels,4,pixels,6,channels)
2867 CopyPixels(pixels,7,result,7,channels);
2869 CopyPixels(pixels,4,result,7,channels);
2870 if (PixelsEqual(pixels,5,pixels,7,channels))
2871 CopyPixels(pixels,5,result,8,channels);
2873 CopyPixels(pixels,4,result,8,channels);
2880 for (i=0; i < 9; i++)
2881 CopyPixels(pixels,4,result,i,channels);
2885MagickExport Image *MagnifyImage(
const Image *image,ExceptionInfo *exception)
2887#define MagnifyImageTag "Magnify/Image"
2920 (*scaling_method)(
const Image *,
const Quantum *,Quantum *,size_t);
2925 assert(image != (
const Image *) NULL);
2926 assert(image->signature == MagickCoreSignature);
2927 assert(exception != (ExceptionInfo *) NULL);
2928 assert(exception->signature == MagickCoreSignature);
2929 if (IsEventLogging() != MagickFalse)
2930 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2931 option=GetImageOption(image->image_info,
"magnify:method");
2932 if (option == (
char *) NULL)
2934 scaling_method=Scale2X;
2941 if (LocaleCompare(option,
"eagle2x") == 0)
2943 scaling_method=Eagle2X;
2948 if (LocaleCompare(option,
"eagle3x") == 0)
2950 scaling_method=Eagle3X;
2955 if (LocaleCompare(option,
"eagle3xb") == 0)
2957 scaling_method=Eagle3XB;
2962 if (LocaleCompare(option,
"epbx2x") == 0)
2964 scaling_method=Epbx2X;
2973 if (LocaleCompare(option,
"fish2x") == 0)
2975 scaling_method=Fish2X;
2984 if (LocaleCompare(option,
"hq2x") == 0)
2986 scaling_method=Hq2X;
2995 if (LocaleCompare(option,
"scale2x") == 0)
2997 scaling_method=Scale2X;
3002 if (LocaleCompare(option,
"scale3x") == 0)
3004 scaling_method=Scale3X;
3013 if (LocaleCompare(option,
"xbr2x") == 0)
3015 scaling_method=Xbr2X;
3027 source_image=CloneImage(image,image->columns,image->rows,MagickTrue,
3029 if (source_image == (Image *) NULL)
3030 return((Image *) NULL);
3035 rectangle.width=image->columns;
3036 rectangle.height=image->rows;
3037 (void) CopyImagePixels(source_image,image,&rectangle,&offset,exception);
3038 if (IssRGBCompatibleColorspace(source_image->colorspace) == MagickFalse)
3039 (void) TransformImageColorspace(source_image,sRGBColorspace,exception);
3040 magnify_image=CloneImage(source_image,magnification*source_image->columns,
3041 magnification*source_image->rows,MagickTrue,exception);
3042 if (magnify_image == (Image *) NULL)
3044 source_image=DestroyImage(source_image);
3045 return((Image *) NULL);
3052 image_view=AcquireVirtualCacheView(source_image,exception);
3053 magnify_view=AcquireAuthenticCacheView(magnify_image,exception);
3054#if defined(MAGICKCORE_OPENMP_SUPPORT)
3055 #pragma omp parallel for schedule(static) shared(progress,status) \
3056 magick_number_threads(source_image,magnify_image,source_image->rows,1)
3058 for (y=0; y < (ssize_t) source_image->rows; y++)
3069 if (status == MagickFalse)
3071 q=QueueCacheViewAuthenticPixels(magnify_view,0,magnification*y,
3072 magnify_image->columns,magnification,exception);
3073 if (q == (Quantum *) NULL)
3081 for (x=0; x < (ssize_t) source_image->columns; x++)
3093 p=GetCacheViewVirtualPixels(image_view,x-width/2,y-width/2,width,width,
3095 if (p == (Quantum *) NULL)
3100 channels=GetPixelChannels(source_image);
3101 scaling_method(source_image,p,r,channels);
3105 for (j=0; j < (ssize_t) magnification; j++)
3106 for (i=0; i < (ssize_t) (channels*magnification); i++)
3107 q[j*(ssize_t) channels*(ssize_t) magnify_image->columns+i]=
3108 r[j*magnification*(ssize_t) channels+i];
3109 q+=(ptrdiff_t) magnification*GetPixelChannels(magnify_image);
3111 if (SyncCacheViewAuthenticPixels(magnify_view,exception) == MagickFalse)
3113 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3118#if defined(MAGICKCORE_OPENMP_SUPPORT)
3122 proceed=SetImageProgress(image,MagnifyImageTag,progress,image->rows);
3123 if (proceed == MagickFalse)
3127 magnify_view=DestroyCacheView(magnify_view);
3128 image_view=DestroyCacheView(image_view);
3129 source_image=DestroyImage(source_image);
3130 if (status == MagickFalse)
3131 magnify_image=DestroyImage(magnify_image);
3132 return(magnify_image);
3160MagickExport Image *MinifyImage(
const Image *image,ExceptionInfo *exception)
3165 assert(image != (Image *) NULL);
3166 assert(image->signature == MagickCoreSignature);
3167 assert(exception != (ExceptionInfo *) NULL);
3168 assert(exception->signature == MagickCoreSignature);
3169 if (IsEventLogging() != MagickFalse)
3170 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3171 minify_image=ResizeImage(image,image->columns/2,image->rows/2,SplineFilter,
3173 return(minify_image);
3210MagickExport Image *ResampleImage(
const Image *image,
const double x_resolution,
3211 const double y_resolution,
const FilterType filter,ExceptionInfo *exception)
3213#define ResampleImageTag "Resample/Image"
3225 assert(image != (
const Image *) NULL);
3226 assert(image->signature == MagickCoreSignature);
3227 assert(exception != (ExceptionInfo *) NULL);
3228 assert(exception->signature == MagickCoreSignature);
3229 if (IsEventLogging() != MagickFalse)
3230 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3231 width=(size_t) (x_resolution*image->columns/(image->resolution.x == 0.0 ?
3232 DefaultResolution : image->resolution.x)+0.5);
3233 height=(size_t) (y_resolution*image->rows/(image->resolution.y == 0.0 ?
3234 DefaultResolution : image->resolution.y)+0.5);
3235 resample_image=ResizeImage(image,width,height,filter,exception);
3236 if (resample_image != (Image *) NULL)
3238 resample_image->resolution.x=x_resolution;
3239 resample_image->resolution.y=y_resolution;
3241 return(resample_image);
3292static ContributionInfo **DestroyContributionTLS(
3293 ContributionInfo **contribution)
3298 assert(contribution != (ContributionInfo **) NULL);
3299 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
3300 if (contribution[i] != (ContributionInfo *) NULL)
3301 contribution[i]=(ContributionInfo *) RelinquishAlignedMemory(
3303 contribution=(ContributionInfo **) RelinquishMagickMemory(contribution);
3304 return(contribution);
3307static ContributionInfo **AcquireContributionTLS(
const size_t count)
3318 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
3319 contribution=(ContributionInfo **) AcquireQuantumMemory(number_threads,
3320 sizeof(*contribution));
3321 if (contribution == (ContributionInfo **) NULL)
3322 return((ContributionInfo **) NULL);
3323 (void) memset(contribution,0,number_threads*
sizeof(*contribution));
3324 for (i=0; i < (ssize_t) number_threads; i++)
3326 contribution[i]=(ContributionInfo *) MagickAssumeAligned(
3327 AcquireAlignedMemory(count,
sizeof(**contribution)));
3328 if (contribution[i] == (ContributionInfo *) NULL)
3329 return(DestroyContributionTLS(contribution));
3331 return(contribution);
3334static MagickBooleanType HorizontalFilter(
3335 const ResizeFilter *magick_restrict resize_filter,
3336 const Image *magick_restrict image,Image *magick_restrict resize_image,
3337 const double x_factor,
const MagickSizeType span,
3338 MagickOffsetType *magick_restrict progress,ExceptionInfo *exception)
3340#define ResizeImageTag "Resize/Image"
3350 **magick_restrict contributions;
3365 scale=MagickMax(1.0/x_factor+MagickEpsilon,1.0);
3366 support=scale*GetResizeFilterSupport(resize_filter);
3367 storage_class=support > 0.5 ? DirectClass : image->storage_class;
3368 if (SetImageStorageClass(resize_image,storage_class,exception) == MagickFalse)
3369 return(MagickFalse);
3375 support=(double) 0.5;
3378 contributions=AcquireContributionTLS((
size_t) (2.0*support+3.0));
3379 if (contributions == (ContributionInfo **) NULL)
3381 (void) ThrowMagickException(exception,GetMagickModule(),
3382 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",image->filename);
3383 return(MagickFalse);
3386 scale=MagickSafeReciprocal(scale);
3387 image_view=AcquireVirtualCacheView(image,exception);
3388 resize_view=AcquireAuthenticCacheView(resize_image,exception);
3389#if defined(MAGICKCORE_OPENMP_SUPPORT)
3390 #pragma omp parallel for schedule(static) shared(progress,status) \
3391 magick_number_threads(image,resize_image,resize_image->columns,1)
3393 for (x=0; x < (ssize_t) resize_image->columns; x++)
3396 id = GetOpenMPThreadId();
3402 *magick_restrict contribution;
3417 if (status == MagickFalse)
3419 bisect=(double) (x+0.5)/x_factor+MagickEpsilon;
3420 start=(ssize_t) MagickMax(bisect-support+0.5,0.0);
3421 stop=(ssize_t) MagickMin(bisect+support+0.5,(
double) image->columns);
3423 contribution=contributions[id];
3424 for (n=0; n < (stop-start); n++)
3426 contribution[n].pixel=start+n;
3427 contribution[n].weight=GetResizeFilterWeight(resize_filter,scale*
3428 ((
double) (start+n)-bisect+0.5));
3429 density+=contribution[n].weight;
3433 if ((density != 0.0) && (density != 1.0))
3441 density=MagickSafeReciprocal(density);
3442 for (i=0; i < n; i++)
3443 contribution[i].weight*=density;
3445 p=GetCacheViewVirtualPixels(image_view,contribution[0].pixel,0,(
size_t)
3446 (contribution[n-1].pixel-contribution[0].pixel+1),image->rows,exception);
3447 q=QueueCacheViewAuthenticPixels(resize_view,x,0,1,resize_image->rows,
3449 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3454 for (y=0; y < (ssize_t) resize_image->rows; y++)
3459 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3477 channel=GetPixelChannelChannel(image,i);
3478 traits=GetPixelChannelTraits(image,channel);
3479 resize_traits=GetPixelChannelTraits(resize_image,channel);
3480 if ((traits == UndefinedPixelTrait) ||
3481 (resize_traits == UndefinedPixelTrait))
3483 if (((resize_traits & CopyPixelTrait) != 0) ||
3484 (GetPixelWriteMask(resize_image,q) <= (QuantumRange/2)))
3486 j=(ssize_t) (MagickMin(MagickMax(bisect,(
double) start),(
double)
3488 k=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
3489 (contribution[j-start].pixel-contribution[0].pixel);
3490 SetPixelChannel(resize_image,channel,
3491 p[k*(ssize_t) GetPixelChannels(image)+i],q);
3495 if ((resize_traits & BlendPixelTrait) == 0)
3500 for (j=0; j < n; j++)
3502 k=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
3503 (contribution[j].pixel-contribution[0].pixel);
3504 alpha=contribution[j].weight;
3505 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3507 SetPixelChannel(resize_image,channel,ClampToQuantum(pixel),q);
3514 for (j=0; j < n; j++)
3516 k=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
3517 (contribution[j].pixel-contribution[0].pixel);
3518 alpha=contribution[j].weight*QuantumScale*
3519 (double) GetPixelAlpha(image,p+k*(ssize_t) GetPixelChannels(image));
3520 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3523 gamma=MagickSafeReciprocal(gamma);
3524 SetPixelChannel(resize_image,channel,ClampToQuantum(gamma*pixel),q);
3526 q+=(ptrdiff_t) GetPixelChannels(resize_image);
3528 if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
3530 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3535#if defined(MAGICKCORE_OPENMP_SUPPORT)
3539 proceed=SetImageProgress(image,ResizeImageTag,*progress,span);
3540 if (proceed == MagickFalse)
3544 resize_view=DestroyCacheView(resize_view);
3545 image_view=DestroyCacheView(image_view);
3546 contributions=DestroyContributionTLS(contributions);
3550static MagickBooleanType VerticalFilter(
3551 const ResizeFilter *magick_restrict resize_filter,
3552 const Image *magick_restrict image,Image *magick_restrict resize_image,
3553 const double y_factor,
const MagickSizeType span,
3554 MagickOffsetType *magick_restrict progress,ExceptionInfo *exception)
3564 **magick_restrict contributions;
3579 scale=MagickMax(1.0/y_factor+MagickEpsilon,1.0);
3580 support=scale*GetResizeFilterSupport(resize_filter);
3581 storage_class=support > 0.5 ? DirectClass : image->storage_class;
3582 if (SetImageStorageClass(resize_image,storage_class,exception) == MagickFalse)
3583 return(MagickFalse);
3589 support=(double) 0.5;
3592 contributions=AcquireContributionTLS((
size_t) (2.0*support+3.0));
3593 if (contributions == (ContributionInfo **) NULL)
3595 (void) ThrowMagickException(exception,GetMagickModule(),
3596 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",image->filename);
3597 return(MagickFalse);
3600 scale=MagickSafeReciprocal(scale);
3601 image_view=AcquireVirtualCacheView(image,exception);
3602 resize_view=AcquireAuthenticCacheView(resize_image,exception);
3603#if defined(MAGICKCORE_OPENMP_SUPPORT)
3604 #pragma omp parallel for schedule(static) shared(progress,status) \
3605 magick_number_threads(image,resize_image,resize_image->rows,1)
3607 for (y=0; y < (ssize_t) resize_image->rows; y++)
3610 id = GetOpenMPThreadId();
3616 *magick_restrict contribution;
3631 if (status == MagickFalse)
3633 bisect=(double) (y+0.5)/y_factor+MagickEpsilon;
3634 start=(ssize_t) MagickMax(bisect-support+0.5,0.0);
3635 stop=(ssize_t) MagickMin(bisect+support+0.5,(
double) image->rows);
3637 contribution=contributions[id];
3638 for (n=0; n < (stop-start); n++)
3640 contribution[n].pixel=start+n;
3641 contribution[n].weight=GetResizeFilterWeight(resize_filter,scale*
3642 ((
double) (start+n)-bisect+0.5));
3643 density+=contribution[n].weight;
3647 if ((density != 0.0) && (density != 1.0))
3655 density=MagickSafeReciprocal(density);
3656 for (i=0; i < n; i++)
3657 contribution[i].weight*=density;
3659 p=GetCacheViewVirtualPixels(image_view,0,contribution[0].pixel,
3660 image->columns,(
size_t) (contribution[n-1].pixel-contribution[0].pixel+1),
3662 q=QueueCacheViewAuthenticPixels(resize_view,0,y,resize_image->columns,1,
3664 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3669 for (x=0; x < (ssize_t) resize_image->columns; x++)
3674 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3692 channel=GetPixelChannelChannel(image,i);
3693 traits=GetPixelChannelTraits(image,channel);
3694 resize_traits=GetPixelChannelTraits(resize_image,channel);
3695 if ((traits == UndefinedPixelTrait) ||
3696 (resize_traits == UndefinedPixelTrait))
3698 if (((resize_traits & CopyPixelTrait) != 0) ||
3699 (GetPixelWriteMask(resize_image,q) <= (QuantumRange/2)))
3701 j=(ssize_t) (MagickMin(MagickMax(bisect,(
double) start),(
double)
3703 k=(ssize_t) ((contribution[j-start].pixel-contribution[0].pixel)*
3704 (ssize_t) image->columns+x);
3705 SetPixelChannel(resize_image,channel,p[k*(ssize_t)
3706 GetPixelChannels(image)+i],q);
3710 if ((resize_traits & BlendPixelTrait) == 0)
3715 for (j=0; j < n; j++)
3717 k=(ssize_t) ((contribution[j].pixel-contribution[0].pixel)*
3718 (ssize_t) image->columns+x);
3719 alpha=contribution[j].weight;
3720 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3722 SetPixelChannel(resize_image,channel,ClampToQuantum(pixel),q);
3726 for (j=0; j < n; j++)
3728 k=(ssize_t) ((contribution[j].pixel-contribution[0].pixel)*
3729 (ssize_t) image->columns+x);
3730 alpha=contribution[j].weight*QuantumScale*(double)
3731 GetPixelAlpha(image,p+k*(ssize_t) GetPixelChannels(image));
3732 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3735 gamma=MagickSafeReciprocal(gamma);
3736 SetPixelChannel(resize_image,channel,ClampToQuantum(gamma*pixel),q);
3738 q+=(ptrdiff_t) GetPixelChannels(resize_image);
3740 if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
3742 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3747#if defined(MAGICKCORE_OPENMP_SUPPORT)
3751 proceed=SetImageProgress(image,ResizeImageTag,*progress,span);
3752 if (proceed == MagickFalse)
3756 resize_view=DestroyCacheView(resize_view);
3757 image_view=DestroyCacheView(image_view);
3758 contributions=DestroyContributionTLS(contributions);
3762MagickExport Image *ResizeImage(
const Image *image,
const size_t columns,
3763 const size_t rows,
const FilterType filter,ExceptionInfo *exception)
3791 assert(image != (Image *) NULL);
3792 assert(image->signature == MagickCoreSignature);
3793 assert(exception != (ExceptionInfo *) NULL);
3794 assert(exception->signature == MagickCoreSignature);
3795 if (IsEventLogging() != MagickFalse)
3796 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3797 if ((columns == 0) || (rows == 0))
3798 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
3799 if ((columns == image->columns) && (rows == image->rows) &&
3800 (filter == UndefinedFilter))
3801 return(CloneImage(image,0,0,MagickTrue,exception));
3805 x_factor=(double) (columns*MagickSafeReciprocal((
double) image->columns));
3806 y_factor=(double) (rows*MagickSafeReciprocal((
double) image->rows));
3807 filter_type=LanczosFilter;
3808 if (filter != UndefinedFilter)
3811 if ((x_factor == 1.0) && (y_factor == 1.0))
3812 filter_type=PointFilter;
3814 if ((image->storage_class == PseudoClass) ||
3815 (image->alpha_trait != UndefinedPixelTrait) ||
3816 ((x_factor*y_factor) > 1.0))
3817 filter_type=MitchellFilter;
3818 resize_filter=AcquireResizeFilter(image,filter_type,MagickFalse,exception);
3819#if defined(MAGICKCORE_OPENCL_SUPPORT)
3820 resize_image=AccelerateResizeImage(image,columns,rows,resize_filter,
3822 if (resize_image != (Image *) NULL)
3824 resize_filter=DestroyResizeFilter(resize_filter);
3825 return(resize_image);
3828 resize_image=CloneImage(image,columns,rows,MagickTrue,exception);
3829 if (resize_image == (Image *) NULL)
3831 resize_filter=DestroyResizeFilter(resize_filter);
3832 return(resize_image);
3834 if (x_factor > y_factor)
3835 filter_image=CloneImage(image,columns,image->rows,MagickTrue,exception);
3837 filter_image=CloneImage(image,image->columns,rows,MagickTrue,exception);
3838 if (filter_image == (Image *) NULL)
3840 resize_filter=DestroyResizeFilter(resize_filter);
3841 return(DestroyImage(resize_image));
3847 if (x_factor > y_factor)
3849 span=(MagickSizeType) (filter_image->columns+rows);
3850 status=HorizontalFilter(resize_filter,image,filter_image,x_factor,span,
3852 status&=(MagickStatusType) VerticalFilter(resize_filter,filter_image,
3853 resize_image,y_factor,span,&offset,exception);
3857 span=(MagickSizeType) (filter_image->rows+columns);
3858 status=VerticalFilter(resize_filter,image,filter_image,y_factor,span,
3860 status&=(MagickStatusType) HorizontalFilter(resize_filter,filter_image,
3861 resize_image,x_factor,span,&offset,exception);
3866 filter_image=DestroyImage(filter_image);
3867 resize_filter=DestroyResizeFilter(resize_filter);
3868 if (status == MagickFalse)
3870 resize_image=DestroyImage(resize_image);
3871 return((Image *) NULL);
3873 resize_image->type=image->type;
3874 return(resize_image);
3908MagickExport Image *SampleImage(
const Image *image,
const size_t columns,
3909 const size_t rows,ExceptionInfo *exception)
3911#define SampleImageTag "Sample/Image"
3937 assert(image != (
const Image *) NULL);
3938 assert(image->signature == MagickCoreSignature);
3939 assert(exception != (ExceptionInfo *) NULL);
3940 assert(exception->signature == MagickCoreSignature);
3941 if (IsEventLogging() != MagickFalse)
3942 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3943 if ((columns == 0) || (rows == 0))
3944 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
3945 if ((columns == image->columns) && (rows == image->rows))
3946 return(CloneImage(image,0,0,MagickTrue,exception));
3947 sample_image=CloneImage(image,columns,rows,MagickTrue,exception);
3948 if (sample_image == (Image *) NULL)
3949 return((Image *) NULL);
3953 sample_offset.x=0.5-MagickEpsilon;
3954 sample_offset.y=sample_offset.x;
3959 value=GetImageArtifact(image,
"sample:offset");
3960 if (value != (
char *) NULL)
3968 (void) ParseGeometry(value,&geometry_info);
3969 flags=ParseGeometry(value,&geometry_info);
3970 sample_offset.x=sample_offset.y=geometry_info.rho/100.0-MagickEpsilon;
3971 if ((flags & SigmaValue) != 0)
3972 sample_offset.y=geometry_info.sigma/100.0-MagickEpsilon;
3978 x_offset=(ssize_t *) AcquireQuantumMemory((
size_t) sample_image->columns,
3980 if (x_offset == (ssize_t *) NULL)
3982 sample_image=DestroyImage(sample_image);
3983 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3985 for (j=0; j < (ssize_t) sample_image->columns; j++)
3986 x_offset[j]=(ssize_t) ((((double) j+sample_offset.x)*image->columns)/
3987 sample_image->columns);
3993 image_view=AcquireVirtualCacheView(image,exception);
3994 sample_view=AcquireAuthenticCacheView(sample_image,exception);
3995#if defined(MAGICKCORE_OPENMP_SUPPORT)
3996 #pragma omp parallel for schedule(static) shared(status) \
3997 magick_number_threads(image,sample_image,sample_image->rows,2)
3999 for (y=0; y < (ssize_t) sample_image->rows; y++)
4011 if (status == MagickFalse)
4013 y_offset=(ssize_t) ((((
double) y+sample_offset.y)*image->rows)/
4014 sample_image->rows);
4015 p=GetCacheViewVirtualPixels(image_view,0,y_offset,image->columns,1,
4017 q=QueueCacheViewAuthenticPixels(sample_view,0,y,sample_image->columns,1,
4019 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
4027 for (x=0; x < (ssize_t) sample_image->columns; x++)
4032 if (GetPixelWriteMask(sample_image,q) <= (QuantumRange/2))
4034 q+=(ptrdiff_t) GetPixelChannels(sample_image);
4037 for (i=0; i < (ssize_t) GetPixelChannels(sample_image); i++)
4046 channel=GetPixelChannelChannel(sample_image,i);
4047 traits=GetPixelChannelTraits(sample_image,channel);
4048 image_traits=GetPixelChannelTraits(image,channel);
4049 if ((traits == UndefinedPixelTrait) ||
4050 (image_traits == UndefinedPixelTrait))
4052 SetPixelChannel(sample_image,channel,p[x_offset[x]*(ssize_t)
4053 GetPixelChannels(image)+i],q);
4055 q+=(ptrdiff_t) GetPixelChannels(sample_image);
4057 if (SyncCacheViewAuthenticPixels(sample_view,exception) == MagickFalse)
4059 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4064 proceed=SetImageProgress(image,SampleImageTag,progress++,image->rows);
4065 if (proceed == MagickFalse)
4069 image_view=DestroyCacheView(image_view);
4070 sample_view=DestroyCacheView(sample_view);
4071 x_offset=(ssize_t *) RelinquishMagickMemory(x_offset);
4072 sample_image->type=image->type;
4073 if (status == MagickFalse)
4074 sample_image=DestroyImage(sample_image);
4075 return(sample_image);
4107MagickExport Image *ScaleImage(
const Image *image,
const size_t columns,
4108 const size_t rows,ExceptionInfo *exception)
4110#define ScaleImageTag "Scale/Image"
4118 pixel[CompositePixelChannel],
4149 assert(image != (
const Image *) NULL);
4150 assert(image->signature == MagickCoreSignature);
4151 assert(exception != (ExceptionInfo *) NULL);
4152 assert(exception->signature == MagickCoreSignature);
4153 if (IsEventLogging() != MagickFalse)
4154 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4155 if ((columns == 0) || (rows == 0))
4156 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
4157 if ((columns == image->columns) && (rows == image->rows))
4158 return(CloneImage(image,0,0,MagickTrue,exception));
4159 scale_image=CloneImage(image,columns,rows,MagickTrue,exception);
4160 if (scale_image == (Image *) NULL)
4161 return((Image *) NULL);
4162 if (SetImageStorageClass(scale_image,DirectClass,exception) == MagickFalse)
4164 scale_image=DestroyImage(scale_image);
4165 return((Image *) NULL);
4170 x_vector=(
double *) AcquireQuantumMemory((
size_t) image->columns,
4171 MaxPixelChannels*
sizeof(*x_vector));
4173 if (image->rows != scale_image->rows)
4174 scanline=(
double *) AcquireQuantumMemory((
size_t) image->columns,
4175 MaxPixelChannels*
sizeof(*scanline));
4176 scale_scanline=(
double *) AcquireQuantumMemory((
size_t) scale_image->columns,
4177 MaxPixelChannels*
sizeof(*scale_scanline));
4178 y_vector=(
double *) AcquireQuantumMemory((
size_t) image->columns,
4179 MaxPixelChannels*
sizeof(*y_vector));
4180 if ((scanline == (
double *) NULL) || (scale_scanline == (
double *) NULL) ||
4181 (x_vector == (
double *) NULL) || (y_vector == (
double *) NULL))
4183 if ((image->rows != scale_image->rows) && (scanline != (
double *) NULL))
4184 scanline=(
double *) RelinquishMagickMemory(scanline);
4185 if (scale_scanline != (
double *) NULL)
4186 scale_scanline=(
double *) RelinquishMagickMemory(scale_scanline);
4187 if (x_vector != (
double *) NULL)
4188 x_vector=(
double *) RelinquishMagickMemory(x_vector);
4189 if (y_vector != (
double *) NULL)
4190 y_vector=(
double *) RelinquishMagickMemory(y_vector);
4191 scale_image=DestroyImage(scale_image);
4192 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
4198 next_row=MagickTrue;
4200 scale.y=(double) scale_image->rows/(
double) image->rows;
4201 (void) memset(y_vector,0,(
size_t) MaxPixelChannels*image->columns*
4205 image_view=AcquireVirtualCacheView(image,exception);
4206 scale_view=AcquireAuthenticCacheView(scale_image,exception);
4207 for (y=0; y < (ssize_t) scale_image->rows; y++)
4218 if (status == MagickFalse)
4220 q=QueueCacheViewAuthenticPixels(scale_view,0,y,scale_image->columns,1,
4222 if (q == (Quantum *) NULL)
4228 if (scale_image->rows == image->rows)
4233 p=GetCacheViewVirtualPixels(image_view,0,n++,image->columns,1,
4235 if (p == (
const Quantum *) NULL)
4240 for (x=0; x < (ssize_t) image->columns; x++)
4242 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
4244 p+=(ptrdiff_t) GetPixelChannels(image);
4247 if (image->alpha_trait != UndefinedPixelTrait)
4248 alpha=QuantumScale*(double) GetPixelAlpha(image,p);
4249 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4251 PixelChannel channel = GetPixelChannelChannel(image,i);
4252 PixelTrait traits = GetPixelChannelTraits(image,channel);
4253 if ((traits & BlendPixelTrait) == 0)
4255 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=(double) p[i];
4258 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=alpha*(double) p[i];
4260 p+=(ptrdiff_t) GetPixelChannels(image);
4268 while (scale.y < span.y)
4270 if ((next_row != MagickFalse) &&
4271 (number_rows < (ssize_t) image->rows))
4276 p=GetCacheViewVirtualPixels(image_view,0,n++,image->columns,1,
4278 if (p == (
const Quantum *) NULL)
4283 for (x=0; x < (ssize_t) image->columns; x++)
4285 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
4287 p+=(ptrdiff_t) GetPixelChannels(image);
4290 if (image->alpha_trait != UndefinedPixelTrait)
4291 alpha=QuantumScale*(double) GetPixelAlpha(image,p);
4292 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4294 PixelChannel channel = GetPixelChannelChannel(image,i);
4295 PixelTrait traits = GetPixelChannelTraits(image,channel);
4296 if ((traits & BlendPixelTrait) == 0)
4298 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=
4302 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=alpha*
4305 p+=(ptrdiff_t) GetPixelChannels(image);
4309 for (x=0; x < (ssize_t) image->columns; x++)
4310 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4311 y_vector[x*(ssize_t) GetPixelChannels(image)+i]+=scale.y*
4312 x_vector[x*(ssize_t) GetPixelChannels(image)+i];
4314 scale.y=(double) scale_image->rows/(
double) image->rows;
4315 next_row=MagickTrue;
4317 if ((next_row != MagickFalse) && (number_rows < (ssize_t) image->rows))
4322 p=GetCacheViewVirtualPixels(image_view,0,n++,image->columns,1,
4324 if (p == (
const Quantum *) NULL)
4329 for (x=0; x < (ssize_t) image->columns; x++)
4331 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
4333 p+=(ptrdiff_t) GetPixelChannels(image);
4336 if (image->alpha_trait != UndefinedPixelTrait)
4337 alpha=QuantumScale*(double) GetPixelAlpha(image,p);
4338 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4340 PixelChannel channel = GetPixelChannelChannel(image,i);
4341 PixelTrait traits = GetPixelChannelTraits(image,channel);
4342 if ((traits & BlendPixelTrait) == 0)
4344 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=
4348 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=alpha*
4351 p+=(ptrdiff_t) GetPixelChannels(image);
4354 next_row=MagickFalse;
4356 for (x=0; x < (ssize_t) image->columns; x++)
4358 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4360 pixel[i]=y_vector[x*(ssize_t) GetPixelChannels(image)+i]+span.y*
4361 x_vector[x*(ssize_t) GetPixelChannels(image)+i];
4362 scanline[x*(ssize_t) GetPixelChannels(image)+i]=pixel[i];
4363 y_vector[x*(ssize_t) GetPixelChannels(image)+i]=0.0;
4369 scale.y=(double) scale_image->rows/(
double) image->rows;
4370 next_row=MagickTrue;
4374 if (scale_image->columns == image->columns)
4379 for (x=0; x < (ssize_t) scale_image->columns; x++)
4381 if (GetPixelWriteMask(scale_image,q) <= (QuantumRange/2))
4383 q+=(ptrdiff_t) GetPixelChannels(scale_image);
4386 if (image->alpha_trait != UndefinedPixelTrait)
4388 alpha=QuantumScale*scanline[x*(ssize_t) GetPixelChannels(image)+
4389 GetPixelChannelOffset(image,AlphaPixelChannel)];
4390 alpha=MagickSafeReciprocal(alpha);
4392 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4394 PixelChannel channel = GetPixelChannelChannel(image,i);
4395 PixelTrait traits = GetPixelChannelTraits(image,channel);
4396 scale_traits=GetPixelChannelTraits(scale_image,channel);
4397 if ((traits == UndefinedPixelTrait) ||
4398 (scale_traits == UndefinedPixelTrait))
4400 if ((traits & BlendPixelTrait) == 0)
4402 SetPixelChannel(scale_image,channel,ClampToQuantum(
4403 scanline[x*(ssize_t) GetPixelChannels(image)+i]),q);
4406 SetPixelChannel(scale_image,channel,ClampToQuantum(alpha*scanline[
4407 x*(ssize_t) GetPixelChannels(image)+i]),q);
4409 q+=(ptrdiff_t) GetPixelChannels(scale_image);
4420 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4422 next_column=MagickFalse;
4425 for (x=0; x < (ssize_t) image->columns; x++)
4427 scale.x=(double) scale_image->columns/(
double) image->columns;
4428 while (scale.x >= span.x)
4430 if (next_column != MagickFalse)
4432 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4436 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4438 PixelChannel channel = GetPixelChannelChannel(image,i);
4439 PixelTrait traits = GetPixelChannelTraits(image,channel);
4440 if (traits == UndefinedPixelTrait)
4442 pixel[i]+=span.x*scanline[x*(ssize_t) GetPixelChannels(image)+i];
4443 scale_scanline[t*(ssize_t) GetPixelChannels(image)+i]=pixel[i];
4447 next_column=MagickTrue;
4451 if (next_column != MagickFalse)
4453 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4455 next_column=MagickFalse;
4458 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4459 pixel[i]+=scale.x*scanline[x*(ssize_t)
4460 GetPixelChannels(image)+i];
4466 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4468 scanline[(x-1)*(ssize_t) GetPixelChannels(image)+i];
4470 if ((next_column == MagickFalse) && (t < (ssize_t) scale_image->columns))
4471 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4472 scale_scanline[t*(ssize_t) GetPixelChannels(image)+i]=pixel[i];
4476 for (x=0; x < (ssize_t) scale_image->columns; x++)
4478 if (GetPixelWriteMask(scale_image,q) <= (QuantumRange/2))
4480 q+=(ptrdiff_t) GetPixelChannels(scale_image);
4483 if (image->alpha_trait != UndefinedPixelTrait)
4485 alpha=QuantumScale*scale_scanline[x*(ssize_t)
4486 GetPixelChannels(image)+
4487 GetPixelChannelOffset(image,AlphaPixelChannel)];
4488 alpha=MagickSafeReciprocal(alpha);
4490 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4492 PixelChannel channel = GetPixelChannelChannel(image,i);
4493 PixelTrait traits = GetPixelChannelTraits(image,channel);
4494 scale_traits=GetPixelChannelTraits(scale_image,channel);
4495 if ((traits == UndefinedPixelTrait) ||
4496 (scale_traits == UndefinedPixelTrait))
4498 if ((traits & BlendPixelTrait) == 0)
4500 SetPixelChannel(scale_image,channel,ClampToQuantum(
4501 scale_scanline[x*(ssize_t) GetPixelChannels(image)+i]),q);
4504 SetPixelChannel(scale_image,channel,ClampToQuantum(alpha*
4505 scale_scanline[x*(ssize_t) GetPixelChannels(image)+i]),q);
4507 q+=(ptrdiff_t) GetPixelChannels(scale_image);
4510 if (SyncCacheViewAuthenticPixels(scale_view,exception) == MagickFalse)
4515 proceed=SetImageProgress(image,ScaleImageTag,(MagickOffsetType) y,
4517 if (proceed == MagickFalse)
4523 scale_view=DestroyCacheView(scale_view);
4524 image_view=DestroyCacheView(image_view);
4528 y_vector=(
double *) RelinquishMagickMemory(y_vector);
4529 scale_scanline=(
double *) RelinquishMagickMemory(scale_scanline);
4530 if (scale_image->rows != image->rows)
4531 scanline=(
double *) RelinquishMagickMemory(scanline);
4532 x_vector=(
double *) RelinquishMagickMemory(x_vector);
4533 scale_image->type=image->type;
4534 if (status == MagickFalse)
4535 scale_image=DestroyImage(scale_image);
4536 return(scale_image);
4571static void url_encode(
const char *uri,
char *encode_uri)
4577 *hex =
"0123456789ABCDEF";
4579 for (p=encode_uri; *uri !=
'\0'; uri++)
4580 if (((
'a' <= *uri) && (*uri <=
'z')) || ((
'A' <= *uri) && (*uri <=
'Z')) ||
4581 ((
'0' <= *uri) && (*uri <=
'9')) || (strchr(
"/-_.~",*uri) != 0))
4586 *p++=hex[(*uri >> 4) & 0xF];
4587 *p++=hex[*uri & 0xF];
4592MagickExport Image *ThumbnailImage(
const Image *image,
const size_t columns,
4593 const size_t rows,ExceptionInfo *exception)
4595#define SampleFactor 5
4598 encode_uri[3*MagickPathExtent+1] =
"/0";
4610 assert(image != (Image *) NULL);
4611 assert(image->signature == MagickCoreSignature);
4612 assert(exception != (ExceptionInfo *) NULL);
4613 assert(exception->signature == MagickCoreSignature);
4614 if (IsEventLogging() != MagickFalse)
4615 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4616 thumbnail_image=CloneImage(image,0,0,MagickTrue,exception);
4617 if (thumbnail_image == (Image *) NULL)
4618 return(thumbnail_image);
4619 if ((columns != image->columns) || (rows != image->rows))
4622 *clone_image = thumbnail_image;
4628 x_factor=(ssize_t) image->columns/(ssize_t) columns;
4629 y_factor=(ssize_t) image->rows/(ssize_t) rows;
4630 if ((x_factor > 4) && (y_factor > 4))
4632 thumbnail_image=SampleImage(clone_image,4*columns,4*rows,exception);
4633 if (thumbnail_image != (Image *) NULL)
4635 clone_image=DestroyImage(clone_image);
4636 clone_image=thumbnail_image;
4639 if ((x_factor > 2) && (y_factor > 2))
4641 thumbnail_image=ResizeImage(clone_image,2*columns,2*rows,BoxFilter,
4643 if (thumbnail_image != (Image *) NULL)
4645 clone_image=DestroyImage(clone_image);
4646 clone_image=thumbnail_image;
4649 thumbnail_image=ResizeImage(clone_image,columns,rows,image->filter ==
4650 UndefinedFilter ? LanczosSharpFilter : image->filter,exception);
4651 clone_image=DestroyImage(clone_image);
4652 if (thumbnail_image == (Image *) NULL)
4653 return(thumbnail_image);
4655 (void) ParseAbsoluteGeometry(
"0x0+0+0",&thumbnail_image->page);
4656 thumbnail_image->depth=8;
4657 thumbnail_image->interlace=NoInterlace;
4661 ResetImageProfileIterator(thumbnail_image);
4662 for (name=GetNextImageProfile(thumbnail_image); name != (
const char *) NULL; )
4664 if ((LocaleCompare(name,
"icc") != 0) && (LocaleCompare(name,
"icm") != 0))
4666 (void) DeleteImageProfile(thumbnail_image,name);
4667 ResetImageProfileIterator(thumbnail_image);
4669 name=GetNextImageProfile(thumbnail_image);
4671 (void) DeleteImageProperty(thumbnail_image,
"comment");
4672 url_encode(image->filename,encode_uri);
4673 if (*image->filename !=
'/')
4674 (void) FormatImageProperty(thumbnail_image,
"Thumb::URI",
"./%s",encode_uri);
4676 (
void) FormatImageProperty(thumbnail_image,
"Thumb::URI",
"file://%s",
4678 if (GetPathAttributes(image->filename,&attributes) != MagickFalse )
4679 (void) FormatImageProperty(thumbnail_image,
"Thumb::MTime",
"%.20g",(
double)
4680 attributes.st_mtime);
4681 (void) FormatImageProperty(thumbnail_image,
"Thumb::Size",
"%.20g",
4682 (
double) GetBlobSize(image));
4683 mime_type=GetImageProperty(image,
"mime:type",exception);
4684 if (mime_type != (
const char *) NULL)
4685 (void) SetImageProperty(thumbnail_image,
"Thumb::Mimetype",mime_type,
4687 (void) SetImageProperty(thumbnail_image,
"software",MagickAuthoritativeURL,
4689 (void) FormatImageProperty(thumbnail_image,
"Thumb::Image::Width",
"%.20g",
4690 (
double) image->magick_columns);
4691 (void) FormatImageProperty(thumbnail_image,
"Thumb::Image::Height",
"%.20g",
4692 (
double) image->magick_rows);
4693 (void) FormatImageProperty(thumbnail_image,
"Thumb::Document::Pages",
"%.20g",
4694 (
double) GetImageListLength(image));
4695 return(thumbnail_image);