Search code examples
cresizebmp

Resizing bmp image


I'm trying to resize bmp image and it's almost works, but for some reason I get extra bytes filled with zeros. It kinda works, but I'd like to know where did those zeros come from.

I'm not sure if it's connected somehow with those zeros, but sometimes image depth (biBitCount) changes from 24 in original file to 32. I wasn't able to figure out why it does that. Unfortunately, I didn't save screenshots of that.

I'm sure, that I just did some stupid mistake I can't see. Help me, please. original bmp double sized bmp with extra zeros

My Code :

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

#include "bmp.h"

float atoi2_0(char* S);

int main(int argc, char *argv[])
{
    // ensure proper usage
    if (argc != 4)
    {
        fprintf(stderr, "Usage: ./resize f infile outfile\n");
        return 1;
    }

    // remember filenames
    float f = atoi2_0(argv[1]);
    if(f == -1 || f <= 0.0 || f > 100)
    {
        printf("Usage: ./resize f infile outfile\n");
        return 1;
    }
    char *infile = argv[2];
    char *outfile = argv[3];

    // open input file
    FILE *inptr = fopen(infile, "r");
    if (inptr == NULL)
    {
        fprintf(stderr, "Could not open %s.\n", infile);
        return 2;
    }

    // open output file
    FILE *outptr = fopen(outfile, "w");
    if (outptr == NULL)
    {
        fclose(inptr);
        fprintf(stderr, "Could not create %s.\n", outfile);
        return 3;
    }

    // read infile's BITMAPFILEHEADER
    BITMAPFILEHEADER bf;
    fread(&bf, sizeof(BITMAPFILEHEADER), 1, inptr);

    // read infile's BITMAPINFOHEADER
    BITMAPINFOHEADER bi;
    fread(&bi, sizeof(BITMAPINFOHEADER), 1, inptr);

    // ensure infile is (likely) a 24-bit uncompressed BMP 4.0
    if (bf.bfType != 0x4d42 || bf.bfOffBits != 54 || bi.biSize != 40 ||
        bi.biBitCount != 24 || bi.biCompression != 0)
    {
        fclose(outptr);
        fclose(inptr);
        fprintf(stderr, "Unsupported file format.\n");
        return 4;
    }

    int oldpadding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;

    bi.biWidth *= f;
    bi.biHeight *= f;

    int padding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;

    bi.biSizeImage = ((sizeof(RGBTRIPLE) * bi.biWidth) + padding) * abs(bi.biHeight);
    bf.bfSize = bi.biSizeImage + 54;


    // write outfile's BITMAPFILEHEADER
    fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr);

    // write outfile's BITMAPINFOHEADER
    fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, outptr);

float df = f - (int)f;
int revdf = 1 / df;
int bbw = bi.biWidth / f;

for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++)
{
    RGBTRIPLE * oldtriple = (RGBTRIPLE*)calloc(bbw, sizeof(RGBTRIPLE));
    if (oldtriple == NULL)
    {
        fclose(inptr);
        fclose(outptr);
        return 5;
    }

    fread(oldtriple, sizeof(RGBTRIPLE), bbw, inptr);

    RGBTRIPLE * triple = (RGBTRIPLE*)calloc(bi.biWidth, sizeof(RGBTRIPLE));
    if (triple == NULL)
    {
        free(oldtriple);
        fclose(inptr);
        fclose(outptr);
        return 5;
    }

    for (int j = 0; j < bbw; j++)
    {
        int jxf = j * f;
        for (int n = 0; n < f; n++)
        {
            *(triple + jxf + n) = *(oldtriple + j);
        }
    }


    for (int j = 0; j < f; j++)
    {
        if (i % revdf && f - j == df) continue;
        fwrite(triple, sizeof(RGBTRIPLE), bi.biWidth, outptr);
        for (int n = 0; n < padding; n++)
        {
            fputc(0x00, outptr);
        }
    }

    fseek(inptr, oldpadding, SEEK_CUR);

    free(triple);
    free(oldtriple);
}

    // close infile
    fclose(inptr);

    // close outfile
    fclose(outptr);

    // success
    return 0;
}

float atoi2_0(char* S)//kinda atoi for floats
{
    int strl = strlen(S);
    for (int i = 0; i < strl; i++)//input check
    {
        if ((S[i] < '0' || S[i] > '9') && (S[i] != '.'))
        {
            printf("Invalid input");
            return -1;
        }
    }
    float a = atoi(S);
    char D[10] = { 0 };
    for (int i = 0; i < strl; i++)
    {
        if (S[i] == '.')
        {
            ++i;
            for (int j = 0; i < strl; i++, j++)
            {
                D[j] = S[i];
            }
        }
    }
    a += (float)atoi(D) / pow(10, strlen(D));
    return a;
}





BMP.h :

``` // BMP-related data types based on Microsoft's own

#include <stdint.h>

// aliases for C/C++ primitive data types
// https://msdn.microsoft.com/en-us/library/cc230309.aspx
typedef uint8_t  BYTE;
typedef uint32_t DWORD;
typedef int32_t  LONG;
typedef uint16_t WORD;

// information about the type, size, and layout of a file
// https://msdn.microsoft.com/en-us/library/dd183374(v=vs.85).aspx
typedef struct
{
    WORD bfType;
    DWORD bfSize;
    WORD bfReserved1;
    WORD bfReserved2;
    DWORD bfOffBits;
} __attribute__((__packed__))
BITMAPFILEHEADER;

// information about the dimensions and color format
// https://msdn.microsoft.com/en-us/library/dd183376(v=vs.85).aspx
typedef struct
{
    DWORD biSize;
    LONG biWidth;
    LONG biHeight;
    WORD biPlanes;
    WORD biBitCount;
    DWORD biCompression;
    DWORD biSizeImage;
    LONG biXPelsPerMeter;
    LONG biYPelsPerMeter;
    DWORD biClrUsed;
    DWORD biClrImportant;
} __attribute__((__packed__))
BITMAPINFOHEADER;

// relative intensities of red, green, and blue
// https://msdn.microsoft.com/en-us/library/dd162939(v=vs.85).aspx
typedef struct
{
    BYTE rgbtBlue;
    BYTE rgbtGreen;
    BYTE rgbtRed;
} __attribute__((__packed__))
RGBTRIPLE;

Solution

  • Yeah, I fixed it myself. Problem was in cycle length.