Home > OS >  How to scale .pnm images in C?
How to scale .pnm images in C?

Time:11-10

so first off to give some background info I'm extremely new to C, currently learning it in university, and we had a lab last week that I was unable to attend and now I'm playing catch up trying to figure out how to do it without having been there when they explained it (They released a document of course explaining the assignment I just missed any extra verbal info they didn't include in the doc)

The lab assignment is that we are given an .pnm image file and have to scale it down by 1/2 (it will be 1/2 as wide and 1/2 as long).

I've gotten SOMETHING down to start but don't really know where to go from here. Any help would be appreciated.

For reference, here are are my functions in no particular order:

void fillImageArray(rgb_t *pixels, int max){

    for(int a = 0; a < max; a  ){
        fscanf(stdin, "%i", &pixels[a].r);
        fscanf(stdin, "%i", &pixels[a].g);
        fscanf(stdin, "%i", &pixels[a].b);
    }

    
}
#include "defs.h"

info_t getHeader(){

    info_t header;
    fscanf(stdin, "%s", &header.type);
    int *z;
    z = (int *) malloc(3 * sizeof(int));
       for(int i = 0; i < 3; i  ){
              fscanf(stdin, "%i", &z[i]);
       }
    header.width = z[0];
    header.height = z[1];
    header.maxColor = z[2];

    free(z);

return header;
}
#include"defs.h"

void writeHeader(info_t headerInfo){
    fprintf(stdout, "%s\n", headerInfo.type);
    fprintf(stdout, "%i %i %i\n", (headerInfo.width/2), (headerInfo.height/2), headerInfo.maxColor); 
}
#include"defs.h"

void halfSizeWritePixels(rgb_t *pixels, int max){

    for(int b = 0; b < max; b =4){
        fprintf(stdout, "%i ", pixels[b].r);
        fprintf(stdout, "%i ", pixels[b].g);
        fprintf(stdout, "%i\n", pixels[b].b);
    }
        
}

Also, for reference, here is my header file:

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

//header struct
typedef struct info{
        char type[3];
        int width;
        int height;
        int maxColor;
    }info_t;

//struct to hold pixels
typedef struct rgb{
        unsigned int r;
        unsigned int g;
        unsigned int b;
    }rgb_t;

//function prototypes
info_t getHeader();
void writeHeader(info_t headerInfo);
void fillImageArray(rgb_t *pixels, int max);
void writePixels(rgb_t *pixels, int max);
void halfSizeWritePixels(rgb_t *pixels, int max);

And here is my driver code:

#include"defs.h"

int main (){

    //declaring header struct
    info_t headerInfo;
    
    //function to get header
    headerInfo = getHeader();

    int max = (headerInfo.width)*(headerInfo.height);
    int max2 = max*3;

    rgb_t *pixels;

    pixels = (rgb_t *) malloc(max2 * sizeof(int));


    //function to fill array
    fillImageArray(pixels, max);

    writeHeader(headerInfo);    

    //function to print image
    halfSizeWritePixels(pixels, max);

    free(pixels);
    
    
//end of program
return 0;
}

The way I was thinking of doing this is to read in the pixels from the file, which I know for a fact it does successfully, and then just output every 4th pixel, since when scaling the image by 1/2 it's reducing the amount of pixels overall by 1/4th.

**Here is the image we are given to start: https://i.stack.imgur.com/ukiw1.png

And here is what is outputted when I run my program: https://i.stack.imgur.com/dOU1W.png**

This lab is just building on our previous one (which I did successfully) - the previous lab assignment was to just make a program that can read in the .pnm file and output it, so I know that at least works.

This program is the the same as that one, with the only real change I made so far being changing this:

#include"defs.h"

void halfSizeWritePixels(rgb_t *pixels, int max){

    for(int b = 0; b < max/4; b  ){
        fprintf(stdout, "%i ", pixels[b].r);
        fprintf(stdout, "%i ", pixels[b].g);
        fprintf(stdout, "%i\n", pixels[b].b);
    }
        
}

To this:

#include"defs.h"

void halfSizeWritePixels(rgb_t *pixels, int max){

    for(int b = 0; b < max/4; b =4){
        fprintf(stdout, "%i ", pixels[b].r);
        fprintf(stdout, "%i ", pixels[b].g);
        fprintf(stdout, "%i\n", pixels[b].b);
    }
        
}

I know I haven't done much so far, but the logic of this makes sense to me. I've tried other slight variations of this and they all just crop the picture in different ways instead of scaling the entire thing down as a whole. Just not sure where to go from here since my logic is obviously flawed.

Again, any help would be greatly appreciated, I apologize in advance if this is a bit too general, I tried to be as specific as I reasonably could. Big thanks in advance to anyone who tries to help out.

CodePudding user response:

b = 4 skips 3 out of every 4 pixels. You don't want that. You can see the result is that your output combines two rows of data in each row.

Think about it: For half-sized output you need to skip only every second pixel. But also you need to skip every second row of pixels. You cannot do this with your function as currently written, because it does not understand the image dimensions. The basic approach is:

for (int y = 0; y < height; y  = 2) {
   for (int x = 0; x < height; x  = 2) {
       int index = y * width   x;
       // Write out the value of pixels[index]
   }
}
  •  Tags:  
  • c
  • Related