1

I've been working this problem for a couple of weeks and am unsure what the black is after the first line. It seems like my code is duplicating the pixels correctly for the width, but I'm getting stuck on the padding. I'm enlarging by a factor of 4, meaning it should be divisible by 4 (no padding) yet there is black space. Does anyone have any idea what I'm doing wrong? Thanks in advance.

enter image description here is supposed to resize to enter image description here by a factor of 4. (only considering scanlines right now not height).

/**
 * copy.c
 *
 * Computer Science 50
 * Problem Set 4
 *
 * Copies a BMP piece by piece, just because.
 */

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

#include "bmp.h"

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

// remember filenames
char* infile = argv[2];
char* outfile = argv[3];
int n = atoi(argv[1]);

// open input file 
FILE* inptr = fopen(infile, "r");
if (inptr == NULL)
{
    printf("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
*/
// 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;
}

/*
    TRANSFORM
    [ ] pixel repeated n times
    [ ] row repeated n times 
*/ 

//store

// int before_bfSize = bf.bfSize;
// int before_biSizeImage = bi.biSizeImage;
// int before_biWidth = bi.biWidth;
// int before_biHeight = bi.biHeight;

//transform

/**the size (in bytes) of the bitmap file. [ ]
 */
bf.bfSize = bf.bfSize * n;

/**resize horizontally [x]
 * width of image (in pixels)
 * does not include padding 
 * write it n times in the outfile
 */
bi.biWidth = bi.biWidth * n; 

/**resize vertically [ ]
 * method 1: "Rewrite" methods | remember pixels in an array || write array as many times as needed
 * method 2: "Re-copy" methods | go back to the start of the original row with fseek() || repeat the horizontal resizing
 */
bi.biHeight = bi.biHeight * n;

/**the size (in bytes) of the image [ ]
 * total size of image (in bytes)
 * includes pixels and padding 
 */
bi.biSizeImage = bi.biSizeImage * n; 

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

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

// determine padding for scanlines
int padding_in =  (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
// int padding_out = padding_in * n; 

// iterate over infile's scanlines
for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++)
{
    // iterate over pixels in scanline
    for (int j = 0; j < bi.biWidth; j++)
    {
        // temporary storage
        RGBTRIPLE triple;

        // read RGB triple from infile
        fread(&triple, sizeof(RGBTRIPLE), 1, inptr);

        for (int a = 0; a < n; a++)
        {
            // write RGB triple to outfile
            fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
        }

         /**add padding to row [ ]
          * each pixel is 3 bytes
          * size of each scanline must be a multiple of 4 bytes
          * if the number of pixels isn't a multiple of 4 we need padding
          * fputc(chr, output) to write padding | chr: char to write | outptr: FILE* to write to | fputc(0x00, outptr);
          * fseek(inptr, amount, from); to move file position indicator | inptr:FILE* to seek in | amount: number of bytes to move cursor | from: SEEK_CUR(current position in file) || SEEK_SET (beginninng of file) || SEEK_END (end of file)
          * make sure your file position indicator is at the correct point to resize vertically [ ]
          * calculate input file padding and output file padding separately
          */
    }

    // skip over padding, if any
    fseek(inptr, padding_in, SEEK_CUR);

    // then add it back (to demonstrate how)
    for (int k = 0; k < padding_in; k++)
    {
        fputc(0x00, outptr);
    }
}

// close infile
fclose(inptr);

// close outfile
fclose(outptr);

// that's all folks
return 0;
}

_______________________________ Update 1 _______________________________

I've made some changes, but I'm still having trouble with the black spaces.

enter image description here enter image description here enter image description here enter image description here enter image description here enter image description here enter image description here

It seems to be turning out every way except the way it's supposed to. The black spaces are still visible. Any tips?

/**
 * copy.c
 *
 * Computer Science 50
 * Problem Set 4
 *
 * Copies a BMP piece by piece, just because.
*/

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

#include "bmp.h"

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

// remember filenames
char* infile = argv[2];
char* outfile = argv[3];
int n = atoi(argv[1]);

// open input file 
FILE* inptr = fopen(infile, "r");
if (inptr == NULL)
{
    printf("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
*/
// 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;
}

/*
    TRANSFORM
    [ ] pixel repeated n times
    [ ] row repeated n times 
*/ 

//store

// int before_bfSize = bf.bfSize;
// int before_biSizeImage = bi.biSizeImage;
// int before_biWidth = bi.biWidth;
// int before_biHeight = bi.biHeight;

/**transform padding
 * the input and the output files do not necessarily have the same amount of padding.
 * calculate the output file padding, based on the changed header values.
*/

// determine padding for scanlines
int padding_in =  (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
// int padding_out = padding_in * n; 
int padding_out =  (4 - ((bi.biWidth * atoi(argv[1]) * sizeof(RGBTRIPLE)) % 4)) % 4;

//transform header properties

/**resize horizontally [x]
 * width of image (in pixels)
 * does not include padding 
 * write it n times in the outfile
 */
bi.biWidth = bi.biWidth * n; 

/**resize vertically [ ]
 * method 1: "Rewrite" methods | remember pixels in an array || write array as many times as needed
 * method 2: "Re-copy" methods | go back to the start of the original row with fseek() || repeat the horizontal resizing
 */
bi.biHeight = bi.biHeight * n;

/**the size (in bytes) of the image 
 * total size of image (in bytes)
 * includes pixels and padding 
 */
// bi.biSizeImage = bi.biSizeImage * n; 
bi.biSizeImage = (bi.biWidth * sizeof(RGBTRIPLE) + padding_out) * abs(bi.biHeight); // this works

/**the size (in bytes) of the bitmap file. 
 */
// bf.bfSize = bf.bfSize * n;
bf.bfSize = bi.biSizeImage + 54; // 54 is the size of the meta data

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

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


// iterate over infile's scanlines
for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++)
{
    // iterate over pixels in scanline
    for (int j = 0; j < bi.biWidth; j++)
    {
        // temporary storage
        RGBTRIPLE triple;

        // read RGB triple from infile
        fread(&triple, sizeof(RGBTRIPLE), 1, inptr);

        for (int a = 0; a < n; a++)
        {
            for (int row = 0; row < n; row++ )
            {
                // write RGB triple to outfile
                fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
            }
        }

         /**add padding to row [ ]
          * each pixel is 3 bytes
          * size of each scanline must be a multiple of 4 bytes
          * if the number of pixels isn't a multiple of 4 we need padding
          * fputc(chr, output) to write padding | chr: char to write | outptr: FILE* to write to | fputc(0x00, outptr);
          * fseek(inptr, amount, from); to move file position indicator | inptr:FILE* to seek in | amount: number of bytes to move cursor | from: SEEK_CUR(current position in file) || SEEK_SET (beginninng of file) || SEEK_END (end of file)
          * make sure your file position indicator is at the correct point to resize vertically [ ]
          * calculate input file padding and output file padding separately
          */

    }

    // skip over padding, if any
    fseek(inptr, padding_in, SEEK_CUR);

    // then add it back (to demonstrate how)
    for (int k = 0; k < padding_in; k++)
    {
        fputc(0x00, outptr);
    }
}

// close infile  
fclose(inptr);

// close outfile
fclose(outptr);

// that's all folks
return 0;
}

_______________________________ Update 2 _______________________________

Ok, now I'm just putting these up here for fun.

enter image description here enter image description here enter image description here enter image description here enter image description here enter image description here enter image description here enter image description here

enter image description here

Ok, this is as close as I've come. I'm kind of hitting the wall again and have to do work. I'd like to move on with CS50, so any hints are greatly appreciated at this point.

/**
* copy.c
*
* Computer Science 50
* Problem Set 4
*
* Copies a BMP piece by piece, just because.
*/

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

#include "bmp.h"

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

// remember filenames
char* infile = argv[2];
char* outfile = argv[3];
int n = atoi(argv[1]);

// open input file 
FILE* inptr = fopen(infile, "r");
if (inptr == NULL)
{
    printf("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
*/
// 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;
}

/*
    TRANSFORM
    [ ] pixel repeated n times
    [X] row repeated n times 
*/ 

/**transform padding
 * the input and the output files do not necessarily have the same amount of padding.
 * calculate the output file padding, based on the changed header values.
 */
// determine padding for scanlines
int padding_in =  (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
int padding_out =  (4 - ((bi.biWidth * n * sizeof(RGBTRIPLE)) % 4)) % 4;

/**transform header properties
 */

// store infile header property values
// int in_biWidth = bi.biWidth;
int in_biHeight = bi.biHeight;
// int in_biSizeImage = bi.biSizeImage;
// int in_bfSize = bf.bfSize;

// calculate outfile header propery values
// int out_biWidth = bi.biWidth * n;
int out_biHeight = bi.biHeight * n;
// int out_biSizeImage = (bi.biWidth * sizeof(RGBTRIPLE) + padding_out) * abs(bi.biHeight); // this works;
// int out_bfSize = bi.biSizeImage + 54;

// update output object's values to write 
/**resize horizontally [x]
 * width of image (in pixels)
 * does not include padding 
 * write it n times in the outfile
 */
bi.biWidth = bi.biWidth * n; 
/**resize vertically [ ]
 * method 1: "Rewrite" methods | remember pixels in an array || write array as many times as needed
 * method 2: "Re-copy" methods | go back to the start of the original row with fseek() || repeat the horizontal resizing
 */
bi.biHeight = bi.biHeight * n;
/** biSizeImage = the size (in bytes) of the image 
 * total size of image (in bytes)
 * includes pixels and padding 
 */
bi.biSizeImage = (bi.biWidth * sizeof(RGBTRIPLE) + padding_out) * abs(bi.biHeight); // this works
/** bfsize = the size (in bytes) of the bitmap file. 
 */
bf.bfSize = bi.biSizeImage + 54; // 54 is the size of the meta data

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

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

// temporary storage
RGBTRIPLE triple;

/**
 * read the infile, pixel by pixel. 
 * for every pixel in the infile print n pixels to the outfile. 
 * for every row in the infile, produce n rows in the outfile.
*/
// iterate over infile's scanlines to read
for (int in_row = 0; in_row < abs(out_biHeight); in_row++)
{
    //keep track of pointer position
    int orig_pos = ftell(inptr);

    // for every row in the infile, produce n rows in the outfile.
    for (int out_row = 0; out_row < abs(in_biHeight); out_row++)
    {
        // iterate over pixels in scanline to read
        // read RGB triple from infile
        fread(&triple, sizeof(RGBTRIPLE), 1, inptr);

        // write for each col
        for (int out_col = 0; out_col < n; out_col++ )
        {
            // write RGB triple to outfile
            fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
        }              
    }

    /**add padding to row [ ]
     * each pixel is 3 bytes
     * size of each scanline must be a multiple of 4 bytes
     * if the number of pixels isn't a multiple of 4 we need padding
     * fputc(chr, output) to write padding | chr: char to write | outptr: FILE* to write to | fputc(0x00, outptr);
     * fseek(inptr, amount, from); to move file position indicator | inptr:FILE* to seek in | amount: number of bytes to move cursor | from: SEEK_CUR(current position in file) || SEEK_SET (beginninng of file) || SEEK_END (end of file)
     * make sure your file position indicator is at the correct point to resize vertically [ ]
     * calculate input file padding and output file padding separately
     */
    // skip over padding, if any
    fseek(inptr, padding_in, SEEK_CUR);

    // then add it back (to demonstrate how)
    for (int k = 0; k < padding_out; k++)
    {
        fputc(0x00, outptr);
    }

    if(in_row < (n-1))
    {
        int curr_pos = ftell(inptr);
        fseek(inptr, -(curr_pos - orig_pos), SEEK_CUR);
    }
}

// close infile  
fclose(inptr);

// close outfile
fclose(outptr);

// that's all folks
return 0;
}

_______________________________ Update 3 _______________________________

I need to solve this, this is crazy.

enter image description here enter image description here enter image description here enter image description here enter image description here

2
  • I have the exact same problem Sprintup, did you find our mutual error yet? Commented Apr 29, 2016 at 8:12
  • Not yet, still working on it. I'm thinking about reposting or something, I don't really know what to do now except just keep staring at it.
    – Sprintup
    Commented Apr 29, 2016 at 19:05

1 Answer 1

1

It's mostly about what wasn't done. First, biSizeImage and bfSize cannot simply be multiplied by n. Read the docs on what they are, along with what's next here.

Two problems with the image side of the code. First, the input and the output files do not necessarily have the same amount of padding. You need to calculate the output file padding, based on the changed header values.

Next, the code scales horizontally, but not vertically. Each line of image data from the original file needs to be processed n times, meaning that you need to go back and read the input line and reprocess it n times before moving forward. That's why the top 1/4 of the image has green and the rest is black.

If this answers your question, please click on the check mark to accept. Let's keep up on forum maintenance. ;-)

7
  • Thank you, I've made the changes you've recommended and put the updated code under the previous code above. I'm still having issues, however. Do you have any additional tips?
    – Sprintup
    Commented Apr 23, 2016 at 15:46
  • Cliff? Do you think you could help me with this? It's kind of killing me.
    – Sprintup
    Commented Apr 26, 2016 at 2:46
  • You have modified the header fields to contain the necessary output file values, but then you use those values to control the reading of the input file image. None of the original values were saved. You'd do better to read in the input file headers, copy them to another pair of header structures for the output file, and make the necessary changes in the output file headers while leaving the input file headers intact. Most of your problems arise from using output file values where you should use input file values and vice versa.
    – Cliff B
    Commented May 12, 2016 at 0:36
  • Thank you Cliff, I'll give it a shot!
    – Sprintup
    Commented May 12, 2016 at 12:47
  • Thanks Cliff, I worked on it for a couple of hours this morning. It's still not solved, but I'm closer (above). Any additional help is greatly appreciated.
    – Sprintup
    Commented May 12, 2016 at 17:12

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .