234 static const float tbl[ 256 ] = {
235 0.0f, 0.000303527f, 0.000607054f, 0.000910581f, 0.001214108f,
236 0.001517635f, 0.001821162f, 0.002124689f, 0.002428216f, 0.002731743f,
237 0.00303527f, 0.003348383f, 0.003678029f, 0.004025973f, 0.004392482f,
238 0.004777817f, 0.005182236f, 0.005605992f, 0.006049334f, 0.006512507f,
239 0.006995751f, 0.007499306f, 0.008023403f, 0.008568275f, 0.009134147f,
240 0.009721244f, 0.01032979f, 0.01095999f, 0.01161207f, 0.01228625f,
241 0.01298271f, 0.01370169f, 0.01444337f, 0.01520795f, 0.01599565f,
242 0.01680664f, 0.01764113f, 0.01849931f, 0.01938136f, 0.02028748f,
243 0.02121784f, 0.02217263f, 0.02315203f, 0.02415622f, 0.02518537f,
244 0.02623966f, 0.02731927f, 0.02842436f, 0.0295551f, 0.03071166f,
245 0.0318942f, 0.0331029f, 0.03433791f, 0.03559939f, 0.03688751f,
246 0.03820243f, 0.03954429f, 0.04091326f, 0.04230949f, 0.04373313f,
247 0.04518433f, 0.04666325f, 0.04817003f, 0.04970482f, 0.05126777f,
248 0.05285903f, 0.05447873f, 0.05612702f, 0.05780404f, 0.05950994f,
249 0.06124485f, 0.06300892f, 0.06480227f, 0.06662506f, 0.0684774f,
250 0.07035945f, 0.07227132f, 0.07421317f, 0.07618511f, 0.07818728f,
251 0.08021981f, 0.08228283f, 0.08437647f, 0.08650086f, 0.08865612f,
252 0.09084239f, 0.09305977f, 0.09530841f, 0.09758843f, 0.09989995f,
253 0.1022431f, 0.104618f, 0.1070247f, 0.1094634f, 0.1119343f,
254 0.1144373f, 0.1169728f, 0.1195406f, 0.1221411f, 0.1247742f,
255 0.1274402f, 0.1301391f, 0.132871f, 0.1356361f, 0.1384344f,
256 0.1412662f, 0.1441314f, 0.1470303f, 0.1499628f, 0.1529292f,
257 0.1559296f, 0.158964f, 0.1620326f, 0.1651354f, 0.1682726f,
258 0.1714443f, 0.1746506f, 0.1778916f, 0.1811674f, 0.1844781f,
259 0.1878239f, 0.1912047f, 0.1946208f, 0.1980722f, 0.2015591f,
260 0.2050815f, 0.2086396f, 0.2122334f, 0.215863f, 0.2195286f,
261 0.2232303f, 0.2269681f, 0.2307422f, 0.2345526f, 0.2383994f,
262 0.2422828f, 0.2462029f, 0.2501597f, 0.2541534f, 0.258184f,
263 0.2622517f, 0.2663564f, 0.2704985f, 0.2746778f, 0.2788946f,
264 0.2831489f, 0.2874409f, 0.2917705f, 0.296138f, 0.3005433f,
265 0.3049867f, 0.3094681f, 0.3139877f, 0.3185456f, 0.3231419f,
266 0.3277766f, 0.3324498f, 0.3371618f, 0.3419124f, 0.3467019f,
267 0.3515303f, 0.3563977f, 0.3613041f, 0.3662498f, 0.3712348f,
268 0.3762591f, 0.3813228f, 0.3864261f, 0.391569f, 0.3967517f,
269 0.4019741f, 0.4072364f, 0.4125387f, 0.4178811f, 0.4232636f,
270 0.4286864f, 0.4341495f, 0.4396529f, 0.4451969f, 0.4507815f,
271 0.4564067f, 0.4620726f, 0.4677794f, 0.4735271f, 0.4793158f,
272 0.4851456f, 0.4910165f, 0.4969287f, 0.5028822f, 0.5088771f,
273 0.5149135f, 0.5209915f, 0.5271111f, 0.5332725f, 0.5394757f,
274 0.5457208f, 0.5520078f, 0.558337f, 0.5647082f, 0.5711217f,
275 0.5775775f, 0.5840756f, 0.5906162f, 0.5971993f, 0.6038251f,
276 0.6104935f, 0.6172047f, 0.6239587f, 0.6307557f, 0.6375956f,
277 0.6444787f, 0.6514048f, 0.6583742f, 0.665387f, 0.6724431f,
278 0.6795426f, 0.6866857f, 0.6938724f, 0.7011027f, 0.7083769f,
279 0.7156948f, 0.7230567f, 0.7304625f, 0.7379124f, 0.7454064f,
280 0.7529446f, 0.7605271f, 0.7681539f, 0.7758252f, 0.7835409f,
281 0.7913012f, 0.7991061f, 0.8069558f, 0.8148502f, 0.8227894f,
282 0.8307736f, 0.8388028f, 0.846877f, 0.8549964f, 0.8631609f,
283 0.8713707f, 0.8796259f, 0.8879265f, 0.8962726f, 0.9046642f,
284 0.9131014f, 0.9215843f, 0.930113f, 0.9386874f, 0.9473078f,
285 0.9559742f, 0.9646865f, 0.973445f, 0.9822496f, 0.9911004f,
288 return( tbl[ (
size_t) s0 ]);
4633 , ResBitDepth( aResBitDepth )
4635 SrcBitDepth = ( aSrcBitDepth == 0 ? ResBitDepth : aSrcBitDepth );
4637 initFilterBank( FixedFilterBank, 1.0,
false,
CFltBuffer() );
4638 FixedFilterBank.createAllFilters();
4680 template<
typename Tin,
typename Tout >
4682 const int SrcHeight,
int SrcScanlineSize, Tout*
const NewBuf,
4683 const int NewWidth,
const int NewHeight,
const int ElCountIO,
4686 if( SrcWidth == 0 || SrcHeight == 0 )
4688 memset( NewBuf, 0, (
size_t) NewWidth * (
size_t) NewHeight *
4694 if( NewWidth == 0 || NewHeight == 0 )
4711 double ox = Vars.
ox;
4712 double oy = Vars.
oy;
4716 kx = (double) SrcWidth / NewWidth;
4717 ox += ( kx - 1.0 ) * 0.5;
4719 ky = (double) SrcHeight / NewHeight;
4720 oy += ( ky - 1.0 ) * 0.5;
4728 const double ko = ( k - 1.0 ) * 0.5;
4740 const bool IsInFloat = ( (Tin) 0.25 != 0 );
4741 const bool IsOutFloat = ( (Tout) 0.25 != 0 );
4753 1.0 / (
sizeof( Tin ) == 1 ? 255.0 : 65535.0 );
4762 Vars.
OutGammaMult = (
sizeof( Tout ) == 1 ? 255.0 : 65535.0 );
4775 OutMul = (
sizeof( Tout ) == 1 ? 255.0 : 65535.0 );
4780 OutMul /= (
sizeof( Tin ) == 1 ? 255.0 : 65535.0 );
4786 const int ElCount = ( ElCountIO + fpclass :: fppack - 1 ) /
4789 const int NewWidthE = NewWidth * ElCount;
4791 if( SrcScanlineSize < 1 )
4793 SrcScanlineSize = SrcWidth * ElCountIO;
4798 Vars.
fppack = fpclass :: fppack;
4799 Vars.
fpalign = fpclass :: fpalign;
4800 Vars.
elalign = fpclass :: elalign;
4801 Vars.
packmode = fpclass :: packmode;
4806 CFilterSteps FltSteps;
4807 typename CFilterStep :: CRPosBufArray RPosBufArray;
4813 int UseBuildMode = 1;
4814 const int BuildModeCount =
4815 ( FixedFilterBank.getOrder() == 0 ? 4 : 2 );
4825 int BestScore = 0x7FFFFFFF;
4827 for( m = 0; m < BuildModeCount; m++ )
4830 CFilterSteps TmpSteps;
4833 buildFilterSteps( TmpSteps, Vars, TmpBank, OutMul, m,
true );
4834 updateFilterStepBuffers( TmpSteps, Vars, RPosBufArray,
4835 SrcWidth, NewWidth );
4837 fillUsedFracMap( TmpSteps[ Vars.
ResizeStep ], UsedFracMap );
4838 const int c = calcComplexity( TmpSteps, Vars, UsedFracMap,
4853 buildFilterSteps( FltSteps, Vars, FltBank, OutMul, UseBuildMode,
4856 updateFilterStepBuffers( FltSteps, Vars, RPosBufArray, SrcWidth,
4859 updateBufLenAndRPosPtrs( FltSteps, Vars, NewWidth );
4868 for( i = 0; i < ThreadCount; i++ )
4875 td[ i ].init( i, ThreadCount, FltSteps, Vars );
4877 td[ i ].initScanlineQueue( td[ i ].sopResizeH, SrcHeight,
4882 (
size_t) SrcHeight, fpclass :: fpalign );
4885 for( i = 0; i < SrcHeight; i++ )
4887 td[ i % ThreadCount ].addScanlineToQueue(
4888 (
void*) &SrcBuf[ (
size_t) i * (
size_t) SrcScanlineSize ],
4889 &FltBuf[ (
size_t) i * (
size_t) NewWidthE ]);
4893 td[ 0 ].processScanlineQueue();
4899 const int PrevUseBuildMode = UseBuildMode;
4908 int BestScore = 0x7FFFFFFF;
4910 for( m = 0; m < BuildModeCount; m++ )
4914 CFilterSteps TmpSteps;
4917 buildFilterSteps( TmpSteps, TmpVars, TmpBank, 1.0, m,
true );
4918 updateFilterStepBuffers( TmpSteps, TmpVars, RPosBufArray,
4919 SrcHeight, NewHeight );
4921 fillUsedFracMap( TmpSteps[ TmpVars.
ResizeStep ],
4924 const int c = calcComplexity( TmpSteps, TmpVars, UsedFracMap,
4938 if( UseBuildMode == PrevUseBuildMode && ky == kx )
4942 modifyCorrFilterDCGain( FltSteps, 1.0 / OutMul );
4947 buildFilterSteps( FltSteps, Vars, FltBank, 1.0, UseBuildMode,
4951 updateFilterStepBuffers( FltSteps, Vars, RPosBufArray, SrcHeight,
4954 updateBufLenAndRPosPtrs( FltSteps, Vars, NewWidth );
4956 if( IsOutFloat &&
sizeof( FltBuf[ 0 ]) ==
sizeof( Tout ) &&
4957 fpclass :: packmode == 0 )
4961 for( i = 0; i < ThreadCount; i++ )
4963 td[ i ].initScanlineQueue( td[ i ].sopResizeV, NewWidth,
4964 SrcHeight, NewWidthE, NewWidthE );
4967 for( i = 0; i < NewWidth; i++ )
4969 td[ i % ThreadCount ].addScanlineToQueue(
4970 &FltBuf[ i * ElCount ], (fptype*) &NewBuf[ i * ElCount ]);
4974 td[ 0 ].processScanlineQueue();
4982 (
size_t) NewHeight, fpclass :: fpalign );
4984 for( i = 0; i < ThreadCount; i++ )
4986 td[ i ].initScanlineQueue( td[ i ].sopResizeV, NewWidth,
4987 SrcHeight, NewWidthE, NewWidthE );
4990 const int im = ( fpclass :: packmode == 0 ? ElCount : 1 );
4992 for( i = 0; i < NewWidth; i++ )
4994 td[ i % ThreadCount ].addScanlineToQueue(
4995 &FltBuf[ i * im ], &ResBuf[ i * im ]);
4999 td[ 0 ].processScanlineQueue();
5006 for( i = 0; i < ThreadCount; i++ )
5008 td[ i ].initScanlineQueue( td[ i ].sopUnpackH,
5009 NewHeight, NewWidth );
5012 for( i = 0; i < NewHeight; i++ )
5014 td[ i % ThreadCount ].addScanlineToQueue(
5015 &ResBuf[ (
size_t) i * (
size_t) NewWidthE ],
5016 &NewBuf[ (
size_t) i * (
size_t) ( NewWidth * ElCountIO )]);
5020 td[ 0 ].processScanlineQueue();
5032 if(
sizeof( Tout ) == 1 )
5034 TruncBits = 8 - ResBitDepth;
5039 TruncBits = 16 - ResBitDepth;
5043 const double PkOut = OutRange;
5044 const double TrMul = ( TruncBits > 0 ?
5045 PkOut / ( OutRange >> TruncBits ) : 1.0 );
5047 if( CDitherer :: isRecursive() )
5049 td[ 0 ].getDitherer().init( NewWidth, Vars, TrMul, PkOut );
5051 for( i = 0; i < NewHeight; i++ )
5053 fptype*
const ResScanline =
5054 &ResBuf[ (size_t) i * (
size_t) NewWidthE ];
5058 CFilterStep :: applySRGBGamma( ResScanline, NewWidth,
5062 td[ 0 ].getDitherer().dither( ResScanline );
5064 CFilterStep :: unpackScanline( ResScanline,
5065 &NewBuf[ (
size_t) i * (
size_t) ( NewWidth * ElCountIO )],
5071 for( i = 0; i < ThreadCount; i++ )
5073 td[ i ].initScanlineQueue( td[ i ].sopDitherAndUnpackH,
5074 NewHeight, NewWidth );
5076 td[ i ].getDitherer().init( NewWidth, Vars, TrMul, PkOut );
5079 for( i = 0; i < NewHeight; i++ )
5081 td[ i % ThreadCount ].addScanlineToQueue(
5082 &ResBuf[ (
size_t) i * (
size_t) NewWidthE ],
5083 &NewBuf[ (
size_t) i * (
size_t) ( NewWidth * ElCountIO )]);
5087 td[ 0 ].processScanlineQueue();
5095 typedef typename fpclass :: fptype fptype;
5097 typedef typename fpclass :: CFilterStep CFilterStep;
5099 typedef typename fpclass :: CDitherer CDitherer;
5129 const double CutoffMult,
const bool ForceHiOrder,
5132 const int IntBitDepth = ( ResBitDepth > SrcBitDepth ? ResBitDepth :
5135 const double SNR = -6.02 * ( IntBitDepth + 3 );
5145 if( ForceHiOrder || IntBitDepth > 8 )
5148 FracCount = (int) ceil( 0.23134052 * exp( -0.058062929 * SNR ));
5153 FracCount = (int) ceil( 0.33287686 * exp( -0.11334583 * SNR ));
5161 FltBank.
init( FracCount, UseOrder, Params.IntFltLen / CutoffMult,
5162 Params.IntFltCutoff * CutoffMult, Params.IntFltAlpha, ExtFilter,
5163 fpclass :: fpalign, fpclass :: elalign );
5181 static void allocFilter( CBuffer< fptype >& Flt,
const int ReqCapacity,
5182 const bool IsModel =
false,
int*
const FltExt =
nullptr )
5184 int UseCapacity = ( ReqCapacity + fpclass :: elalign - 1 ) &
5185 ~( fpclass :: elalign - 1 );
5187 int Ext = UseCapacity - ReqCapacity;
5189 if( FltExt !=
nullptr )
5196 Flt.forceCapacity( UseCapacity );
5200 Flt.alloc( UseCapacity, fpclass :: fpalign );
5205 Flt[ ReqCapacity + Ext ] = 0;
5231 void assignFilterParams( CFilterStep& fs,
const bool IsUpsample,
5232 const int ResampleFactor,
const double FltCutoff,
const double DCGain,
5233 const bool UseFltOrig,
const bool IsModel )
const
5239 if( FltCutoff == 0.0 )
5241 const double m = 2.0 / ResampleFactor;
5242 FltAlpha = Params.HBFltAlpha;
5243 Len2 = 0.5 * Params.HBFltLen / m;
5244 Freq =
AVIR_PI * Params.HBFltCutoff * m;
5248 FltAlpha = Params.LPFltAlpha;
5249 Len2 = 0.25 * Params.LPFltBaseLen / FltCutoff;
5250 Freq =
AVIR_PI * Params.LPFltCutoffMult * FltCutoff;
5255 Len2 *= ResampleFactor;
5256 Freq /= ResampleFactor;
5257 fs.DCGain = DCGain * ResampleFactor;
5264 fs.FltOrig.Len2 = Len2;
5265 fs.FltOrig.Freq = Freq;
5266 fs.FltOrig.Alpha = FltAlpha;
5267 fs.FltOrig.DCGain = fs.DCGain;
5269 CDSPPeakedCosineLPF w( Len2, Freq, FltAlpha );
5271 fs.IsUpsample = IsUpsample;
5272 fs.ResampleFactor = ResampleFactor;
5273 fs.FltLatency = w.fl2;
5279 allocFilter( fs.Flt, w.FilterLen,
true, &FltExt );
5286 fs.FltOrig.alloc( w.FilterLen );
5287 memset( &fs.FltOrig[ 0 ], 0,
5288 (
size_t) w.FilterLen *
sizeof( fs.FltOrig[ 0 ]));
5293 fs.FltOrig.alloc( w.FilterLen );
5295 w.generateLPF( &fs.FltOrig[ 0 ], fs.DCGain );
5297 allocFilter( fs.Flt, fs.FltOrig.getCapacity(),
false, &FltExt );
5298 copyArray( &fs.FltOrig[ 0 ], &fs.Flt[ 0 ],
5299 fs.FltOrig.getCapacity() );
5309 int l = fs.Flt.getCapacity() - fs.FltLatency - ResampleFactor -
5312 allocFilter( fs.PrefixDC, l, IsModel );
5313 allocFilter( fs.SuffixDC, fs.FltLatency, IsModel );
5322 const fptype* ip = &fs.Flt[ fs.FltLatency + ResampleFactor ];
5327 ip += ResampleFactor;
5328 l -= ResampleFactor;
5335 addArray( ip, &fs.PrefixDC[ 0 ], l );
5339 fptype* op = &fs.SuffixDC[ 0 ];
5344 op += ResampleFactor;
5345 l -= ResampleFactor;
5358 fs.EdgePixelCount = fs.EdgePixelCountDef;
5384 void addCorrectionFilter( CFilterSteps& Steps,
const double bw,
5385 const bool IsPreCorrection,
const bool IsModel )
const
5387 CFilterStep& nfs = ( IsPreCorrection ? Steps[ 0 ] : Steps.add() );
5388 nfs.IsUpsample =
false;
5389 nfs.ResampleFactor = 1;
5391 nfs.EdgePixelCount = ( IsPreCorrection ? nfs.EdgePixelCountDef : 0 );
5395 allocFilter( nfs.Flt, CDSPFIREQ :: calcFilterLength(
5396 Params.CorrFltLen, nfs.FltLatency ),
true );
5401 const int BinCount = 65;
5402 const int BinCount1 = BinCount - 1;
5409 CBuffer< double > Bins( BinCount );
5412 for( j = 0; j < BinCount; j++ )
5417 const int si = ( IsPreCorrection ? 1 : 0 );
5419 for( i = si; i < Steps.getItemCount() - ( si ^ 1 ); i++ )
5421 const CFilterStep& fs = Steps[ i ];
5425 curbw *= fs.ResampleFactor;
5427 if( fs.FltOrig.getCapacity() > 0 )
5436 if( fs.ResampleFactor == 0 )
5438 if( fs.FltBankDyn ==
nullptr )
5440 Flt = fs.FltBank -> getFilterConst( 0 );
5441 FltLen = fs.FltBank -> getFilterLen();
5445 Flt = fs.FltBankDyn -> getFilter( 0 );
5446 FltLen = fs.FltBankDyn -> getFilterLen();
5452 FltLen = fs.Flt.getCapacity();
5459 const double thm =
AVIR_PI * bw / ( curbw * BinCount1 );
5461 for( j = 0; j < BinCount; j++ )
5465 Bins[ j ] *= fs.DCGain / sqrt( re * re + im * im );
5468 if( !fs.IsUpsample && fs.ResampleFactor > 1 )
5470 curbw /= fs.ResampleFactor;
5477 EQ.init( bw * 2.0, Params.CorrFltLen, BinCount, 0.0, bw,
false,
5478 Params.CorrFltAlpha );
5480 nfs.FltLatency = EQ.getFilterLatency();
5482 CBuffer< double > Filter( EQ.getFilterLength() );
5483 EQ.buildFilter( Bins, &Filter[ 0 ]);
5486 allocFilter( nfs.Flt, Filter.getCapacity() );
5487 copyArray( &Filter[ 0 ], &nfs.Flt[ 0 ], Filter.getCapacity() );
5526 static void addSharpenTest( CFilterSteps& Steps,
const double bw,
5527 const bool IsModel )
5534 const double FltLen = 10.0 * bw;
5536 CFilterStep& fs = Steps.add();
5537 fs.IsUpsample =
false;
5538 fs.ResampleFactor = 1;
5540 fs.EdgePixelCount = 0;
5544 allocFilter( fs.Flt, CDSPFIREQ :: calcFilterLength( FltLen,
5545 fs.FltLatency ),
true );
5550 const int BinCount = 200;
5551 CBuffer< double > Bins( BinCount );
5552 int Thresh = (int)
round( BinCount / bw * 1.75 );
5554 if( Thresh > BinCount )
5561 for( j = 0; j < Thresh; j++ )
5566 for( j = Thresh; j < BinCount; j++ )
5572 EQ.init( bw * 2.0, FltLen, BinCount, 0.0, bw,
false, 1.7 );
5574 fs.FltLatency = EQ.getFilterLatency();
5576 CBuffer< double > Filter( EQ.getFilterLength() );
5577 EQ.buildFilter( Bins, &Filter[ 0 ]);
5580 allocFilter( fs.Flt, Filter.getCapacity() );
5581 copyArray( &Filter[ 0 ], &fs.Flt[ 0 ], Filter.getCapacity() );
5616 void buildFilterSteps( CFilterSteps& Steps, CImageResizerVars& Vars,
5617 CDSPFracFilterBankLin< fptype >& FltBank,
const double DCGain,
5618 const int ModeFlags,
const bool IsModel )
const
5622 const bool DoFltAndIntCombo = (( ModeFlags & 1 ) != 0 );
5624 const bool ForceHiOrderInt = (( ModeFlags & 2 ) != 0 );
5626 const bool UseHalfband = (( ModeFlags & 4 ) != 0 );
5629 const double bw = 1.0 / Vars.k;
5630 const int UpsampleFactor = ( (int) floor( Vars.k ) < 2 ? 2 : 1 );
5631 double IntCutoffMult;
5632 CFilterStep* ReuseStep;
5634 CFilterStep* ExtFltStep;
5636 bool IsPreCorrection;
5643 IsPreCorrection =
true;
5650 IsPreCorrection =
false;
5657 if( UpsampleFactor > 1 )
5659 CFilterStep& fs = Steps.add();
5660 assignFilterParams( fs,
true, UpsampleFactor, FltCutoff, DCGain,
5661 DoFltAndIntCombo, IsModel );
5663 IntCutoffMult = FltCutoff * 2.0 / UpsampleFactor;
5664 ReuseStep =
nullptr;
5665 ExtFltStep = ( DoFltAndIntCombo ? &fs : nullptr );
5669 int DownsampleFactor;
5673 DownsampleFactor = (int) floor( 0.5 / FltCutoff );
5674 bool DoHBFltAdd = ( UseHalfband && DownsampleFactor > 1 );
5678 assignFilterParams( Steps.add(),
false, DownsampleFactor,
5679 0.0, 1.0,
false, IsModel );
5681 FltCutoff *= DownsampleFactor;
5685 if( DownsampleFactor < 1 )
5687 DownsampleFactor = 1;
5694 CFilterStep& fs = Steps.add();
5695 assignFilterParams( fs,
false, DownsampleFactor, FltCutoff,
5696 DCGain, DoFltAndIntCombo, IsModel );
5698 IntCutoffMult = FltCutoff / 0.5;
5700 if( DoFltAndIntCombo )
5707 IntCutoffMult *= DownsampleFactor;
5708 ReuseStep =
nullptr;
5709 ExtFltStep =
nullptr;
5715 CFilterStep& fs = ( ReuseStep ==
nullptr ? Steps.add() : *ReuseStep );
5717 Vars.ResizeStep = Steps.getItemCount() - 1;
5718 fs.IsUpsample =
false;
5719 fs.ResampleFactor = 0;
5720 fs.DCGain = ( ExtFltStep ==
nullptr ? 1.0 : ExtFltStep -> DCGain );
5722 initFilterBank( FltBank, IntCutoffMult, ForceHiOrderInt,
5723 ( ExtFltStep ==
nullptr ? fs.FltOrig : ExtFltStep -> FltOrig ));
5725 if( FltBank == FixedFilterBank )
5727 fs.FltBank = &FixedFilterBank;
5728 fs.FltBankDyn =
nullptr;
5732 fs.FltBank = &FltBank;
5733 fs.FltBankDyn = &FltBank;
5736 addCorrectionFilter( Steps, corrbw, IsPreCorrection, IsModel );
5753 static void extendUpsample( CFilterStep& fs, CFilterStep& NextStep )
5755 fs.InPrefix = ( NextStep.InPrefix + fs.ResampleFactor - 1 ) /
5758 fs.OutPrefix += fs.InPrefix * fs.ResampleFactor;
5759 NextStep.InPrefix = 0;
5761 fs.InSuffix = ( NextStep.InSuffix + fs.ResampleFactor - 1 ) /
5764 fs.OutSuffix += fs.InSuffix * fs.ResampleFactor;
5765 NextStep.InSuffix = 0;
5782 static void fillRPosBuf( CFilterStep& fs,
const CImageResizerVars& Vars )
5784 const int PrevLen = fs.RPosBuf -> getCapacity();
5786 if( fs.OutLen > PrevLen )
5788 fs.RPosBuf -> increaseCapacity( fs.OutLen );
5791 typename CFilterStep :: CResizePos* rpos = &(*fs.RPosBuf)[ PrevLen ];
5792 const int FracCount = fs.FltBank -> getFracCount();
5793 const double o = Vars.o;
5794 const double k = Vars.k;
5797 for( i = PrevLen; i < fs.OutLen; i++ )
5799 const double SrcPos = o + k * i;
5800 const int SrcPosInt = (int) floor( SrcPos );
5801 const double x = ( SrcPos - SrcPosInt ) * FracCount;
5802 const int fti = (int) x;
5803 rpos -> x = (
typename fpclass :: fptypeatom) ( x - fti );
5805 rpos -> SrcPosInt = SrcPosInt;
5827 static void updateFilterStepBuffers( CFilterSteps& Steps,
5828 CImageResizerVars& Vars,
5829 typename CFilterStep :: CRPosBufArray& RPosBufArray,
int SrcLen,
5836 for( i = 0; i < Steps.getItemCount(); i++ )
5838 CFilterStep& fs = Steps[ i ];
5843 fs.OutBuf = ( InBuf + 1 ) & 1;
5848 Vars.k *= fs.ResampleFactor;
5849 Vars.o *= fs.ResampleFactor;
5852 fs.OutLen = fs.InLen * fs.ResampleFactor;
5853 fs.OutPrefix = fs.FltLatency;
5854 fs.OutSuffix = fs.Flt.getCapacity() - fs.FltLatency -
5857 int l0 = fs.OutPrefix + fs.OutLen + fs.OutSuffix;
5858 int l = fs.InLen * fs.ResampleFactor +
5859 fs.SuffixDC.getCapacity();
5863 fs.OutSuffix += l - l0;
5866 l0 = fs.OutLen + fs.OutSuffix;
5868 if( fs.PrefixDC.getCapacity() > l0 )
5870 fs.OutSuffix += fs.PrefixDC.getCapacity() - l0;
5874 if( fs.ResampleFactor == 0 )
5876 const int FilterLenD2 = fs.FltBank -> getFilterLen() / 2;
5877 const int FilterLenD21 = FilterLenD2 - 1;
5879 const int ResizeLPix = (int) floor( Vars.o ) - FilterLenD21;
5880 fs.InPrefix = ( ResizeLPix < 0 ? -ResizeLPix : 0 );
5881 const int ResizeRPix = (int) floor( Vars.o +
5882 ( NewLen - 1 ) * Vars.k ) + FilterLenD2 + 1;
5884 fs.InSuffix = ( ResizeRPix > fs.InLen ?
5885 ResizeRPix - fs.InLen : 0 );
5888 fs.RPosBuf = &RPosBufArray.getRPosBuf( Vars.k, Vars.o,
5889 fs.FltBank -> getFracCount() );
5891 fillRPosBuf( fs, Vars );
5895 Vars.k /= fs.ResampleFactor;
5896 Vars.o /= fs.ResampleFactor;
5897 Vars.o += fs.EdgePixelCount;
5899 fs.InPrefix = fs.FltLatency;
5900 fs.InSuffix = fs.Flt.getCapacity() - fs.FltLatency - 1;
5905 fs.OutLen = ( fs.InLen + fs.ResampleFactor - 1 ) /
5906 fs.ResampleFactor + fs.EdgePixelCount;
5908 fs.InSuffix += ( fs.OutLen - 1 ) * fs.ResampleFactor + 1 -
5911 fs.InPrefix += fs.EdgePixelCount * fs.ResampleFactor;
5912 fs.OutLen += fs.EdgePixelCount;
5919 Steps[ Steps.getItemCount() - 1 ].OutBuf = 2;
5920 Vars.IsResize2 =
false;
5924 extendUpsample( Steps[ upstep ], Steps[ upstep + 1 ]);
5926 if( Steps[ upstep ].ResampleFactor == 2 &&
5927 Vars.ResizeStep == upstep + 1 &&
5928 fpclass :: packmode == 0 &&
5929 Steps[ upstep ].FltOrig.getCapacity() > 0 )
5934 Vars.IsResize2 =
true;
5957 static void updateBufLenAndRPosPtrs( CFilterSteps& Steps,
5958 CImageResizerVars& Vars,
const int ResElIncr )
5960 int MaxPrefix[ 2 ] = { 0, 0 };
5961 int MaxLen[ 2 ] = { 0, 0 };
5964 for( i = 0; i < Steps.getItemCount(); i++ )
5966 CFilterStep& fs = Steps[ i ];
5967 const int ib = fs.InBuf;
5969 if( fs.InPrefix > MaxPrefix[ ib ])
5971 MaxPrefix[ ib ] = fs.InPrefix;
5974 int l = fs.InLen + fs.InSuffix;
5976 if( l > MaxLen[ ib ])
5981 fs.InElIncr = fs.InPrefix + l;
5983 if( fs.OutBuf == 2 )
5988 const int ob = fs.OutBuf;
5992 if( fs.OutPrefix > MaxPrefix[ ob ])
5994 MaxPrefix[ ob ] = fs.OutPrefix;
5997 l = fs.OutLen + fs.OutSuffix;
5999 if( l > MaxLen[ ob ])
6006 if( fs.OutLen > MaxLen[ ob ])
6008 MaxLen[ ob ] = fs.OutLen;
6015 for( i = 0; i < Steps.getItemCount(); i++ )
6017 CFilterStep& fs = Steps[ i ];
6019 if( fs.OutBuf == 2 )
6021 fs.OutElIncr = ResElIncr;
6025 CFilterStep& fs2 = Steps[ i + 1 ];
6029 fs.OutElIncr = fs.OutPrefix + fs.OutLen + fs.OutSuffix;
6031 if( fs.OutElIncr > fs2.InElIncr )
6033 fs2.InElIncr = fs.OutElIncr;
6037 fs.OutElIncr = fs2.InElIncr;
6042 fs.OutElIncr = fs2.InElIncr;
6048 for( i = 0; i < 2; i++ )
6050 Vars.BufLen[ i ] = MaxPrefix[ i ] + MaxLen[ i ];
6051 Vars.BufOffs[ i ] = MaxPrefix[ i ];
6053 if( Vars.packmode == 0 )
6055 Vars.BufOffs[ i ] *= Vars.ElCount;
6058 Vars.BufLen[ i ] *= Vars.ElCount;
6063 CFilterStep& fs = Steps[ Vars.ResizeStep ];
6064 typename CFilterStep :: CResizePos* rpos = &(*fs.RPosBuf)[ 0 ];
6065 const int em = ( fpclass :: packmode == 0 ? Vars.ElCount : 1 );
6066 const int fl = ( fs.FltBankDyn ==
nullptr ?
6067 fs.FltBank -> getFilterLen() : fs.FltBankDyn -> getFilterLen() );
6069 const int FilterLenD21 = fl / 2 - 1;
6071 if( Vars.IsResize2 )
6073 if( fs.FltBankDyn == nullptr )
6075 for( i = 0; i < fs.OutLen; i++ )
6077 const int p = rpos -> SrcPosInt - FilterLenD21;
6078 const int fo = p & 1;
6079 rpos -> SrcOffs = ( p + fo ) * em;
6080 rpos -> ftp = fs.FltBank -> getFilterConst(
6083 rpos -> fl = fl - fo;
6089 for( i = 0; i < fs.OutLen; i++ )
6091 const int p = rpos -> SrcPosInt - FilterLenD21;
6092 const int fo = p & 1;
6093 rpos -> SrcOffs = ( p + fo ) * em;
6094 rpos -> ftp = fs.FltBankDyn -> getFilter(
6097 rpos -> fl = fl - fo;
6104 if( fs.FltBankDyn ==
nullptr )
6106 for( i = 0; i < fs.OutLen; i++ )
6108 rpos -> SrcOffs = ( rpos -> SrcPosInt -
6109 FilterLenD21 ) * em;
6111 rpos -> ftp = fs.FltBank -> getFilterConst( rpos -> fti );
6117 for( i = 0; i < fs.OutLen; i++ )
6119 rpos -> SrcOffs = ( rpos -> SrcPosInt -
6120 FilterLenD21 ) * em;
6122 rpos -> ftp = fs.FltBankDyn -> getFilter( rpos -> fti );
6137 void modifyCorrFilterDCGain( CFilterSteps& Steps,
const double m )
const
6139 CBuffer< fptype >* Flt;
6140 const int z = Steps.getItemCount() - 1;
6142 if( !Steps[ z ].IsUpsample && Steps[ z ].ResampleFactor == 1 )
6144 Flt = &Steps[ z ].Flt;
6148 Flt = &Steps[ 0 ].Flt;
6153 for( i = 0; i < Flt -> getCapacity(); i++ )
6155 (*Flt)[ i ] = (fptype) ( (
double) (*Flt)[ i ] * m );
6167 static void fillUsedFracMap(
const CFilterStep& fs,
6168 CBuffer< char >& UsedFracMap )
6170 const int FracCount = fs.FltBank -> getFracCount();
6171 UsedFracMap.increaseCapacity( FracCount,
false );
6172 memset( &UsedFracMap[ 0 ], 0,
6173 (
size_t) FracCount *
sizeof( UsedFracMap[ 0 ]));
6175 typename CFilterStep :: CResizePos* rpos = &(*fs.RPosBuf)[ 0 ];
6178 for( i = 0; i < fs.OutLen; i++ )
6180 UsedFracMap[ rpos -> fti ] |= 1;
6206 static int calcComplexity(
const CFilterSteps& Steps,
6207 const CImageResizerVars& Vars,
const CBuffer< char >& UsedFracMap,
6208 const int ScanlineCount )
6213 if( Vars.packmode != 0 )
6231 for( i = 0; i < Steps.getItemCount(); i++ )
6233 const CFilterStep& fs = Steps[ i ];
6235 s2 += 65 * fs.Flt.getCapacity();
6239 if( fs.FltOrig.getCapacity() > 0 )
6244 s += ( fs.Flt.getCapacity() *
6245 ( fs.InPrefix + fs.InLen + fs.InSuffix ) +
6246 fs.SuffixDC.getCapacity() + fs.PrefixDC.getCapacity() ) *
6250 if( fs.ResampleFactor == 0 )
6252 s += fs.FltBank -> getFilterLen() *
6253 ( fs.FltBank -> getOrder() + Vars.ElCount ) * fs.OutLen;
6255 if( i == Vars.ResizeStep && Vars.IsResize2 )
6260 s2 += fs.FltBank -> calcInitComplexity( UsedFracMap );
6264 s += fs.Flt.getCapacity() * Vars.ElCount * fs.OutLen *
6269 return( s + s2 / ScanlineCount );
6284 template<
typename Tin,
typename Tout >
6285 class CThreadData :
public CImageResizerThreadPool :: CWorkload
6288 virtual void process()
6289 #if __cplusplus >= 201103L
6293 processScanlineQueue();
6300 enum EScanlineOperation
6304 sopDitherAndUnpackH,
6318 void init(
const int aThreadIndex,
const int aThreadCount,
6319 const CFilterSteps& aSteps,
const CImageResizerVars& aVars )
6321 ThreadIndex = aThreadIndex;
6322 ThreadCount = aThreadCount;
6341 void initScanlineQueue(
const EScanlineOperation aOp,
6342 const int TotalLines,
const int aSrcLen,
const int aSrcIncr = 0,
6343 const int aResIncr = 0 )
6345 const int l = Vars -> BufLen[ 0 ] + Vars -> BufLen[ 1 ];
6347 if( Bufs.getCapacity() < l )
6349 Bufs.alloc( l, fpclass :: fpalign );
6352 BufPtrs[ 0 ] = Bufs + Vars -> BufOffs[ 0 ];
6353 BufPtrs[ 1 ] = Bufs + Vars -> BufLen[ 0 ] + Vars -> BufOffs[ 1 ];
6358 for( j = 0; j < Steps -> getItemCount(); j++ )
6360 const CFilterStep& fs = (*Steps)[ j ];
6362 if( fs.ResampleFactor == 0 &&
6363 ml < fs.FltBank -> getFilterLen() )
6365 ml = fs.FltBank -> getFilterLen();
6369 TmpFltBuf.alloc( ml, fpclass :: fpalign );
6375 Queue.increaseCapacity(( TotalLines + ThreadCount - 1 ) /
6376 ThreadCount,
false );
6390 void addScanlineToQueue(
void*
const SrcBuf,
void*
const ResBuf )
6392 Queue[ QueueLen ].SrcBuf = SrcBuf;
6393 Queue[ QueueLen ].ResBuf = ResBuf;
6401 void processScanlineQueue()
6405 switch( ScanlineOp )
6409 for( i = 0; i < QueueLen; i++ )
6411 resizeScanlineH( (Tin*) Queue[ i ].SrcBuf,
6412 (fptype*) Queue[ i ].ResBuf );
6420 for( i = 0; i < QueueLen; i++ )
6422 resizeScanlineV( (fptype*) Queue[ i ].SrcBuf,
6423 (fptype*) Queue[ i ].ResBuf );
6429 case sopDitherAndUnpackH:
6431 for( i = 0; i < QueueLen; i++ )
6433 if( Vars -> UseSRGBGamma )
6435 CFilterStep :: applySRGBGamma(
6436 (fptype*) Queue[ i ].SrcBuf, SrcLen, *Vars );
6439 Ditherer.dither( (fptype*) Queue[ i ].SrcBuf );
6441 CFilterStep :: unpackScanline(
6442 (fptype*) Queue[ i ].SrcBuf,
6443 (Tout*) Queue[ i ].ResBuf, SrcLen, *Vars );
6451 for( i = 0; i < QueueLen; i++ )
6453 if( Vars -> UseSRGBGamma )
6455 CFilterStep :: applySRGBGamma(
6456 (fptype*) Queue[ i ].SrcBuf, SrcLen, *Vars );
6459 CFilterStep :: unpackScanline(
6460 (fptype*) Queue[ i ].SrcBuf,
6461 (Tout*) Queue[ i ].ResBuf, SrcLen, *Vars );
6474 CDitherer& getDitherer()
6482 const CFilterSteps* Steps;
6483 const CImageResizerVars* Vars;
6484 CBuffer< fptype > Bufs;
6485 fptype* BufPtrs[ 3 ];
6487 CBuffer< fptype > TmpFltBuf;
6489 EScanlineOperation ScanlineOp;
6511 CBuffer< CQueueItem > Queue;
6522 void resizeScanlineH(
const Tin*
const SrcBuf, fptype*
const ResBuf )
6524 const CFilterStep& fs0 = (*Steps)[ 0 ];
6526 fs0.packScanline( SrcBuf, BufPtrs[ 0 ], SrcLen );
6527 BufPtrs[ 2 ] = ResBuf;
6531 for( j = 0; j < Steps -> getItemCount(); j++ )
6533 const CFilterStep& fs = (*Steps)[ j ];
6534 fs.prepareInBuf( BufPtrs[ fs.InBuf ]);
6536 ( Vars -> packmode == 0 ? Vars -> ElCount : 1 );
6538 if( fs.ResampleFactor != 0 )
6542 fs.doUpsample( BufPtrs[ fs.InBuf ],
6543 BufPtrs[ fs.OutBuf ]);
6547 fs.doFilter( BufPtrs[ fs.InBuf ],
6548 BufPtrs[ fs.OutBuf ], DstIncr );
6553 if( Vars -> IsResize2 )
6555 fs.doResize2( BufPtrs[ fs.InBuf ],
6556 BufPtrs[ fs.OutBuf ], DstIncr, TmpFltBuf );
6560 fs.doResize( BufPtrs[ fs.InBuf ],
6561 BufPtrs[ fs.OutBuf ], DstIncr, TmpFltBuf );
6575 void resizeScanlineV(
const fptype*
const SrcBuf,
6576 fptype*
const ResBuf )
6578 const CFilterStep& fs0 = (*Steps)[ 0 ];
6580 fs0.convertVtoH( SrcBuf, BufPtrs[ 0 ], SrcLen, SrcIncr );
6581 BufPtrs[ 2 ] = ResBuf;
6585 for( j = 0; j < Steps -> getItemCount(); j++ )
6587 const CFilterStep& fs = (*Steps)[ j ];
6588 fs.prepareInBuf( BufPtrs[ fs.InBuf ]);
6589 const int DstIncr = ( fs.OutBuf == 2 ? ResIncr :
6590 ( Vars -> packmode == 0 ? Vars -> ElCount : 1 ));
6592 if( fs.ResampleFactor != 0 )
6596 fs.doUpsample( BufPtrs[ fs.InBuf ],
6597 BufPtrs[ fs.OutBuf ]);
6601 fs.doFilter( BufPtrs[ fs.InBuf ],
6602 BufPtrs[ fs.OutBuf ], DstIncr );
6607 if( Vars -> IsResize2 )
6609 fs.doResize2( BufPtrs[ fs.InBuf ],
6610 BufPtrs[ fs.OutBuf ], DstIncr, TmpFltBuf );
6614 fs.doResize( BufPtrs[ fs.InBuf ],
6615 BufPtrs[ fs.OutBuf ], DstIncr, TmpFltBuf );