C Image Scaling – How to Reduce an Image in C Efficiently

c++imagereducescaling

Hello fellow programmers. I'm new to the forum so please bear with me.

What I am trying to achieve is taking a loaded image from file(e.g. background wallpaper image 4000×2250) and scale it down to native resolution of 1360×768. In the same fashion as a modern OS when you set a wallpaper image for your desktop.

typedef struct {
    UINT8 Blue;
    UINT8 Green;
    UINT8 Red;
    UINT8 Reserved;
} EFI_GRAPHICS_OUTPUT_BLT_PIXEL;

typedef EFI_GRAPHICS_OUTPUT_BLT_PIXEL   GUI_PIXEL;

typedef struct {
    UINT32    Width;
    UINT32    Height;
    BOOLEAN   HasAlpha;
    GUI_PIXEL *PixelData;
} GUI_IMAGE;
GUI_IMAGE* ReduceImage(GUI_IMAGE* image)
{
    UINT32 resizeWidth = image->Width / 2;
    UINT32 resizeHeight = image->Height / 2;
    UINT32 x;
    UINT32 y;
    UINT32 row = 0;
    UINT32 column = 0;
    GUI_IMAGE *NewImage;

    NewImage = AllocateZeroPool(sizeof(GUI_IMAGE));
    if (NewImage == NULL)
    {
        return NULL;
    }

    NewImage->PixelData = AllocateZeroPool(resizeWidth * resizeHeight *
sizeof(GUI_PIXEL));
    if (NewImage->PixelData == NULL) 
    {
        FreePool(NewImage);
        return NULL;
    }

    NewImage->Width = resizeWidth;
    NewImage->Height = resizeHeight;
    NewImage->HasAlpha = TRUE;

    for(y = 0; y < resizeHeight - 1; y++)
    {
        for(x = 0; x < resizeWidth - 1; x++)
        {
            NewImage->PixelData[(resizeWidth) * y + x] = image->PixelData[(image->Width) * row + column];
            column += 2;
        }
        row += 2;
        column = 0;
    }

    return NewImage;
}

Best Answer

Thank you for all the help! I figured it out.

#define RoundValue(x)  ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))

GUI_IMAGE* ScaleImage(GUI_IMAGE* image)
{
    float ratio; // >1 is enlarging(e.g. 1.1), <1 is reducing(e.g. 0.4)
    UINT32 resWidth;
    UINT32 resHeight;
    UINT32 x;
    UINT32 y;
    UINT32 x_in;
    UINT32 y_in;
    GUI_IMAGE *NewImage;

    GetResolution(&resWidth, &resHeight);

    ratio = (float)resWidth / (float)image->Width;

    NewImage = AllocateZeroPool(sizeof(GUI_IMAGE));
    if (NewImage == NULL)
    {
        return NULL;
    }

    NewImage->PixelData = AllocateZeroPool(resWidth * resHeight * sizeof(GUI_PIXEL));
    if (NewImage->PixelData == NULL) 
    {
        FreePool(NewImage);
        return NULL;
    }

    NewImage->Width = resWidth;
    NewImage->Height = resHeight;
    NewImage->HasAlpha = TRUE;

    for(y = 0; y < resHeight; y++)
    {
        for(x = 0; x < resWidth; x++)
        {
            x_in = RoundValue((float)x / ratio);
            y_in = RoundValue((float)y / ratio);
            NewImage->PixelData[resWidth * y + x] = image->PixelData[image->Width * y_in + x_in];
        }
    }

    return NewImage;
}