4640 , ResBitDepth( aResBitDepth )
4642 SrcBitDepth = ( aSrcBitDepth == 0 ? ResBitDepth : aSrcBitDepth );
4644 initFilterBank( FixedFilterBank, 1.0,
false,
CFltBuffer() );
4645 FixedFilterBank.createAllFilters();
4687 template<
class Tin,
class Tout >
4689 const int SrcHeight,
int SrcScanlineSize, Tout*
const NewBuf,
4690 const int NewWidth,
const int NewHeight,
const int ElCountIO,
4693 if( SrcWidth == 0 || SrcHeight == 0 )
4695 memset( NewBuf, 0, (
size_t) NewWidth * NewHeight *
4701 if( NewWidth == 0 || NewHeight == 0 )
4718 double ox = Vars.
ox;
4719 double oy = Vars.
oy;
4723 kx = (double) SrcWidth / NewWidth;
4724 ox += ( kx - 1.0 ) * 0.5;
4726 ky = (double) SrcHeight / NewHeight;
4727 oy += ( ky - 1.0 ) * 0.5;
4735 const double ko = ( k - 1.0 ) * 0.5;
4747 const bool IsInFloat = ( (Tin) 0.25 != 0 );
4748 const bool IsOutFloat = ( (Tout) 0.25 != 0 );
4760 1.0 / (
sizeof( Tin ) == 1 ? 255.0 : 65535.0 );
4769 Vars.
OutGammaMult = (
sizeof( Tout ) == 1 ? 255.0 : 65535.0 );
4782 OutMul = (
sizeof( Tout ) == 1 ? 255.0 : 65535.0 );
4787 OutMul /= (
sizeof( Tin ) == 1 ? 255.0 : 65535.0 );
4793 const int ElCount = ( ElCountIO + fpclass :: fppack - 1 ) /
4796 const int NewWidthE = NewWidth * ElCount;
4798 if( SrcScanlineSize < 1 )
4800 SrcScanlineSize = SrcWidth * ElCountIO;
4805 Vars.
fppack = fpclass :: fppack;
4806 Vars.
fpalign = fpclass :: fpalign;
4807 Vars.
elalign = fpclass :: elalign;
4808 Vars.
packmode = fpclass :: packmode;
4813 CFilterSteps FltSteps;
4814 typename CFilterStep :: CRPosBufArray RPosBufArray;
4820 int UseBuildMode = 1;
4821 const int BuildModeCount =
4822 ( FixedFilterBank.getOrder() == 0 ? 4 : 2 );
4832 int BestScore = 0x7FFFFFFF;
4834 for( m = 0; m < BuildModeCount; m++ )
4837 CFilterSteps TmpSteps;
4840 buildFilterSteps( TmpSteps, Vars, TmpBank, OutMul, m,
true );
4841 updateFilterStepBuffers( TmpSteps, Vars, RPosBufArray,
4842 SrcWidth, NewWidth );
4844 fillUsedFracMap( TmpSteps[ Vars.
ResizeStep ], UsedFracMap );
4845 const int c = calcComplexity( TmpSteps, Vars, UsedFracMap,
4860 buildFilterSteps( FltSteps, Vars, FltBank, OutMul, UseBuildMode,
4863 updateFilterStepBuffers( FltSteps, Vars, RPosBufArray, SrcWidth,
4866 updateBufLenAndRPosPtrs( FltSteps, Vars, NewWidth );
4875 for( i = 0; i < ThreadCount; i++ )
4882 td[ i ].init( i, ThreadCount, FltSteps, Vars );
4884 td[ i ].initScanlineQueue( td[ i ].sopResizeH, SrcHeight,
4889 fpclass :: fpalign );
4892 for( i = 0; i < SrcHeight; i++ )
4894 td[ i % ThreadCount ].addScanlineToQueue(
4895 (
void*) &SrcBuf[ (
size_t) i * SrcScanlineSize ],
4896 &FltBuf[ (
size_t) i * NewWidthE ]);
4900 td[ 0 ].processScanlineQueue();
4906 const int PrevUseBuildMode = UseBuildMode;
4915 int BestScore = 0x7FFFFFFF;
4917 for( m = 0; m < BuildModeCount; m++ )
4921 CFilterSteps TmpSteps;
4924 buildFilterSteps( TmpSteps, TmpVars, TmpBank, 1.0, m,
true );
4925 updateFilterStepBuffers( TmpSteps, TmpVars, RPosBufArray,
4926 SrcHeight, NewHeight );
4928 fillUsedFracMap( TmpSteps[ TmpVars.
ResizeStep ],
4931 const int c = calcComplexity( TmpSteps, TmpVars, UsedFracMap,
4945 if( UseBuildMode == PrevUseBuildMode && ky == kx )
4949 modifyCorrFilterDCGain( FltSteps, 1.0 / OutMul );
4954 buildFilterSteps( FltSteps, Vars, FltBank, 1.0, UseBuildMode,
4958 updateFilterStepBuffers( FltSteps, Vars, RPosBufArray, SrcHeight,
4961 updateBufLenAndRPosPtrs( FltSteps, Vars, NewWidth );
4963 if( IsOutFloat &&
sizeof( FltBuf[ 0 ]) ==
sizeof( Tout ) &&
4964 fpclass :: packmode == 0 )
4968 for( i = 0; i < ThreadCount; i++ )
4970 td[ i ].initScanlineQueue( td[ i ].sopResizeV, NewWidth,
4971 SrcHeight, NewWidthE, NewWidthE );
4974 for( i = 0; i < NewWidth; i++ )
4976 td[ i % ThreadCount ].addScanlineToQueue(
4977 &FltBuf[ (
size_t) i * ElCount ],
4978 (fptype*) &NewBuf[ (
size_t) i * ElCount ]);
4982 td[ 0 ].processScanlineQueue();
4990 fpclass :: fpalign );
4992 for( i = 0; i < ThreadCount; i++ )
4994 td[ i ].initScanlineQueue( td[ i ].sopResizeV, NewWidth,
4995 SrcHeight, NewWidthE, NewWidthE );
4998 const int im = ( fpclass :: packmode == 0 ? ElCount : 1 );
5000 for( i = 0; i < NewWidth; i++ )
5002 td[ i % ThreadCount ].addScanlineToQueue(
5003 &FltBuf[ (
size_t) i * im ], &ResBuf[ (
size_t) i * im ]);
5007 td[ 0 ].processScanlineQueue();
5014 for( i = 0; i < ThreadCount; i++ )
5016 td[ i ].initScanlineQueue( td[ i ].sopUnpackH,
5017 NewHeight, NewWidth );
5020 for( i = 0; i < NewHeight; i++ )
5022 td[ i % ThreadCount ].addScanlineToQueue(
5023 &ResBuf[ (
size_t) i * NewWidthE ],
5024 &NewBuf[ (
size_t) i * NewWidth * ElCountIO ]);
5028 td[ 0 ].processScanlineQueue();
5040 if(
sizeof( Tout ) == 1 )
5042 TruncBits = 8 - ResBitDepth;
5047 TruncBits = 16 - ResBitDepth;
5051 const double PkOut = OutRange;
5052 const double TrMul = ( TruncBits > 0 ?
5053 PkOut / ( OutRange >> TruncBits ) : 1.0 );
5055 if( CDitherer :: isRecursive() )
5057 td[ 0 ].getDitherer().init( NewWidth, Vars, TrMul, PkOut );
5061 for( i = 0; i < NewHeight; i++ )
5063 fptype*
const ResScanline =
5064 &ResBuf[ (size_t) i * NewWidthE ];
5066 CFilterStep :: applySRGBGamma( ResScanline, NewWidth,
5069 td[ 0 ].getDitherer().dither( ResScanline );
5071 CFilterStep :: unpackScanline( ResScanline,
5072 &NewBuf[ (
size_t) i * NewWidth * ElCountIO ],
5078 for( i = 0; i < NewHeight; i++ )
5080 fptype*
const ResScanline =
5081 &ResBuf[ (size_t) i * NewWidthE ];
5083 td[ 0 ].getDitherer().dither( ResScanline );
5085 CFilterStep :: unpackScanline( ResScanline,
5086 &NewBuf[ (
size_t) i * NewWidth * ElCountIO ],
5093 for( i = 0; i < ThreadCount; i++ )
5095 td[ i ].initScanlineQueue( td[ i ].sopDitherAndUnpackH,
5096 NewHeight, NewWidth );
5098 td[ i ].getDitherer().init( NewWidth, Vars, TrMul, PkOut );
5101 for( i = 0; i < NewHeight; i++ )
5103 td[ i % ThreadCount ].addScanlineToQueue(
5104 &ResBuf[ (
size_t) i * NewWidthE ],
5105 &NewBuf[ (
size_t) i * NewWidth * ElCountIO ]);
5109 td[ 0 ].processScanlineQueue();
5117 typedef typename fpclass :: fptype fptype;
5120 typedef typename fpclass :: CFilterStep CFilterStep;
5123 typedef typename fpclass :: CDitherer CDitherer;
5158 const double CutoffMult,
const bool ForceHiOrder,
5161 const int IntBitDepth = ( ResBitDepth > SrcBitDepth ? ResBitDepth :
5164 const double SNR = -6.02 * ( IntBitDepth + 3 );
5173 if( ForceHiOrder || IntBitDepth > 8 )
5176 FracCount = (int) ceil( 0.23134052 * exp( -0.058062929 * SNR ));
5181 FracCount = (int) ceil( 0.33287686 * exp( -0.11334583 * SNR ));
5189 FltBank.
init( FracCount, UseOrder, Params.IntFltLen / CutoffMult,
5190 Params.IntFltCutoff * CutoffMult, Params.IntFltAlpha, ExtFilter,
5191 fpclass :: fpalign, fpclass :: elalign );
5207 static void allocFilter( CBuffer< fptype >& Flt,
const int ReqCapacity,
5208 const bool IsModel =
false,
int*
const FltExt = NULL )
5210 int UseCapacity = ( ReqCapacity + fpclass :: elalign - 1 ) &
5211 ~( fpclass :: elalign - 1 );
5213 int Ext = UseCapacity - ReqCapacity;
5215 if( FltExt != NULL )
5222 Flt.forceCapacity( UseCapacity );
5226 Flt.alloc( UseCapacity, fpclass :: fpalign );
5231 Flt[ ReqCapacity + Ext ] = (fptype) 0;
5256 void assignFilterParams( CFilterStep& fs,
const bool IsUpsample,
5257 const int ResampleFactor,
const double FltCutoff,
const double DCGain,
5258 const bool UseFltOrig,
const bool IsModel )
const
5264 if( FltCutoff == 0.0 )
5266 const double m = 2.0 / ResampleFactor;
5267 FltAlpha = Params.HBFltAlpha;
5268 Len2 = 0.5 * Params.HBFltLen / m;
5269 Freq =
AVIR_PI * Params.HBFltCutoff * m;
5273 FltAlpha = Params.LPFltAlpha;
5274 Len2 = 0.25 * Params.LPFltBaseLen / FltCutoff;
5275 Freq =
AVIR_PI * Params.LPFltCutoffMult * FltCutoff;
5280 Len2 *= ResampleFactor;
5281 Freq /= ResampleFactor;
5282 fs.DCGain = DCGain * ResampleFactor;
5289 fs.FltOrig.Len2 = Len2;
5290 fs.FltOrig.Freq = Freq;
5291 fs.FltOrig.Alpha = FltAlpha;
5292 fs.FltOrig.DCGain = fs.DCGain;
5294 CDSPPeakedCosineLPF w( Len2, Freq, FltAlpha );
5296 fs.IsUpsample = IsUpsample;
5297 fs.ResampleFactor = ResampleFactor;
5298 fs.FltLatency = w.fl2;
5304 allocFilter( fs.Flt, w.FilterLen,
true, &FltExt );
5311 fs.FltOrig.alloc( w.FilterLen );
5312 memset( &fs.FltOrig[ 0 ], 0,
5313 w.FilterLen *
sizeof( fs.FltOrig[ 0 ]));
5318 fs.FltOrig.alloc( w.FilterLen );
5320 w.generateLPF( &fs.FltOrig[ 0 ], fs.DCGain );
5322 allocFilter( fs.Flt, fs.FltOrig.getCapacity(),
false, &FltExt );
5323 copyArray( &fs.FltOrig[ 0 ], &fs.Flt[ 0 ],
5324 fs.FltOrig.getCapacity() );
5334 int l = fs.Flt.getCapacity() - fs.FltLatency - ResampleFactor -
5337 allocFilter( fs.PrefixDC, l, IsModel );
5338 allocFilter( fs.SuffixDC, fs.FltLatency, IsModel );
5347 const fptype* ip = &fs.Flt[ fs.FltLatency + ResampleFactor ];
5352 ip += ResampleFactor;
5353 l -= ResampleFactor;
5360 addArray( ip, &fs.PrefixDC[ 0 ], l );
5364 fptype* op = &fs.SuffixDC[ 0 ];
5369 op += ResampleFactor;
5370 l -= ResampleFactor;
5383 fs.EdgePixelCount = fs.EdgePixelCountDef;
5408 void addCorrectionFilter( CFilterSteps& Steps,
const double bw,
5409 const bool IsPreCorrection,
const bool IsModel )
const
5411 CFilterStep& fs = ( IsPreCorrection ? Steps[ 0 ] : Steps.add() );
5412 fs.IsUpsample =
false;
5413 fs.ResampleFactor = 1;
5415 fs.EdgePixelCount = ( IsPreCorrection ? fs.EdgePixelCountDef : 0 );
5419 allocFilter( fs.Flt, CDSPFIREQ :: calcFilterLength(
5420 Params.CorrFltLen, fs.FltLatency ),
true );
5425 const int BinCount = 65;
5426 const int BinCount1 = BinCount - 1;
5433 CBuffer< double > Bins( BinCount );
5436 for( j = 0; j < BinCount; j++ )
5441 const int si = ( IsPreCorrection ? 1 : 0 );
5443 for( i = si; i < Steps.getItemCount() - ( si ^ 1 ); i++ )
5445 const CFilterStep& fs = Steps[ i ];
5449 curbw *= fs.ResampleFactor;
5451 if( fs.FltOrig.getCapacity() > 0 )
5460 if( fs.ResampleFactor == 0 )
5462 Flt = fs.FltBank -> getFilter( 0 );
5463 FltLen = fs.FltBank -> getFilterLen();
5468 FltLen = fs.Flt.getCapacity();
5475 const double thm =
AVIR_PI * bw / ( curbw * BinCount1 );
5477 for( j = 0; j < BinCount; j++ )
5481 Bins[ j ] *= fs.DCGain / sqrt( re * re + im * im );
5484 if( !fs.IsUpsample && fs.ResampleFactor > 1 )
5486 curbw /= fs.ResampleFactor;
5493 EQ.init( bw * 2.0, Params.CorrFltLen, BinCount, 0.0, bw,
false,
5494 Params.CorrFltAlpha );
5496 fs.FltLatency = EQ.getFilterLatency();
5498 CBuffer< double > Filter( EQ.getFilterLength() );
5499 EQ.buildFilter( Bins, &Filter[ 0 ]);
5502 allocFilter( fs.Flt, Filter.getCapacity() );
5503 copyArray( &Filter[ 0 ], &fs.Flt[ 0 ], Filter.getCapacity() );
5541 static void addSharpenTest( CFilterSteps& Steps,
const double bw,
5542 const bool IsModel )
5549 const double FltLen = 10.0 * bw;
5551 CFilterStep& fs = Steps.add();
5552 fs.IsUpsample =
false;
5553 fs.ResampleFactor = 1;
5555 fs.EdgePixelCount = 0;
5559 allocFilter( fs.Flt, CDSPFIREQ :: calcFilterLength( FltLen,
5560 fs.FltLatency ),
true );
5565 const int BinCount = 200;
5566 CBuffer< double > Bins( BinCount );
5567 int Thresh = (int)
round( BinCount / bw * 1.75 );
5569 if( Thresh > BinCount )
5576 for( j = 0; j < Thresh; j++ )
5581 for( j = Thresh; j < BinCount; j++ )
5587 EQ.init( bw * 2.0, FltLen, BinCount, 0.0, bw,
false, 1.7 );
5589 fs.FltLatency = EQ.getFilterLatency();
5591 CBuffer< double > Filter( EQ.getFilterLength() );
5592 EQ.buildFilter( Bins, &Filter[ 0 ]);
5595 allocFilter( fs.Flt, Filter.getCapacity() );
5596 copyArray( &Filter[ 0 ], &fs.Flt[ 0 ], Filter.getCapacity() );
5629 void buildFilterSteps( CFilterSteps& Steps, CImageResizerVars& Vars,
5630 CDSPFracFilterBankLin< fptype >& FltBank,
const double DCGain,
5631 const int ModeFlags,
const bool IsModel )
const
5635 const bool DoFltAndIntCombo = (( ModeFlags & 1 ) != 0 );
5637 const bool ForceHiOrderInt = (( ModeFlags & 2 ) != 0 );
5639 const bool UseHalfband = (( ModeFlags & 4 ) != 0 );
5642 const double bw = 1.0 / Vars.k;
5643 const int UpsampleFactor = ( (int) floor( Vars.k ) < 2 ? 2 : 1 );
5644 double IntCutoffMult;
5645 CFilterStep* ReuseStep;
5647 CFilterStep* ExtFltStep;
5649 bool IsPreCorrection;
5656 IsPreCorrection =
true;
5663 IsPreCorrection =
false;
5670 if( UpsampleFactor > 1 )
5672 CFilterStep& fs = Steps.add();
5673 assignFilterParams( fs,
true, UpsampleFactor, FltCutoff, DCGain,
5674 DoFltAndIntCombo, IsModel );
5676 IntCutoffMult = FltCutoff * 2.0 / UpsampleFactor;
5678 ExtFltStep = ( DoFltAndIntCombo ? &fs : NULL );
5682 int DownsampleFactor;
5686 DownsampleFactor = (int) floor( 0.5 / FltCutoff );
5687 bool DoHBFltAdd = ( UseHalfband && DownsampleFactor > 1 );
5691 assignFilterParams( Steps.add(),
false, DownsampleFactor,
5692 0.0, 1.0,
false, IsModel );
5694 FltCutoff *= DownsampleFactor;
5698 if( DownsampleFactor < 1 )
5700 DownsampleFactor = 1;
5707 CFilterStep& fs = Steps.add();
5708 assignFilterParams( fs,
false, DownsampleFactor, FltCutoff,
5709 DCGain, DoFltAndIntCombo, IsModel );
5711 IntCutoffMult = FltCutoff / 0.5;
5713 if( DoFltAndIntCombo )
5720 IntCutoffMult *= DownsampleFactor;
5728 CFilterStep& fs = ( ReuseStep == NULL ? Steps.add() : *ReuseStep );
5730 Vars.ResizeStep = Steps.getItemCount() - 1;
5731 fs.IsUpsample =
false;
5732 fs.ResampleFactor = 0;
5733 fs.DCGain = ( ExtFltStep == NULL ? 1.0 : ExtFltStep -> DCGain );
5735 initFilterBank( FltBank, IntCutoffMult, ForceHiOrderInt,
5736 ( ExtFltStep == NULL ? fs.FltOrig : ExtFltStep -> FltOrig ));
5738 if( FltBank == FixedFilterBank )
5740 fs.FltBank = (CDSPFracFilterBankLin< fptype >*) &FixedFilterBank;
5744 fs.FltBank = &FltBank;
5747 addCorrectionFilter( Steps, corrbw, IsPreCorrection, IsModel );
5762 static void extendUpsample( CFilterStep& fs, CFilterStep& NextStep )
5764 fs.InPrefix = ( NextStep.InPrefix + fs.ResampleFactor - 1 ) /
5767 fs.OutPrefix += fs.InPrefix * fs.ResampleFactor;
5768 NextStep.InPrefix = 0;
5770 fs.InSuffix = ( NextStep.InSuffix + fs.ResampleFactor - 1 ) /
5773 fs.OutSuffix += fs.InSuffix * fs.ResampleFactor;
5774 NextStep.InSuffix = 0;
5791 static void fillRPosBuf( CFilterStep& fs,
const CImageResizerVars& Vars )
5793 const int PrevLen = fs.RPosBuf -> getCapacity();
5795 if( fs.OutLen > PrevLen )
5797 fs.RPosBuf -> increaseCapacity( fs.OutLen );
5800 typename CFilterStep :: CResizePos* rpos = &(*fs.RPosBuf)[ PrevLen ];
5801 const int FracCount = fs.FltBank -> getFracCount();
5802 const double o = Vars.o;
5803 const double k = Vars.k;
5806 for( i = PrevLen; i < fs.OutLen; i++ )
5808 const double SrcPos = o + k * i;
5809 const int SrcPosInt = (int) floor( SrcPos );
5810 const double x = ( SrcPos - SrcPosInt ) * FracCount;
5811 const int fti = (int) x;
5812 rpos -> x = (
typename fpclass :: fptypeatom) ( x - fti );
5814 rpos -> SrcPosInt = SrcPosInt;
5835 static void updateFilterStepBuffers( CFilterSteps& Steps,
5836 CImageResizerVars& Vars,
5837 typename CFilterStep :: CRPosBufArray& RPosBufArray,
int SrcLen,
5844 for( i = 0; i < Steps.getItemCount(); i++ )
5846 CFilterStep& fs = Steps[ i ];
5851 fs.OutBuf = ( InBuf + 1 ) & 1;
5856 Vars.k *= fs.ResampleFactor;
5857 Vars.o *= fs.ResampleFactor;
5860 fs.OutLen = fs.InLen * fs.ResampleFactor;
5861 fs.OutPrefix = fs.FltLatency;
5862 fs.OutSuffix = fs.Flt.getCapacity() - fs.FltLatency -
5865 int l0 = fs.OutPrefix + fs.OutLen + fs.OutSuffix;
5866 int l = fs.InLen * fs.ResampleFactor +
5867 fs.SuffixDC.getCapacity();
5871 fs.OutSuffix += l - l0;
5874 l0 = fs.OutLen + fs.OutSuffix;
5876 if( fs.PrefixDC.getCapacity() > l0 )
5878 fs.OutSuffix += fs.PrefixDC.getCapacity() - l0;
5882 if( fs.ResampleFactor == 0 )
5884 const int FilterLenD2 = fs.FltBank -> getFilterLen() / 2;
5885 const int FilterLenD21 = FilterLenD2 - 1;
5887 const int ResizeLPix = (int) floor( Vars.o ) - FilterLenD21;
5888 fs.InPrefix = ( ResizeLPix < 0 ? -ResizeLPix : 0 );
5889 const int ResizeRPix = (int) floor( Vars.o +
5890 ( NewLen - 1 ) * Vars.k ) + FilterLenD2 + 1;
5892 fs.InSuffix = ( ResizeRPix > fs.InLen ?
5893 ResizeRPix - fs.InLen : 0 );
5896 fs.RPosBuf = &RPosBufArray.getRPosBuf( Vars.k, Vars.o,
5897 fs.FltBank -> getFracCount() );
5899 fillRPosBuf( fs, Vars );
5903 Vars.k /= fs.ResampleFactor;
5904 Vars.o /= fs.ResampleFactor;
5905 Vars.o += fs.EdgePixelCount;
5907 fs.InPrefix = fs.FltLatency;
5908 fs.InSuffix = fs.Flt.getCapacity() - fs.FltLatency - 1;
5913 fs.OutLen = ( fs.InLen + fs.ResampleFactor - 1 ) /
5914 fs.ResampleFactor + fs.EdgePixelCount;
5916 fs.InSuffix += ( fs.OutLen - 1 ) * fs.ResampleFactor + 1 -
5919 fs.InPrefix += fs.EdgePixelCount * fs.ResampleFactor;
5920 fs.OutLen += fs.EdgePixelCount;
5927 Steps[ Steps.getItemCount() - 1 ].OutBuf = 2;
5928 Vars.IsResize2 =
false;
5932 extendUpsample( Steps[ upstep ], Steps[ upstep + 1 ]);
5934 if( Steps[ upstep ].ResampleFactor == 2 &&
5935 Vars.ResizeStep == upstep + 1 &&
5936 fpclass :: packmode == 0 &&
5937 Steps[ upstep ].FltOrig.getCapacity() > 0 )
5942 Vars.IsResize2 =
true;
5963 static void updateBufLenAndRPosPtrs( CFilterSteps& Steps,
5964 CImageResizerVars& Vars,
const int ResElIncr )
5966 int MaxPrefix[ 2 ] = { 0, 0 };
5967 int MaxLen[ 2 ] = { 0, 0 };
5970 for( i = 0; i < Steps.getItemCount(); i++ )
5972 CFilterStep& fs = Steps[ i ];
5973 const int ib = fs.InBuf;
5975 if( fs.InPrefix > MaxPrefix[ ib ])
5977 MaxPrefix[ ib ] = fs.InPrefix;
5980 int l = fs.InLen + fs.InSuffix;
5982 if( l > MaxLen[ ib ])
5987 fs.InElIncr = fs.InPrefix + l;
5989 if( fs.OutBuf == 2 )
5994 const int ob = fs.OutBuf;
5998 if( fs.OutPrefix > MaxPrefix[ ob ])
6000 MaxPrefix[ ob ] = fs.OutPrefix;
6003 l = fs.OutLen + fs.OutSuffix;
6005 if( l > MaxLen[ ob ])
6012 if( fs.OutLen > MaxLen[ ob ])
6014 MaxLen[ ob ] = fs.OutLen;
6021 for( i = 0; i < Steps.getItemCount(); i++ )
6023 CFilterStep& fs = Steps[ i ];
6025 if( fs.OutBuf == 2 )
6027 fs.OutElIncr = ResElIncr;
6031 CFilterStep& fs2 = Steps[ i + 1 ];
6035 fs.OutElIncr = fs.OutPrefix + fs.OutLen + fs.OutSuffix;
6037 if( fs.OutElIncr > fs2.InElIncr )
6039 fs2.InElIncr = fs.OutElIncr;
6043 fs.OutElIncr = fs2.InElIncr;
6048 fs.OutElIncr = fs2.InElIncr;
6054 for( i = 0; i < 2; i++ )
6056 Vars.BufLen[ i ] = MaxPrefix[ i ] + MaxLen[ i ];
6057 Vars.BufOffs[ i ] = MaxPrefix[ i ];
6059 if( Vars.packmode == 0 )
6061 Vars.BufOffs[ i ] *= Vars.ElCount;
6064 Vars.BufLen[ i ] *= Vars.ElCount;
6069 CFilterStep& fs = Steps[ Vars.ResizeStep ];
6070 typename CFilterStep :: CResizePos* rpos = &(*fs.RPosBuf)[ 0 ];
6071 const int em = ( fpclass :: packmode == 0 ? Vars.ElCount : 1 );
6072 const int fl = fs.FltBank -> getFilterLen();
6073 const int FilterLenD21 = fl / 2 - 1;
6075 if( Vars.IsResize2 )
6077 for( i = 0; i < fs.OutLen; i++ )
6079 const int p = rpos -> SrcPosInt - FilterLenD21;
6080 const int fo = p & 1;
6081 rpos -> SrcOffs = ( p + fo ) * em;
6082 rpos -> ftp = fs.FltBank -> getFilter( rpos -> fti ) + fo;
6083 rpos -> fl = fl - fo;
6089 for( i = 0; i < fs.OutLen; i++ )
6091 rpos -> SrcOffs = ( rpos -> SrcPosInt - FilterLenD21 ) * em;
6092 rpos -> ftp = fs.FltBank -> getFilter( rpos -> fti );
6106 void modifyCorrFilterDCGain( CFilterSteps& Steps,
const double m )
const
6108 CBuffer< fptype >* Flt;
6109 const int z = Steps.getItemCount() - 1;
6111 if( !Steps[ z ].IsUpsample && Steps[ z ].ResampleFactor == 1 )
6113 Flt = &Steps[ z ].Flt;
6117 Flt = &Steps[ 0 ].Flt;
6122 for( i = 0; i < Flt -> getCapacity(); i++ )
6124 (*Flt)[ i ] = (fptype) ( (
double) (*Flt)[ i ] * m );
6136 static void fillUsedFracMap(
const CFilterStep& fs,
6137 CBuffer< uint8_t >& UsedFracMap )
6139 const int FracCount = fs.FltBank -> getFracCount();
6140 UsedFracMap.increaseCapacity( FracCount,
false );
6141 memset( &UsedFracMap[ 0 ], 0, FracCount *
sizeof( UsedFracMap[ 0 ]));
6143 typename CFilterStep :: CResizePos* rpos = &(*fs.RPosBuf)[ 0 ];
6146 for( i = 0; i < fs.OutLen; i++ )
6148 UsedFracMap[ rpos -> fti ] |= 1;
6173 static int calcComplexity(
const CFilterSteps& Steps,
6174 const CImageResizerVars& Vars,
const CBuffer< uint8_t >& UsedFracMap,
6175 const int ScanlineCount )
6180 if( Vars.packmode != 0 )
6198 for( i = 0; i < Steps.getItemCount(); i++ )
6200 const CFilterStep& fs = Steps[ i ];
6202 s2 += 65 * fs.Flt.getCapacity();
6206 if( fs.FltOrig.getCapacity() > 0 )
6211 s += ( fs.Flt.getCapacity() *
6212 ( fs.InPrefix + fs.InLen + fs.InSuffix ) +
6213 fs.SuffixDC.getCapacity() + fs.PrefixDC.getCapacity() ) *
6217 if( fs.ResampleFactor == 0 )
6219 s += fs.FltBank -> getFilterLen() *
6220 ( fs.FltBank -> getOrder() + Vars.ElCount ) * fs.OutLen;
6222 if( i == Vars.ResizeStep && Vars.IsResize2 )
6227 s2 += fs.FltBank -> calcInitComplexity( UsedFracMap );
6231 s += fs.Flt.getCapacity() * Vars.ElCount * fs.OutLen *
6236 return( s + s2 / ScanlineCount );
6251 template<
class Tin,
class Tout >
6252 class CThreadData :
public CImageResizerThreadPool :: CWorkload
6255 virtual void process()
6257 processScanlineQueue();
6264 enum EScanlineOperation
6270 sopDitherAndUnpackH,
6286 void init(
const int aThreadIndex,
const int aThreadCount,
6287 const CFilterSteps& aSteps,
const CImageResizerVars& aVars )
6289 ThreadIndex = aThreadIndex;
6290 ThreadCount = aThreadCount;
6309 void initScanlineQueue(
const EScanlineOperation aOp,
6310 const int TotalLines,
const int aSrcLen,
const int aSrcIncr = 0,
6311 const int aResIncr = 0 )
6313 const int l = Vars -> BufLen[ 0 ] + Vars -> BufLen[ 1 ];
6315 if( Bufs.getCapacity() < l )
6317 Bufs.alloc( l, fpclass :: fpalign );
6320 BufPtrs[ 0 ] = Bufs + Vars -> BufOffs[ 0 ];
6321 BufPtrs[ 1 ] = Bufs + Vars -> BufLen[ 0 ] + Vars -> BufOffs[ 1 ];
6326 for( j = 0; j < Steps -> getItemCount(); j++ )
6328 const CFilterStep& fs = (*Steps)[ j ];
6330 if( fs.ResampleFactor == 0 &&
6331 ml < fs.FltBank -> getFilterLen() )
6333 ml = fs.FltBank -> getFilterLen();
6337 TmpFltBuf.alloc( ml, fpclass :: fpalign );
6343 Queue.increaseCapacity(( TotalLines + ThreadCount - 1 ) /
6344 ThreadCount,
false );
6357 void addScanlineToQueue(
void*
const SrcBuf,
void*
const ResBuf )
6359 Queue[ QueueLen ].SrcBuf = SrcBuf;
6360 Queue[ QueueLen ].ResBuf = ResBuf;
6368 void processScanlineQueue()
6372 switch( ScanlineOp )
6376 for( i = 0; i < QueueLen; i++ )
6378 resizeScanlineH( (Tin*) Queue[ i ].SrcBuf,
6379 (fptype*) Queue[ i ].ResBuf );
6387 for( i = 0; i < QueueLen; i++ )
6389 resizeScanlineV( (fptype*) Queue[ i ].SrcBuf,
6390 (fptype*) Queue[ i ].ResBuf );
6396 case sopDitherAndUnpackH:
6398 if( Vars -> UseSRGBGamma )
6400 for( i = 0; i < QueueLen; i++ )
6402 CFilterStep :: applySRGBGamma(
6403 (fptype*) Queue[ i ].SrcBuf, SrcLen, *Vars );
6405 Ditherer.dither( (fptype*) Queue[ i ].SrcBuf );
6407 CFilterStep :: unpackScanline(
6408 (fptype*) Queue[ i ].SrcBuf,
6409 (Tout*) Queue[ i ].ResBuf, SrcLen, *Vars );
6414 for( i = 0; i < QueueLen; i++ )
6416 Ditherer.dither( (fptype*) Queue[ i ].SrcBuf );
6418 CFilterStep :: unpackScanline(
6419 (fptype*) Queue[ i ].SrcBuf,
6420 (Tout*) Queue[ i ].ResBuf, SrcLen, *Vars );
6429 if( Vars -> UseSRGBGamma )
6431 for( i = 0; i < QueueLen; i++ )
6433 CFilterStep :: applySRGBGamma(
6434 (fptype*) Queue[ i ].SrcBuf, SrcLen, *Vars );
6436 CFilterStep :: unpackScanline(
6437 (fptype*) Queue[ i ].SrcBuf,
6438 (Tout*) Queue[ i ].ResBuf, SrcLen, *Vars );
6443 for( i = 0; i < QueueLen; i++ )
6445 CFilterStep :: unpackScanline(
6446 (fptype*) Queue[ i ].SrcBuf,
6447 (Tout*) Queue[ i ].ResBuf, SrcLen, *Vars );
6461 CDitherer& getDitherer()
6471 const CFilterSteps* Steps;
6473 const CImageResizerVars* Vars;
6475 CBuffer< fptype > Bufs;
6477 fptype* BufPtrs[ 3 ];
6480 CBuffer< fptype > TmpFltBuf;
6483 EScanlineOperation ScanlineOp;
6512 CBuffer< CQueueItem > Queue;
6525 void resizeScanlineH(
const Tin*
const SrcBuf, fptype*
const ResBuf )
6527 const CFilterStep& fs0 = (*Steps)[ 0 ];
6529 fs0.packScanline( SrcBuf, BufPtrs[ 0 ], SrcLen );
6530 BufPtrs[ 2 ] = ResBuf;
6532 fptype ElBiases[ 4 ];
6533 fs0.calcScanlineBias( BufPtrs[ 0 ], SrcLen, ElBiases );
6534 fs0.unbiasScanline( BufPtrs[ 0 ], SrcLen, ElBiases );
6538 for( j = 0; j < Steps -> getItemCount(); j++ )
6540 const CFilterStep& fs = (*Steps)[ j ];
6541 fs.prepareInBuf( BufPtrs[ fs.InBuf ]);
6543 ( Vars -> packmode == 0 ? Vars -> ElCount : 1 );
6545 if( fs.ResampleFactor != 0 )
6549 fs.doUpsample( BufPtrs[ fs.InBuf ],
6550 BufPtrs[ fs.OutBuf ]);
6554 fs.doFilter( BufPtrs[ fs.InBuf ],
6555 BufPtrs[ fs.OutBuf ], DstIncr );
6560 if( Vars -> IsResize2 )
6562 fs.doResize2( BufPtrs[ fs.InBuf ],
6563 BufPtrs[ fs.OutBuf ], DstIncr, ElBiases,
6568 fs.doResize( BufPtrs[ fs.InBuf ],
6569 BufPtrs[ fs.OutBuf ], DstIncr, ElBiases,
6584 void resizeScanlineV(
const fptype*
const SrcBuf,
6585 fptype*
const ResBuf )
6587 const CFilterStep& fs0 = (*Steps)[ 0 ];
6589 fs0.convertVtoH( SrcBuf, BufPtrs[ 0 ], SrcLen, SrcIncr );
6590 BufPtrs[ 2 ] = ResBuf;
6592 fptype ElBiases[ 4 ];
6593 fs0.calcScanlineBias( BufPtrs[ 0 ], SrcLen, ElBiases );
6594 fs0.unbiasScanline( BufPtrs[ 0 ], SrcLen, ElBiases );
6598 for( j = 0; j < Steps -> getItemCount(); j++ )
6600 const CFilterStep& fs = (*Steps)[ j ];
6601 fs.prepareInBuf( BufPtrs[ fs.InBuf ]);
6602 const int DstIncr = ( fs.OutBuf == 2 ? ResIncr :
6603 ( Vars -> packmode == 0 ? Vars -> ElCount : 1 ));
6605 if( fs.ResampleFactor != 0 )
6609 fs.doUpsample( BufPtrs[ fs.InBuf ],
6610 BufPtrs[ fs.OutBuf ]);
6614 fs.doFilter( BufPtrs[ fs.InBuf ],
6615 BufPtrs[ fs.OutBuf ], DstIncr );
6620 if( Vars -> IsResize2 )
6622 fs.doResize2( BufPtrs[ fs.InBuf ],
6623 BufPtrs[ fs.OutBuf ], DstIncr, ElBiases,
6628 fs.doResize( BufPtrs[ fs.InBuf ],
6629 BufPtrs[ fs.OutBuf ], DstIncr, ElBiases,