cimagereducescaling

Reduce an Image in C


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 4000x2250) and scale it down to native resolution of 1360x768. 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;
}

Solution

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

    // macro to return -/+ half value
    #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;
    
        // get screen resolution for x and y
        GetResolution(&resWidth, &resHeight);
    
        // calculate ratio
        ratio = (float)resWidth / (float)image->Width;
    
        // allocate space for the new image
        NewImage = AllocateZeroPool(sizeof(GUI_IMAGE));
        if (NewImage == NULL)
        {
            // if no allocation, return NULL
            return NULL;
        }
    
        // allocate space for pixel data
        NewImage->PixelData = AllocateZeroPool(resWidth * resHeight * sizeof(GUI_PIXEL));
        if (NewImage->PixelData == NULL) 
        {
            // if no allocation, return NULL
            FreePool(NewImage);
            return NULL;
        }
    
        // set image attributes
        NewImage->Width = resWidth;
        NewImage->Height = resHeight;
        NewImage->HasAlpha = TRUE;
    
        // loop through x and y coordinates of the entire screen
        for(y = 0; y < resHeight; y++)
        {
            for(x = 0; x < resWidth; x++)
            {
                // calculate target area and set new pixel data from original data
                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 new image
        return NewImage;
    }