UPDATE: Code is OK now, see edits at the end of question
I'm writing a simple application that is supposed to scale given image and display the result on the screen. Image loading, displaying etc is achieved throught SDL, but I still have problem with scaling function - it produces gibberish.
I have to operate on 24-bit images, thus the uint8_t casting and byte by byte calculations.
#include <stdint.h>
void blin(uint8_t* pixelsIn, uint8_t* pixelsOut, int w, int h, float scale)
{
int index1, index2;
int w2, h2;
int i, j, k;
float x, y;
float t;
int p1, p2;
w2 = (int)(scale*w + 0.5);
h2 = (int)(scale*h + 0.5);
p1 = w*3;
if(p1%4) p1 += (4-p1%4);
p2 = w2*3;
if(p2%4) p2 += (4-p2%4);
for(i=0;i<h2;i++) //line
{
index2=i*p2;
for(j=0;j<w2;j++) //column
{
x=((float)(j))/scale;
index1=(int)(x) * 3;
x-=(int)(x);
y=((float)(i))/scale;
index1+=(int)(y) * p1;
y-=(int)(y);
for(k=0;k<3;k++) //for color in R, G, B
{
t = (float)(pixelsIn[index1]) * (1.0-x)*(1.0-y);
t += (float)(pixelsIn[index1+3]) * (x)*(1.0-y);
t += (float)(pixelsIn[index1+p1]) * (1.0-x)*(y);
t += (float)(pixelsIn[index1+p1+3]) * (x)*(y);
pixelsOut[index2] = (uint8_t)(t);
index1++;
index2++;
}
}
}
}
Edit: obvious error, index2 was not zeroed and x was calculated without multiplying by 3 (bytes per pixel). But image is still not properly scaled, this is before and after for scale=1.0 (jpgs just for faster upload):
Edit2: 2nd problem was 4-byte alignment inside SDL_Surface pixel structure. Now it works like a charm (code here is updated), though it's intended to work only on 24bit images - see comments to best answer.
I think this line:-
index1=(int)(x);
should be:-
index1=(int)(x)*3;
Also, don't assume that the stride is the same as width.sizeof(pixel)
, the first pixel on a line may be aligned to a word/dword/etc boundary, so I'd change the code to:-
void blin(uint8_t* pixelsIn, uint8_t* pixelsOut, int w, int h, float scale, int input_stride, int output_stride)
{
int index1, index2;
int w2, h2;
int i, j, k;
float x, y;
float t;
w2=(int)(scale*w + 0.5);
h2=(int)(scale*h + 0.5);
index2=0;
for(i=0;i<h2;i++) //line
{
int pixelindex2=index2;
for(j=0;j<w2;j++) //column
{
x=((float)(j))/scale;
index1=(int)(x)*3;
x-=(int)(x);
y=((float)(i))/scale;
index1+=(int)(y) * input_stride;
y-=(int)(y);
for(k=0;k<3;k++) //for color in R, G, B
{
t = (float)(pixelsIn[index1]) * (1.0-x)*(1.0-y);
t += (float)(pixelsIn[index1+3]) * (x)*(1.0-y);
t += (float)(pixelsIn[index1+w*3]) * (1.0-x)*(y);
t += (float)(pixelsIn[index1+w*3+3]) * (x)*(y);
pixelsOut[pixelindex2] = (uint8_t)(t);
index1++;
pixelindex2++;
}
} //column
index2+=output_stride;
} //line
}
where input_stride
and output_stride
are the number of bytes between the start of consecutive lines which may not be the same as width * 3
.
You may also want to consider making the '3' constant a variable so that you can deal with different image formats.