Thread: Extra junk at the end of Hex after creation of 8bit BMP

  1. #1
    Registered User
    Join Date
    Feb 2013
    Posts
    17

    Extra junk at the end of Hex after creation of 8bit BMP

    Hello, I found some code to read a write 24 bit BMP here:
    Reading a bitmap image

    I want however to read only 8 bit BMPs and so I have been trying to understand the above code as to modify it for 8 bit processing. The code is:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    
    /* Global */
    int height, width;
    
    
    //***************** Structures  *******************//
    typedef struct{
        char type[2];             // file type
        unsigned int size;         // file size in bytes
        unsigned short int reserved1,reserved2;
        unsigned int offset;     // offset to image data
    }HEADER;
    
    
    
    
    typedef struct{
        unsigned char RGB[3]; 
    }RGB;
    
    
    typedef struct{
        unsigned int size;
        int width,height;
        unsigned short int planes;
        unsigned short int bpp;
        unsigned int compression;
        unsigned int imagesize;
        int xresolution,yresolution;
        unsigned int colours;
        unsigned int impcolours;
    }INFOHEADER;
    
    
    
    
    // ********** Verify if the file exist **********
    FILE* exist(char *name){
        FILE *tmp;
        tmp = fopen(name,"rb");
        if (!tmp){
            printf("\nERROR: Incorrect file or not exist!\n");
            exit(0);
        }
        fseek(tmp,0,0);
        return(tmp);
    }
    
    
    // ********** Verify if the file is BMP *********
    void isBMP(FILE* arq, HEADER head, INFOHEADER info){
        char type[3];
        unsigned short int bpp;
        fseek(arq,0,0);
        fread(type,1,2,arq);
        type[2] = '\0';
        
        fseek(arq,28,0);
        fread(&bpp,1,2,arq);
        
        if (strcmp(type,"BM") || (bpp != 8)){
                printf("\nThe file is not BMP format or is not 8 bits\n");
                exit(0);
        }
    }
    
    
    // ********** Read BMP info from file **********
    INFOHEADER readInfo(FILE* arq){
        INFOHEADER info;
        
        // Image Width in pixels
        fseek(arq,18,0);
        fread(&info.width,1,4,arq);
        //printf("infowidth: %d\n", info.width);
    
    
        // Image Height in pixels
        fseek(arq,22,0);
        fread(&info.height,1,4,arq);
        //printf("infoheight: %d\n", info.height);
    
    
        // Color depth, BPP (bits per pixel)
        fseek(arq,28,0);
        fread(&info.bpp,1,2,arq);
        
        // Compression type
        // 0 = Normmally
        // 1 = 8 bits per pixel
        // 2 = 4 bits per pixel
        fseek(arq,30,0);
        fread(&info.compression,1,4,arq);
        //printf("compression: %d\n", info.compression);
        
        // Image size in bytes
        fseek(arq,34,0);
        fread(&info.imagesize,1,4,arq);
        
        // Number of color used (NCL)
        // value = 0 for full color set
        fseek(arq,46,0);
        fread(&info.colours,1,4,arq);
        
        // Number of important color (NIC)
        // value = 0 means all collors important
        fseek(arq,50,0);
        fread(&info.impcolours,1,4,arq);
        
        return(info);
    }
    
    
    // ********** Create Matrix **********
    RGB** createMatrix(){
        RGB** Matrix;
        int i;
        Matrix = (RGB**) malloc(height * sizeof(RGB*));
        if (Matrix == NULL){
            perror("***** No memory available *****");
            exit(0);
        }
        for (i=0;i<height;i++){
            Matrix[i] = (RGB*) malloc(width * sizeof(RGB));
            if (Matrix[i] == NULL){
            perror("***** No memory available *****");
                    exit(0);
            }
        }
        return(Matrix);
    }
    
    
    void loadImage(FILE* arq, RGB** Matrix){
        int i,j;
        RGB tmp;
        long pos = 51;
        
        fseek(arq,0,0);
    
    
        for (i=0; i<height; i++){
            for (j=0; j<width; j++){
                   pos+= 3;
                fseek(arq,pos,0);
                fread(&tmp,(sizeof(RGB)),1,arq);
                Matrix[i][j] = tmp;
             }
        }
    //printf("size of Matrix: %li\n",(sizeof(Matrix)));
    //printf("size of rgb: %li\n",(sizeof(RGB)));
    }
    
    
    
    
    // ********** Image Output **********
    void writeBMP(RGB **Matrix, HEADER head, FILE* arq){
        FILE* out;
        int i,j;
        RGB tmp;
        long pos = 51;
    
    
        char header[54];
        fseek(arq,0,0);
        fread(header,54,1,arq);
        out = fopen("out.bmp","wb");
    
    
        fseek(out,0,0);
        fwrite(header,54,1,out);
    
    
        //printf("\nMatrix = %c\n", Matrix[0][0].RGB[0]);
        for(i=0;i<height;i++){
            for(j=0;j<width;j++){
                pos+= 3;
                //printf("pos %li \n",pos);
                fseek(out,pos,0);
                tmp = Matrix[i][j];
                fwrite(&tmp,(sizeof(RGB)),1,out);
            }
        }
        fflush(out);
        fclose(out);
    }
    
    
    // ********** Free memory allocated for Matrix **********
    void freeMatrix(RGB** Matrix,INFOHEADER info)
    {
        int i;
        int lines = info.height;
    
    
        for (i=0;i<lines;i++){
            free(Matrix[i]);
        }
        free(Matrix);
    }
    
    
    
    
    /* in your main program you just call */
    //    FILE* arq; /* the bitmap file 24 bits */
    /*    RGB** Matrix_aux, Matrix;
        INFOHEADER info;
        info = readInfo(FILE* arq);
        height = info.height;
        width = info.width;
         
        Matrix_aux = createMatrix();
        Matrix = loadImage(arq,Matrix_aux);
    */
    
    
    main(){
    
    
        FILE *arq; 
        RGB  **Matrix;
        INFOHEADER info;
        HEADER head;
        char name[15];
    
    
        printf("Type the image's name : ");
        scanf("%s",name);
    
    
        arq = exist(name);
        isBMP(arq,head,info);
        info = readInfo(arq);
        height = info.height;
    //    printf("height : %d\n", height);
    
    
        width = info.width;
    //    printf("width: %d \n", width);
    
    
        Matrix = createMatrix();
        loadImage(arq,Matrix);
        writeBMP(Matrix,head,arq);
        freeMatrix(Matrix,info);
    }
    The above code runs with no errors and reads in an 8bit BMP and then saves it as out.bmp however it is much larger then in input file (1MB in -->3.1MB out). Opening the output file in an HEX editor it is clear that the output image is the same however is 3 times as long! the last 2 thirds of the file is the same sequence repeated over and over. If this section is deleted in the hex editor the file then drops to 1MB. (NOTE in the image still opens if this section is not deleted.)

    What part of the code is causing these extra junk values??

    Thanks

  2. #2
    Programming Wraith GReaper's Avatar
    Join Date
    Apr 2009
    Location
    Greece
    Posts
    2,738
    You may want to be more careful with alignment in your HEADER struct.
    Also, remember that BMP's 1, 4 and 8 bit modes use palettes and indices to these palettes instead of color values.
    Last but not least, you should check the return value of every fread at least, you don't know where the file might end.
    Devoted my life to programming...

  3. #3
    Registered User
    Join Date
    Feb 2013
    Posts
    17
    I think the issue is that I am allocating the amount of memory for a 24 bit image i.e 3 bytes of info for each pixel (see line 22 above) this means that when I malloc the matrix I have a pointer to a pointer to a char that is 3 bytes long..... Thus, when I read in the data from the source file it must run out of information before it is done filling the matrix. Then the remaining elements in the matrix must for some reason be filled with the last read element... Does this make sense?? The solution would then be to just change the size of the char to 1 byte per pixel (8 bit image) and then change the step size when reading and writing the data to 1??


    ... I got rid of the RGB structure and just made the matrix an unsigned char**, I also changed the step size to 1 when loop reading and writing the data as well as the start position.

    When run the program outputs a file that cant be read however looking at the hex file it looks very much alike the source hex.... the output is smaller then the source by 1024 bytes. Any ideas???

    Note the source image is 1024*1024 8 bit image
    Last edited by bnickerson; 05-13-2013 at 06:36 AM.

  4. #4
    Registered User
    Join Date
    Feb 2013
    Posts
    17
    I found that there are an extra 1024 bytes at the end of the file that I did not consider.. I dont know what they are and am hoping someone can help me understand this. I thought that the 8 bit image had a 54 byte header + height*width bytes of pixel information, ex 1024*1024+54 = 1048630 bytes for a 1024^2 8 bit bmp. However the image I have is actually 1024 bytes longer then this value i.e 1049654 bytes. I dont know what is going on here, can any one explain this?
    Last edited by bnickerson; 05-13-2013 at 07:13 AM.

  5. #5
    Registered User
    Join Date
    May 2012
    Posts
    1,066
    GReaper told you already that the 8 bit BMP uses an additional color table/palette.
    According to the file format description, each entry in the color table uses 4 bytes (there are exceptions, you need to check the header information).
    256 colors, 4 bytes each -> 256 * 4 = 1024.

    In other words, you can't just copy the code you've found but need to study the file format description.

    Bye, Andreas

  6. #6
    Registered User
    Join Date
    Feb 2013
    Posts
    17
    Thank you to both GReaper and AndiPersti. This was the fist time I have worked with images and am still new to C programming but you both provided the answer in as many words.

    The working code is as follows (Note the bulk code came from the link above for 24bit images. Only minor changes were made to get the 8bit config with the help of both GReaper and AndiPersti)

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    
    /////////////// Structures
    typedef struct{
    	char type[2]; 			// file type
    	unsigned int size; 		// file size in bytes
    	unsigned short int reserved1,reserved2;
    	unsigned int offset; 	// offset to image data
    }HEADER;
    
    
    
    
    typedef struct{
    	unsigned int size;
    	int width,height;
    	unsigned short int planes;
    	unsigned short int bpp;
    	unsigned int compression;
    	unsigned int imagesize;
    	int xresolution,yresolution;
    	unsigned int colours;
    	unsigned int impcolours;
    	unsigned char colourtable[1024]; // 256*4 bytes long
    }INFOHEADER;
    
    
    
    
    /////////////// Verify if the file exist
    FILE* exist(char *name){
    	FILE *tmp;
    	tmp = fopen(name,"rb");
    	if (!tmp){
    		printf("\nERROR: Incorrect file or not exist!\n");
    		exit(0);
    	}
    	fseek(tmp,0,0);
    	return(tmp);
    }
    
    
    /////////////// Verify if the file is 8 bit BMP 
    void isBMP(FILE* arq){
    	char type[3];
    	unsigned short int bpp;
    	fseek(arq,0,0);
    	fread(type,1,2,arq);
    	type[2] = '\0';
    	
    	fseek(arq,28,0);
    	fread(&bpp,1,2,arq);
    	
    	if (strcmp(type,"BM") || (bpp != 8)){
    	        printf("\nThe file is not BMP format or is not 8 bits\n");
    	        exit(0);
    	}
    }
    
    
    
    
    /////////////// Read BMP info from file 
    INFOHEADER readInfo(FILE* arq){
    	INFOHEADER info;
    	
    	// Image Width in pixels
    	fseek(arq,18,0);
    	fread(&info.width,1,4,arq);
    	printf("info.width: %d\n", info.width);
    
    
    	// Image Height in pixels
    	fseek(arq,22,0);
    	fread(&info.height,1,4,arq);
    	printf("info.height: %d\n", info.height);
    
    
    	// Color depth, BPP (bits per pixel)
    	fseek(arq,28,0);
    	fread(&info.bpp,1,2,arq);
    	printf("info.bbp: %d\n", info.bpp);
    	
    	// Compression type
    	// 0 = Normmally
    	// 1 = 8 bits per pixel
    	// 2 = 4 bits per pixel
    	fseek(arq,30,0);
    	fread(&info.compression,1,4,arq);
    	printf("info.compression: %d\n", info.compression);
    	
    	// Image size in bytes
    	fseek(arq,34,0);
    	fread(&info.imagesize,1,4,arq);
    	printf("info.imagesize: %d\n", info.imagesize);
    
    
    	
    	// Number of color used (NCL)
    	// value = 0 for full color set
    	fseek(arq,46,0);
    	fread(&info.colours,1,4,arq);
    	printf("info.colours: %d\n", info.colours);
    
    
    	
    	// Number of important color (NIC)
    	// value = 0 means all collors important
    	fseek(arq,50,0);
    	fread(&info.impcolours,1,4,arq);
    
    
    	// Colour table
    	fseek(arq,54,0);
    	fread(&info.colourtable,256,4,arq);
    	
    	return(info);
    }
    
    
    /////////////// Create Matrix 
    unsigned char** createMatrix(INFOHEADER info){
    	unsigned char** Matrix;
    	int i;
    
    
    	Matrix = (unsigned char**) malloc(info.height * sizeof(unsigned char*));
    	if (Matrix == NULL){
        	perror("***** No memory available *****");
    	    exit(0);
    	}
    	for (i=0;i<info.height;i++){
        	Matrix[i] = (unsigned char*) malloc(info.width * sizeof(unsigned char));
    	    if (Matrix[i] == NULL){
    	    perror("***** No memory available *****");
    	            exit(0);
    	    }
    	}
    	return(Matrix);
    }
    
    
    /////////////// Load image data to matrix
    void loadImage(FILE* arq, INFOHEADER info, unsigned char** Matrix){
    	int i,j;
    	unsigned char tmp;
    	int test;
    	long pos = 1077; // header + colourtable length is 1078 start reading pixel info from here
    	
    	fseek(arq,0,0);
    
    
    	for (i=0; i<info.height; i++){
    		for (j=0; j<info.width; j++){
    	       	pos+= 1;
    	        fseek(arq,pos,0);
    	        fread(&tmp,(sizeof(unsigned char)),1,arq);
    	        Matrix[i][j] = tmp;
    			//printf("Matrix[%i][%i]= %i \n", i,j,tmp);
    	 	}
    	}
    }
    
    
    
    
    // ********** Image Output **********
    void writeBMP(unsigned char **Matrix, HEADER head, INFOHEADER info, FILE* arq){
    	FILE* out;
    	int i,j;
    	unsigned char tmp;
    	long pos = 1077;
    
    
    	char header[54];
    	char colourtable[1024];
    
    
    	fseek(arq,0,0);
    	fread(header,54,1,arq); 		// read header 54 bytes
    
    
    	out = fopen("out.bmp","wb");
    
    
    	fseek(out,0,0);
    	fwrite(header,54,1,out); 		// write header to output
    
    
    	fseek(out,54,0);
    	fwrite(info.colourtable,1024,1,out); // write colour table to output
    
    
    	for(i=0;i<info.height;i++){
    		for(j=0;j<info.width;j++){
    			pos+= 1;
    			fseek(out,pos,0);
    			tmp = Matrix[i][j];
    			fwrite(&tmp,(sizeof(unsigned char)),1,out);
    		}
    	}
    	fflush(out);
    	fclose(out);
    }
    
    
    // ********** Free memory allocated for Matrix **********
    void freeMatrix(unsigned char** Matrix,INFOHEADER info)
    {
    	int i;
    	int lines = info.height;
    
    
    	for (i=0;i<lines;i++){
    		free(Matrix[i]);
    	}
    	free(Matrix);
    }
    
    
    
    
    /* in your main program you just call */
    //	FILE* arq; /* the bitmap file 24 bits */
    /*	RGB** Matrix_aux, Matrix;
    	INFOHEADER info;
    	info = readInfo(FILE* arq);
    	height = info.height;
    	width = info.width;
    	 
    	Matrix_aux = createMatrix();
    	Matrix = loadImage(arq,Matrix_aux);
    */
    
    
    main(){
    
    
    	FILE *arq; 
    	unsigned char  **Matrix;
    	INFOHEADER info;
    	HEADER head;
    	char name[15];
    
    
    	printf("Type the image's name : ");
    	scanf("%s",name);
    
    
    	arq = exist(name);
    	isBMP(arq);
    	info = readInfo(arq);
    
    
    
    
    
    
    	Matrix = createMatrix(info);
    	loadImage(arq,info,Matrix);
    	writeBMP(Matrix,head,info,arq);
    	freeMatrix(Matrix,info);
    }

  7. #7
    Programming Wraith GReaper's Avatar
    Join Date
    Apr 2009
    Location
    Greece
    Posts
    2,738
    Does it actually work?! I'm impressed! I guess you got lucky with the packing of your HEADER struct.
    Devoted my life to programming...

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. 8Bit Grayscale Bitmap
    By Shinobii in forum C Programming
    Replies: 1
    Last Post: 07-06-2012, 01:02 PM
  2. 3 each 8bit chars from a 32bit long int
    By Brucewd in forum C Programming
    Replies: 19
    Last Post: 08-02-2011, 06:27 PM
  3. Folders in 8bit
    By epi_jimenez in forum C Programming
    Replies: 3
    Last Post: 04-10-2009, 10:44 AM
  4. Replies: 2
    Last Post: 12-16-2008, 02:43 PM
  5. 8Bit Bitmaps Problem
    By cboard_member in forum Game Programming
    Replies: 3
    Last Post: 08-19-2005, 05:55 PM

Tags for this Thread