0

I'm really sorry for doing this again, but I really need to understand how to do this correctly. I'll post both my horizontal resize code and my vertical resize code. The former is working correctly, but I'll post it just in case.

This is the entire for-loop, by the way:

for (int i = 0, biHeight = abs(img_height); i < biHeight; i++)
{
    // iterate over pixels in scanline
    for (int j = 0; j < img_width; j++)
    {
        // temporary storage
        RGBTRIPLE triple;

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

        for (int index = 0; index <= n - 1; index++)
        {
            fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
        }
    }
    for (int k = 0; k < new_padding; k++)
    {
        fputc(0x00, outptr);
    }
    fseek(inptr, padding, SEEK_CUR);

    // send infile cursor back
    // before reading the next RGBTRIPLE data
    long offset = sizeof(RGBTRIPLE);
    fseek(inptr, -1 * (offset * img_width + padding), SEEK_CUR);

    // vertical resize
    // for each row
    for (int l = 0; l < biHeight; l++)
    {
        // temporary storage for triples data
        RGBTRIPLE triple;

        int m;

        for (int iii = 0; iii < n - 1; iii++)
        {
            for (m = 0; m < img_width; m++)
            {
                // read triples data from infile
                fread(&triple, sizeof(RGBTRIPLE), 1, inptr);

                // for n - 1 times:
                    // write pixels and padding to outfile:
                for (int index = 0; index < n; index++)
                {
                    // write pixels to outfile
                    fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
                }
            }
            // write padding to outfile
            for (int k = 0; k < new_padding; k++)
            {
                fputc(0x00, outptr);
            }

            // send infile cursor back
            fseek(inptr, -1 * (offset * m), SEEK_CUR);
        }
        // write pixels and padding to outfile
        // skip over infile padding:
        for (m = 0; m < img_width; m++)
        {
            fread(&triple, sizeof(RGBTRIPLE), 1, inptr);

            for (int index = 0; index < n; index++)
            {
                fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
            }
        }
        for (int k = 0; k < new_padding; k++)
        {
            fputc(0x00, outptr);
        }
        fseek(inptr, padding, SEEK_CUR);
    }
}

This is the pseudo code for vertical resize I'm trying to implement:

for each row
    for n - 1 times
        write pixels and padding to outfile
        send infile cursor back
    write pixels and padding to outfile
    skip over infile padding

I found the vertical resize code that I'm using on another post on this forum, and I'm trying to have it work on my code (to no avail).

Isn't there a way to use the return value ftell() to see whether the cursor is at the right position in the infile and to send it back if it isn't? If there's a good way to do this, please help me figure it out.

Oh and, by the way, the output for resize.c currently looks like this: Output from resize.c

Again, I'm really sorry to keep doing this. But I really want to figure out how to do this and I'm having a lot of trouble with it.

Edit: Okay, I'll add in the whole code because of Cliff B said.

/**
 * resize.c
 *
 * Computer Science 50
 * Problem Set 4
 *
 * Resizes the file whose name is passed to it as a commandline argument.
 */

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

#include "bmp.h"

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

    // remember filenames
    char* infile = argv[2];
    char* outfile = argv[3];

    // change n into a number so we can use it as such
    int n = atoi(argv[1]);

    if (n <= 0 || n > 100)
    {
        printf("The value provided as the size must be that of a positive integer less than or equal to 100!\n");
        return 2;
    }

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

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

    // 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;
    }

    // remember the old padding
    int padding =  (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;

    // remember dimensions of original image
    int img_height = bi.biHeight;
    int img_width = bi.biWidth;

    // calculate dimensions of resized image
    bi.biHeight *= n;
    bi.biWidth *= n;
    int resized_height = bi.biHeight;
    int resized_width = bi.biWidth;

    // determine scanline padding
    int new_padding = (4 - (resized_width * sizeof(RGBTRIPLE)) % 4) % 4;

    // update header info
    bi.biSizeImage = ((resized_width * sizeof(RGBTRIPLE) + new_padding) * abs(resized_height));
    bf.bfSize = bi.biSizeImage + (sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER));

    // 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(img_height); i < biHeight; i++)
    {
        // iterate over pixels in scanline
       for (int j = 0; j < img_width; j++)
        {
            // temporary storage
            RGBTRIPLE triple;

             long offset = sizeof(RGBTRIPLE);

            // read RGB triple from infile
            for (int l = 0; l < n - 1; l++)
            {
                fread(&triple, sizeof(RGBTRIPLE), 1, inptr);

                for (int index = 0; index <= n - 1; index++)
                {
                    fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
                }
                for (int k = 0; k < new_padding; k++)
                {
                    fputc(0x00, outptr);
                }
                fseek(inptr, -1 * offset * j, SEEK_CUR);
            }
            for (int index = 0; index <= n - 1; index++)
            {
                fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
            }
            for (int k = 0; k < new_padding; k++)
            {
                fputc(0x00, outptr);
            }
           fseek(inptr, padding, SEEK_CUR);
        }
    }

    // close infile
    fclose(inptr);

    // close outfile
    fclose(outptr);

    // that's all folks
    return 0;
}

Edit2: Okay, I've made some changes to the code. It's still completely wrong, but I feel like I'm getting somewhere with Cliff B's pointers. Anyway, here's the output for when n=1:

Output for resize.c for when n=1

Edit3: I said this in below comments, and I'll repeat it here:

I used RISHABH KALAKOTI's code as a reference to fix mine. Now I want to study it to make sure I understand it because it actually works perfectly. Can you help me out so that I can call the code mine? I'll leave a note in comments to tell David that I found the code on this site. Hopefully it's not completely against the course's academic honesty code.

Here's the code I have now (and it works):

/**
 * resize.c
 *
 * Computer Science 50
 * Problem Set 4
 *
 * Resizes the file whose name is passed to it as a commandline argument.
 */

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

#include "bmp.h"

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

    // remember filenames
    char* infile = argv[2];
    char* outfile = argv[3];

    // change n into a number so we can use it as such
    int n = atoi(argv[1]);

    if (n <= 0 || n > 100)
    {
        printf("The value provided as the size must be that of a positive integer less than or equal to 100!\n");
        return 2;
    }

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

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

    // 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;
    }

    // remember the old padding
    int padding =  (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;

    // remember dimensions of original image
    int img_height = bi.biHeight;
    int img_width = bi.biWidth;

    // calculate dimensions of resized image
    bi.biHeight *= n;
    bi.biWidth *= n;
    int resized_height = bi.biHeight;
    int resized_width = bi.biWidth;

    // determine scanline padding
    int new_padding = (4 - (resized_width * sizeof(RGBTRIPLE)) % 4) % 4;

    // update header info
    bi.biSizeImage = ((resized_width * sizeof(RGBTRIPLE) + new_padding) * abs(resized_height));
    bf.bfSize = bi.biSizeImage + (sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER));

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

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

    // pseudo code for resizing:
    // for each row
        // for n - 1 times
            // write pixels and padding to outfile
            // send infile cursor back
     // write pixels and padding to outfile
     // skip over infile padding

    // iterate over infile's scanlines
    // for each row
    for (int outer_index = 0, biHeight = abs(img_height); outer_index < biHeight; outer_index++)                
    {
        int img_width_ref;

        // variable to store the size of RGBTRIPLE 
        // as a signed long, so that it can store
        // negative values
        long offset = sizeof(RGBTRIPLE);

        // temporary storage
        RGBTRIPLE triple;

        for (int inner_index = 0; inner_index < n - 1; inner_index++)                                        
        {
            // write pixels and padding to the file
            // have img_width_ref represent original image's width
            // as it'll go until that value in the loop
            for (img_width_ref = 0; img_width_ref < img_width; img_width_ref++)                                       
            {
                // read pixels from infile
                fread(&triple, sizeof(RGBTRIPLE), 1, inptr);

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

            // write padding to the outfile
            for (int outfile_padding_index = 0; outfile_padding_index < new_padding; outfile_padding_index++)                                
            {
                fputc(0x00, outptr);
            }
            // send infile cursor back
            // by the size of an RGBTIRPLE 
            // multiplied by the the width of the scanline
            fseek(inptr, -1 * offset * img_width_ref, SEEK_CUR);                
        }

        // write pixels, padding to outfile
        for (img_width_ref = 0; img_width_ref < img_width; img_width_ref++)                                           
        {
            // read pixels from infile
            fread(&triple, sizeof(RGBTRIPLE), 1, inptr);

            // write pixels and padding to the file
            // write pixels to outfile
            for (int write_index = 0; write_index < n; write_index++)
            {
                fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
            }
        }

        // write padding to the outfile
        for (int outfile_padding_index = 0; outfile_padding_index < new_padding; outfile_padding_index++)
        {
            fputc(0x00, outptr);
        }

        // skip over infile padding
        fseek(inptr, padding, SEEK_CUR);                                        
    }

    // close infile
    fclose(inptr);

    // close outfile
    fclose(outptr);

    // that's all folks
    return 0;

}

I'll also post a link to the where the code I used as reference is (I'm trying to see what it's doing before I submit mine):

cs50 pset4 resize 're-copy' implementation

I just need to ask about the "for each row" thing. Is that just the loop going from 0 until the width of the infile? And the "for n - 1 times" part is the loop going from 0 to n - 2, reading from the infile, then the loop going from 0 to n - 1 and writing pixels to the outfile? Am I right so far?

But why does it have to write pixels to the outfile twice, once in each of the different loops? Is it because it has to complete the scanlines like that and it won't work with just writing pixels to the outfile once?

I'm doing my best to understand this, so please work with me here. Thanks in advance.

2
  • Looking at pseudocode or at split code isn't going to help anyone diagnose the actual issues with your code. Please edit the current version of your code and post your actual and complete live code so that it can be tested. Once the question is answered, please remove the code unrelated to the problem. (Or better, post a link to your full code posted elsewhere, such as github, which can be taken down later.)
    – Cliff B
    Nov 5 '16 at 22:28
  • How about I just add the full code in there directly? I'll do that, then. Nov 6 '16 at 0:41
1

I wanted to see the whole code to understand exactly what you're trying to do. I think I got the big picture, but it didn't make sense. Anyways, I think I can get you on track.

First, have you noticed that your output files are far too large? Even for n=1, the image date is 4x what it should be.

It looks like the code is trying to scale horizontally in one place and then vertically as a separate process. These two activities need to be interlaced. The code needs to process a line, then go back to the beginning of the line and do it again until there are n copies of the line, before moving on to the next line.

Your code is processing a line once as the "horizontal" scaling, then doing it again in the "vertical" scaling, but doesn't correlate correctly to the number of times each line should be processed. This doesn't count a number of more minor issues in the code. Simply put, you're running almost two full versions of the program in this code!

I did manage to quickly repair it though. I completely dumped the code between the "//vertical resizing" comment and the closing curly braces for the surrounding outer for loops. Then, I added a for loop to iterate over each line n times and adjusted the fseek to reset the pointer the requisite number of times. (I'm being somewhat vague to give you a chance to figure it out yourself.)

Anyways, after dumping the "vertical sizing" and fixing the remaining code (which is fairly straightforward), it passes check50. (OK, maybe it is straightforward for me, but not you. I'll grant that. )

Here are some tips. First, dump the code I talked about. Now, test with n=1 and try to get the image data right. Using xxd to inspect the input and output files (they should be identical) start by getting the same number of lines and bytes in both. Then work on getting the correct data. Once it completely works for n=1, move on to n=2. This is where you can focus on the vertical scaling. Finally, think very carefully about what the code is doing, and think about the big picture, not just what each line of code does. Is a section of code processing a line? Has this been done elsewhere? Are you duplicating code? Especially, blocks of code?

There's a bit of work to do here, but you should be able to work through it. If you really can't sort it out, try one of the more interactive forums like reddit or CS50 Stack, where you can get some live, interactive assistance.

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

4
  • It does already pass the xxd check for the headers, doesn't it? I compared it with the staff's output using xxd and it checks out. I don't want to do anything that would completely break that. Why does Zamyla's pseudo code for the vertical resize have "write pixels to outfile" twice? And she also said to have separate code for the vertical resizing unless I misunderstood. Nov 6 '16 at 15:17
  • I made some changes to it, but now it puts weird colors in for n=1 and makes the file of an unsupported or invalid type for n=4. I'm editing the original post to add the updated code and the output for when n=1. Nov 6 '16 at 15:41
  • Okay, edits for opening post are done. Nov 6 '16 at 15:50
  • I used RISHABH KALAKOTI's code as a reference to fix mine. Now I want to study it to make sure I understand it because it actually works perfectly. Can you help me out so that I can call the code mine? I'll leave a note in comments to tell David that I found the code on this site. Hopefully it's not completely against the course's academic honesty code. Nov 6 '16 at 16:24

This site is temporarily in read only mode and not accepting new answers.

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