final int srcWidth = in.getWidth();
final int srcHeight = in.getHeight();
/* if (SrcWidth < 1) or (SrcHeight < 1) then
raise Exception.Create('Source bitmap too small');*/
// Create intermediate image to hold horizontal zoom
IntegerImage work = (IntegerImage)in.createCompatibleImage(dstWidth, srcHeight);
float xscale;
float yscale;
if (srcWidth == 1)
{
xscale = (float)dstWidth / (float)srcWidth;
}
else
{
xscale = (float)(dstWidth - 1) / (float)(srcWidth - 1);
}
if (srcHeight == 1)
{
yscale = (float)dstHeight / (float)srcHeight;
}
else
{
yscale = (float)(dstHeight - 1) / (float)(srcHeight - 1);
}
/* Marco: the following two variables are used for progress notification */
int processedItems = 0;
int totalItems = /*dstWidth +*/ srcHeight + /*dstHeight +*/ dstWidth;
// --------------------------------------------
// Pre-calculate filter contributions for a row
// -----------------------------------------------
CList[] contrib = new CList[dstWidth];
for (int i = 0; i < contrib.length; i++)
{
contrib[i] = new CList();
}
// Horizontal sub-sampling
// Scales from bigger to smaller width
if (xscale < 1.0f)
{
float width = fwidth / xscale;
float fscale = 1.0f / xscale;
int numPixels = (int)(width * 2.0f + 1);
for (int i = 0; i < dstWidth; i++)
{
contrib[i].n = 0;
contrib[i].p = new Contributor[numPixels];
for (int j = 0; j < contrib[i].p.length; j++)
{
contrib[i].p[j] = new Contributor();
}
float center = i / xscale;
int left = (int)Math.floor(center - width);
int right = (int)Math.ceil(center + width);
for (int j = left; j <= right; j++)
{
float weight = filter.apply((center - j) / fscale) / fscale;
if (weight == 0.0f)
{
continue;
}
int n;
if (j < 0)
{
n = -j;
}
else
if (j >= srcWidth)
{
n = srcWidth - j + srcWidth - 1;
}
else
{
n = j;
}
int k = contrib[i].n;
contrib[i].n = contrib[i].n + 1;
contrib[i].p[k].pixel = n;
contrib[i].p[k].weight = weight;
}
//setProgress(processedItems++, totalItems);
}
}
else
// Horizontal super-sampling
// Scales from smaller to bigger width
{
int numPixels = (int)(fwidth * 2.0f + 1);
for (int i = 0; i < dstWidth; i++)
{
contrib[i].n = 0;
contrib[i].p = new Contributor[numPixels];
for (int j = 0; j < contrib[i].p.length; j++)
{
contrib[i].p[j] = new Contributor();
}
float center = i / xscale;
int left = (int)Math.floor(center - fwidth);
int right = (int)Math.ceil(center + fwidth);
for (int j = left; j <= right; j++)
{
float weight = filter.apply(center - j);
if (weight == 0.0f)
{
continue;
}
int n;
if (j < 0)
{
n = -j;
}
else
if (j >= srcWidth)
{
n = srcWidth - j + srcWidth - 1;
}
else
{
n = j;
}
int k = contrib[i].n;
if (n < 0 || n >= srcWidth)
{
weight = 0.0f;
}
contrib[i].n = contrib[i].n + 1;
contrib[i].p[k].pixel = n;
contrib[i].p[k].weight = weight;
}
//setProgress(processedItems++, totalItems);
}
}
// ----------------------------------------------------
// Apply filter to sample horizontally from Src to Work
// ----------------------------------------------------
// start of Java-specific code
// Marco: adjusted code to work with multi-channel images
// where each channel can have a different maximum sample value (not only 255)
final int NUM_CHANNELS = work.getNumChannels();
final int[] MAX = new int[NUM_CHANNELS];
for (int k = 0; k < NUM_CHANNELS; k++)
{
MAX[k] = work.getMaxSample(k);
}
// end of Java-specific code
for (int k = 0; k < srcHeight; k++)
{
for (int i = 0; i < dstWidth; i++)
{
for (int channel = 0; channel < NUM_CHANNELS; channel++)
{
CList c=contrib[i];
float sample = 0.0f;
int max=c.n;
for (int j = 0; j < max; j++)
{
sample+=in.getSample(channel, c.p[j].pixel, k) * c.p[j].weight;
}
// Marco: procedure BoundRound included directly
int result = (int)sample;
if (result < 0)
{
result = 0;
}
else
if (result > MAX[channel])
{
result = MAX[channel];
}
work.putSample(channel, i, k, result);
}
}
setProgress(processedItems++, totalItems);
}
/* Marco: no need for "free memory" code as Java has garbage collection:
// Free the memory allocated for horizontal filter weights
for i := 0 to DstWidth-1 do
FreeMem(contrib^[i].p);
FreeMem(contrib);
*/
// -----------------------------------------------
// Pre-calculate filter contributions for a column
// -----------------------------------------------
/*GetMem(contrib, DstHeight* sizeof(TCList));*/
contrib = new CList[dstHeight];
for (int i = 0; i < contrib.length; i++)
{
contrib[i] = new CList();
}
// Vertical sub-sampling
// Scales from bigger to smaller height
if (yscale < 1.0f)
{
float width = fwidth / yscale;
float fscale = 1.0f / yscale;
int numContributors = (int)(width * 2.0f + 1);
for (int i = 0; i < dstHeight; i++)
{
contrib[i].n = 0;
contrib[i].p = new Contributor[numContributors];
for (int j = 0; j < contrib[i].p.length; j++)
{
contrib[i].p[j] = new Contributor();
}
float center = i / yscale;
int left = (int)Math.floor(center - width);
int right = (int)Math.ceil(center + width);
for (int j = left; j <= right; j++)
{
float weight = filter.apply((center - j) / fscale) / fscale;
// change suggested by Mike Dillon; not thoroughly tested;
// old version:
// float weight = filter.apply(center - j);
if (weight == 0.0f)
{
continue;
}
int n;
if (j < 0)
{
n = -j;
}
else
if (j >= srcHeight)
{
n = srcHeight - j + srcHeight - 1;
}
else
{
n = j;
}
int k = contrib[i].n;
contrib[i].n = contrib[i].n + 1;
if (n < 0 || n >= srcHeight)
{
weight = 0.0f;// Flag that cell should not be used
}
contrib[i].p[k].pixel = n;
contrib[i].p[k].weight = weight;
}
//setProgress(processedItems++, totalItems);
}
}
else
// Vertical super-sampling
// Scales from smaller to bigger height
{
int numContributors = (int)(fwidth * 2.0f + 1);
for (int i = 0; i < dstHeight; i++)
{
contrib[i].n = 0;
contrib[i].p = new Contributor[numContributors];
for (int j = 0; j < contrib[i].p.length; j++)
{
contrib[i].p[j] = new Contributor();
}
float center = i / yscale;
int left = (int)Math.floor(center - fwidth);
int right = (int)Math.ceil(center + fwidth);
for (int j = left; j <= right; j++)
{
float weight = filter.apply(center - j);
if (weight == 0.0f)
{
continue;
}
int n;
if (j < 0)
{
n = -j;
}
else
if (j >= srcHeight)
{
n = srcHeight - j + srcHeight - 1;
}
else
{
n = j;
}
int k = contrib[i].n;
contrib[i].n = contrib[i].n + 1;
if (n < 0 || n >= srcHeight)
{
weight = 0.0f;// Flag that cell should not be used
}
contrib[i].p[k].pixel = n;
contrib[i].p[k].weight = weight;
}
//setProgress(processedItems++, totalItems);
}
}
// --------------------------------------------------
// Apply filter to sample vertically from Work to Dst
// --------------------------------------------------
for (int k = 0; k < dstWidth; k++)
{
for (int i = 0; i < dstHeight; i++)
{
for (int channel = 0; channel < NUM_CHANNELS; channel++)
{
float sample = 0.0f;
CList c=contrib[i];
int max=c.n;
for (int j = 0; j < max; j++)
{
sample += work.getSample(channel, k, c.p[j].pixel) * c.p[j].weight;
}
int result = (int)sample;
if (result < 0)
{
result = 0;