Search code examples
cimagepixel

Scaling an 8-bit Greyscale RAW in C


Currently, I'm trying to scale a 320x200, 8-bit RAW image to whatever size the user specifies as their preferred resolution. If their resolution is 320x200, It simply uses fread to read the data directly to fill it in, otherwise it'll double all pixels horizontally, producing a 640x200 image. However, this isn't what I want to do, I want to scale exactly to the value of PIXX/PIXY, even if it isn't a multiple. How would I do this?

Here's the important part of the code:

FILE    *f;

int x,y;
int x1,y1;

int c;

char    *p;

f = dopen("art",name,"rb");
if (f == 0) GTFO("Unable to open title");

p = vpage;

if ((PIXX == 320) && (PIXY == 200))
{
    fread(vpage,320,200,f);
}
else
{
    for (y1 = 0; y1 < 200; y1++)
    {
        for (x1 = 0; x1 < 320; x1++)
        {
            c = getc(f);

            *p = c;
            *(p + 1) = c;
            p += 2;
        }
    }
}

fclose(f);

If a function or libary exists that can take the image produced by fread, and perform linear scaling, outputting back to 8-bit raw would be excellent. The image gets stored in vpage.

EDIT: Here's my attempt to use the Bresenham algo, it creates garbage for some reason, but scales the garbage correctly, haha.

#include "imgscale.h"

void ScaleLine(unsigned char *Target, unsigned char *Source, int SrcWidth, int TgtWidth)
{
    int NumPixels = TgtWidth;
    int IntPart = SrcWidth / TgtWidth;
    int FractPart = SrcWidth % TgtWidth;
    int E = 0;
    while (NumPixels-- > 0)
    {
        *Target++ = *Source;
        Source += IntPart;

        E += FractPart;
        if (E >= TgtWidth)
        {
            E -= TgtWidth;
            Source++;
        } /* if */
    } /* while */
}

#define average(a, b)   (unsigned char)(( (int)(a) + (int)(b) ) >> 1)
void ScaleLineAvg(unsigned char *Target, unsigned char *Source, int SrcWidth, int TgtWidth)
{
    int NumPixels = TgtWidth;
    int Mid = TgtWidth / 2;
    int E = 0;
    char p;

    if (TgtWidth > SrcWidth)
    {
        NumPixels--;
    }

    while (NumPixels-- > 0)
    {
        p = *Source;

        if (E >= Mid)
        {
            p = average(p, *(Source+1));
        }

        *Target++ = p;
        E += SrcWidth;
        if (E >= TgtWidth)
        {
            E -= TgtWidth;
            Source++;
        } /* if */
    } /* while */

    if (TgtWidth > SrcWidth)
    {
        *Target = *Source;
    }
}

void ScaleRect(unsigned char *Target, unsigned char *Source, int SrcWidth, int SrcHeight, int TgtWidth, int TgtHeight)
{
    int NumPixels = TgtHeight;
    int IntPart = (SrcHeight / TgtHeight) * SrcWidth;
    int FractPart = SrcHeight % TgtHeight;
    int E = 0;
    char *PrevSource;
    while (NumPixels-- > 0)
    {
        if (Source == PrevSource)
        {
            memcpy(Target, Target-TgtWidth, TgtWidth*sizeof(*Target));
        }
        else
        {
            ScaleLine(Target, Source, SrcWidth, TgtWidth);
            PrevSource = Source;
        } /* if */

        Target += TgtWidth;
        Source += IntPart;
        E += FractPart;

        if (E >= TgtHeight)
        {
            E -= TgtHeight;
            Source += SrcWidth;
        } /* if */
    } /* while */
}

Solution

  • I managed to find the solution. I needed to load the image into a new buffer, and not read the file directly either.

    This code worked for me

        int i;
        FILE    *f;
        char *vpage2;
    
        f = dopen("art",name,"rb");
        if (f == 0) {
            char    text[80];
    
            sprintf(text,"Unable to open title: %s",name);
            GTFO(text);
        }
    
        vpage2 = malloc(PIXX*PIXY);
    
        fread(vpage2,320,200,f);
    
        ScaleRect(vpage, vpage2, 320, 200, PIXX, PIXY);
    
        fclose(f);
    
        for (i = 0; i < PIXX * PIXY; i++) {
            vpage[i] = lightTable[0][vpage[i]];
        }