Aller au contenu

Noob en C en approche


beankylla

Messages recommandés

Du C, Bête et méchant...

 

Bonjour à tous!

 

Je me suis lancé il y a quelques moi, et pour combler une de mes lacunes (je n'avais jamais fait de programmation ça manquait ne serait-ce qu'à ma geekulture) dans un MOOC d'informatique.

 

(et puis j'ai toujours revé d'avoir un diplôme d'Harvard ^^'.

 

Je ne vous la fait pas longue, la pour la première fois je suis aux prises avec un problème dont je ne trouve pas la solution.

 

Le code suivant devrait pouvoir dupliquer et agrandir une image BMP.

La commande est

 

./resize A petit.bmp grand.bmp

 

ou A joue le role de multiplicateur. Si A=1 ça ne fait que copier l'image, et sinon chaque pixel est remplacé par un carré de pixels dont la taille est (pixel*A)

 

Si vous pouviez m'aider sans me donner directement la solution (c'est pédagogique blababla) ca serait top!

 

Merci d'avance!


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

#include "bmp.h"

int main(int argc, char* argv[])
{
    // ensure proper usage
    if (argc != 4)
    {
        printf("Usage: ./resize multiplicator infile outfile\n");
        return 1;
    }
    
    // remember filenames and set multiplier
    char* infile = argv[2];
    char* outfile = argv[3];
    int multi = 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 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;
    }
        
    //plein de variables
    int largeur, hauteur, newlargeur, newhauteur, pad, newpad, tailleimage, taillefichier, repere; 
    
    //calculs des nouveaux elements: hauteur, largeur et padding
    largeur = abs(bi.biWidth);
    hauteur = abs(bi.biHeight);
    pad = (4 - (largeur*sizeof(RGBTRIPLE))%4)%4; 
                 
    newlargeur = largeur * multi;
    newhauteur = hauteur * multi;
    newpad = (4 - (newlargeur*sizeof(RGBTRIPLE))%4)%4;
    
    bi.biWidth = newlargeur;
	bi.biHeight = newhauteur;
	
	//taille de la nouvelle image + du fichier
	tailleimage = abs(newhauteur) * (newlargeur * sizeof(RGBTRIPLE) + newpad);
	taillefichier = tailleimage + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
	    
	//on remet les valeurs à leur place
	bf.bfSize = taillefichier;
	bi.biSizeImage = tailleimage;		
	
    //on pose l'unité de stockage de la ligne
    RGBTRIPLE scancolor[newlargeur];
    
    // write outfile's BITMAPFILEHEADER
    fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr);

    // write outfile's BITMAPINFOHEADER
    fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, outptr);
    
    printf("\nlargeur:%d\nhauteur:%d\n\nnewlargeur:%d\nnewhauteur:%d\n\npad:%d\nnewpad:%d\n\ntailleimage:%d\ntaillefichier:%d\n\nbfSize:%d\nbiSizeimage:%d\n\n",largeur, hauteur,newlargeur, newhauteur,pad, newpad, tailleimage, taillefichier,bf.bfSize,bi.biSizeImage);
    
     
   
        // iterate over infile's scanlines
        for (int i = 0, r = hauteur; i < r; i++)
        {
            repere = 0;
                      
            // iterate over pixels in scanline
            for (int j = 0, v = largeur; j < v; j++)
            {
            
				// temporary storage
				RGBTRIPLE tempcolor;
			
				// read RGB triple from infile (entire line)
				fread(&tempcolor, sizeof(RGBTRIPLE), 1, inptr);
                       
				for (int l = 0; l < multi; l++)
					{
						scancolor[repere].rgbtBlue = tempcolor.rgbtBlue;
						scancolor[repere].rgbtGreen = tempcolor.rgbtGreen;
						scancolor[repere].rgbtRed = tempcolor.rgbtRed;
						repere++;
					}
            }
				//on itère la  réécriture de la ligne
				for (int m = 0; m < multi; m++)
				{
					for (repere = 0; repere < multi; repere++)
					{
						fwrite(&scancolor[repere], sizeof (RGBTRIPLE), 1, outptr);
					}
															 
					for (int u = 0; u < newpad; u++)
					{
						fputc(0x00, outptr);
					}	
				}
					
			// skip over padding, if any
			fseek(inptr, pad, SEEK_CUR);                        
           
           }
	
    // close infile
    fclose(inptr);

    // close outfile
    fclose(outptr);

    // that's all folks
    return 0;
Lien vers le commentaire
Partager sur d’autres sites

l'image de base est celle la (3x3 pixels du vert autour un blanc au milieu):

 

http://meinu.fr/small.bmp

 

en la multipliant par 3 je devrait tomber sur ca (9X9 avec un carré de 3x3 pixels blancs au milieu

 

http://meinu.fr/large.bmp

 

Mais sur le principe ca doit marcher avec n'importe quelle image.

 

Mon soucis est que j'obtiens ca:

 

http://meinu.fr/resize.bmp

 

La taille de l'image est bonne (ca c'est la partie facile) mais j'ai un soucis avec le contenu...

 

Désolé je n'ai pas pu mettre les images en photo apparemment les BMP sont interdits ! :windu:

 

Merci de ton interet! :francais::chinois:

Lien vers le commentaire
Partager sur d’autres sites

Il faut savoir un truc: le format bmp est un format totalement merdik :devil: :devil: :devil:

Regarde Wiki, mais les trucs qu'il faut tenir compte:

  • Les lignes sont des multiples de 4
  • L'image est sauvegardée "upside-down" à l'envers de haut en bas, mais de gauche à droite
  • Il y a éventuellement une palette

Tout cela pour te dire que ton algo est voué à l'échec :ane:

 

Message hors-propos, parce que codé :oops:  :oops:  avec GDI+, en C++ avec la classe Bitmap (ou Image)

Lien vers le commentaire
Partager sur d’autres sites

Ne fonctionne pas avec tous les bmp :fou::zarb:  :zarb::fou:

Il faut ouvrir les fichiers en binaire :siffle:

// XXX CHANGE - include: Need structs RGBTRIPLE, BITMAPFILEHEADER & BITMAPINFOHEADER
#include<Windows.h>

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


int main(int argc, char* argv[]) {
//  Ensure proper usage
    if ((argc != 4) && (argc != 5)) {
        printf("Usage: %s multiplicator infile outfile [version: 1 or 2]\n", argv[0]);

        return 1;
    }

    unsigned short multiplier = atoi( argv[1] );
    if (multiplier == 0) {
        fprintf(stderr, "%s - Error: multiplier must be at least equal to 1\n", argv[0]);

        return 2;
    }

//  Open input file
    FILE* image = fopen(argv[2], "rb");
    if (image == NULL) {
        fprintf(stderr, "%s - Error: Could not open %s\n", argv[0], argv[2]);

        return 3;
    }

//  Open output file
    FILE* new_image = fopen(argv[3], "wb");
    if (new_image == NULL) {
        fclose(image);
        fprintf(stderr, "%s - Error: Could not create %s\n", argv[0], argv[3]);

        return 4;
    }

//  Read infile's BITMAPFILEHEADER & BITMAPINFOHEADER
    BITMAPFILEHEADER bf;
    BITMAPINFOHEADER bi;

    printf("image start:  %d\n", fseek(image, 0, SEEK_SET)); // Useless???
    fread(&bf, sizeof(BITMAPFILEHEADER), 1, image);
    fread(&bi, sizeof(BITMAPINFOHEADER), 1, image);

//  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(new_image);
        fclose(image);
        fprintf(stderr, "%s - Error: Unsupported file format.\n", argv[0]);

        return 5;
    }

    unsigned long width = abs(bi.biWidth), height = abs(bi.biHeight);  // Avoid casting
    unsigned char version = 1, size_RGB = sizeof(RGBTRIPLE);

    if (argc == 5) { version = atoi( argv[4] ); if ((version != 1) && (version != 2)) { version = 1; } }

    if ((width == 0) || (height == 0)) {
        fclose(new_image);
        fclose(image);

        fprintf(stderr, "%s - Error: size 0\n", argv[0]);

        return 6;
    }

//  Skip over headers
    printf("image start1: %d\n", fseek(image, bf.bfOffBits, SEEK_SET)); // Useless???

    bi.biWidth  *= multiplier;
    bi.biHeight *= multiplier;

    unsigned char padding = ((4 - (width * size_RGB) % 4) % 4), new_padding = ((4 - (bi.biWidth * size_RGB) % 4) % 4);
//  unsigned char padding = 0, new_padding = 0;
//  while(((width * size_RGB + padding) % 4) != 0) { padding++; }
//  while(((bi.biWidth * size_RGB + new_padding) % 4) != 0) { new_padding++; }

    printf("%ux%u (Pad: %u, Offset: %lu) -- *%u --> %ux%u (Pad: %u) (Ver: %d)\n", width, height, padding, bf.bfOffBits, multiplier, bi.biWidth, bi.biHeight, new_padding, version);

    bi.biSizeImage = (bi.biHeight * (bi.biWidth * size_RGB + new_padding));
    bf.bfOffBits = (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER));
    bf.bfSize = (bi.biSizeImage + bf.bfOffBits);
//  Maybe should clean other attributes

//  Write outfile's BITMAPFILEHEADER & BITMAPINFOHEADER
    printf("new_image start: %d\n", fseek(new_image, 0, SEEK_SET)); // Useless???
    fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, new_image);
    fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, new_image);

    RGBTRIPLE* one_row = NULL;

    if (version == 1) {
//      Version 1: Write the output bitmap line (with the padding) by line (with the padding)

        unsigned int output_w_size = (bi.biWidth * size_RGB + new_padding); // Avoid casting
        unsigned short pos_w = 0, pos_h = 0, tmp = 0;

        one_row = (RGBTRIPLE*) malloc(output_w_size);
        memset(one_row, 0, output_w_size);

        for(; pos_h < height; ++pos_h) {
            for(pos_w = 0; pos_w < (width * multiplier); pos_w += multiplier) {
                fread((one_row + pos_w), size_RGB, 1, image);

                for(tmp = 1; tmp < multiplier; ++tmp) {
                    one_row[pos_w + tmp] = one_row[pos_w];
                }

//              printf("%u %u: (%u, %u, %u)\n", (height - pos_h), (pos_w + 1), one_row[pos_w].rgbtRed, one_row[pos_w].rgbtGreen, one_row[pos_w].rgbtBlue);
            }

            for(tmp = 0; tmp < multiplier; ++tmp) {
                fwrite(one_row, sizeof(char), output_w_size, new_image);
            }

//          Skip over padding, if any
            fseek(image, padding, SEEK_CUR);
        }
    } else if (version == 2) {
//      Version 2: Write the output bitmap color by color

        unsigned short pos_w = 0, pos_h = 0, mul_h = 0;
        unsigned int tmp = 0; // /!\: Use to write the padding

        one_row = (RGBTRIPLE*) malloc(width * size_RGB);
        memset(one_row, 0, (width * size_RGB));

        for(; pos_h < height; ++pos_h) {
            for(pos_w = 0; pos_w < width; ++pos_w) {
                fread((one_row + pos_w), size_RGB, 1, image);

//              printf("%u %u: (%u, %u, %u)\n", (height - pos_h), (pos_w + 1), one_row[pos_w].rgbtRed, one_row[pos_w].rgbtGreen, one_row[pos_w].rgbtBlue);
            }

            for(mul_h = 0; mul_h < multiplier; ++mul_h) {
                for(pos_w = 0; pos_w < width; ++pos_w) {
                    for(tmp = multiplier; tmp > 0; --tmp) {
                        fwrite((one_row + pos_w), size_RGB, 1, new_image);
                    }
                }

//              Write padding, if any. tmp is equal to 0 here in order to use it
//              to write the padding. The padding is not more than 3 bytes
                fwrite(&tmp, sizeof(char), new_padding, new_image);
            }

//          Skip over padding, if any
            fseek(image, padding, SEEK_CUR);
        }
    }

    if (one_row != NULL) { free(one_row); }

//  Close infile & outfile
    fclose(image);
    fclose(new_image);

    return EXIT_SUCCESS;
}
Lien vers le commentaire
Partager sur d’autres sites

Édition de mon code :windu:

 

Édition de mon code (2 jours plus tard :ane: ) pour proposer 2 approches (suite à mes messages ci-dessous) et un paramètre/ une bascule "version" qui permet de choisir:

  • version == 1 -> On va écrire l'image résultat ligne par ligne en incluant le padding
  • version == 2 -> On va écrire l'image résultat couleur par couleur
Lien vers le commentaire
Partager sur d’autres sites

Le soucis c'est que je dois faire un programme en C et que je n'arrive pas ce qui m'aiderait c'est de savoir ce qui ne marche pas dans mon code.

 

Jusqu'à preuve du contraire mon code est en C99 comme le tien :|

 

D'ailleurs ce bout code n'est pas valide :windu:  "RGBTRIPLE scancolor[newlargeur];"

 

Pourquoi tu dis qu'il est en C++?

 

Je peux le faire en pure C, mais cela ne va servir à rien :siffle:

 

 

 

Quelqu'un voit le soucis? '-_-

 

Tu as un double problème de logique avec cette boucle "for (repere = 0; repere < multi; repere++)"

 

Cela t'apprendras à avoir une bonne indentation, à ne pas avoir de variables qui se trimballent n'importe où (pourquoi la variable repere  (initialisation/ ++/ ...) n'est pas dans les boucles), à déclarer des variables temporaires au milieu de tes boucles ... et avoir trop de variables redondantes (les variables r et v)

 

Sans parler de 2-3 détails (peut-être inutiles) corrigés dans mon code qui lui fonctionne :ane: (et quasi identique au tien, mais avec moins de variables, moins de mémoire utilisée, moins de recopie, 1-2 tests défensifs en plus ...)

 

Édit: Le problème du code original, c'est qu'il écrit les multi premières couleurs enregistrées dans le tableau scancolor, au lieu d'écrire la ligne en entier (c'est à dire multi * width couleurs)

Lien vers le commentaire
Partager sur d’autres sites

Bonjour Foetus!

 

Merci pour ton soutien! En fait l'inclusion de window.h m'a fait penser que c'était pas du C mais ptet du C + quelque chose :ane:.

 

Le developpement étant fait sous fedorah l'inclusion de windows.h n'est pas tellement envisageable :transpi:

 

Sinon, je ne vois pas la soucis de logique avec la boucle:

 

dans la partie précédent cette boucle j'ai attribué à scancolor[repere] les couleurs qui sont sur l'image d'origine, et avec cette boucle je

 

Je suis trop bête le soucis était effectivement là maintenant ca marche!!!

 

Merci t'es un génie! :)

Lien vers le commentaire
Partager sur d’autres sites

Salut!

 

Désolé j'ai les yeux carrés à force de regarder le code ^^...

alors le bmp.h vient dans la machine virtuelle pré-préparée avec laquelle il faut faire les exercixes :p

 

donc je ne sais pas trop d'ou il vient :p!

 

Merci en tout cas c'est super :) je bute toujours sur des détails débiles comme ca!

 

et sans conteste ton code est beauuuucoup plus joli que le mien. Mais je dois rendre mon code et pas celui de quelqu'un d'autre honneteté académique tout ca :)..

 

Merci en tout cas et forcément a bientot pour de nouvelles aventures.... en C! :p

Lien vers le commentaire
Partager sur d’autres sites

Je reviens pour te faire remarquer que, dans ton code, tu peux totalement supprimer la boucle fautive et laisser le travail à fwrite ;) (*)

//					for (repere = 0; repere < newlargeur; repere++)
//					{
//						fwrite(&scancolor[repere], sizeof(RGBTRIPLE), 1, outptr);
//					}

					fwrite(scancolor, sizeof(RGBTRIPLE), newlargeur, outptr);

Et 2-3 détails que j'ai mis dans mon code C (le 2ième code) qui me semble bon de prendre en compte, même si tu veux "plus il est dirty plus c'est le mien :francais: "

  • Ouvre tes fichiers en binaire. C'est le b dans le mode d'accès de fopen "rb", "wb". Cela évite que tes données soient modifiées.
  • Teste si ton fichier en entrée à soit une largeur égale à 0 soit une hauteur égale à 0 (soit les 2). Cela évite de générer une image résultat vide, ce qui peut être confusant: est-ce une erreur? est-ce un résultat normal?
  • Et pour plus tard. scancolor est un tableau. Donc scancolor est un pointeur sur l'adresse de la première case. Parce que &(scancolor[m]), au lieu de (scancolor + m), c'est moche :fou: Et en plus tu pourras t'amuser avec l'arithmétique des pointeurs :ane:

 

Édit:  (*) -> C'est intéressant parce que si fwrite écrit une ligne en entier (sans faire de boucle, quoique pour l'écriture d'un fichier il me semble que les fonctions ne peuvent pas écrire plus d'1 bloc de X (512? 1024?) octects à la fois) c'est une bonne optimisation CPU, parce que tu ne feras que newHauteur appels à fwrite.

 

Par contre niveau mémoire cela se discute  :chinois: Parce que si multi est assez grand ainsi que la largeur de ton image en entrée, scancolor va être assez volumineux.

Lien vers le commentaire
Partager sur d’autres sites

J'avoue que je suis un peu largué!

 

mais petite note comme ca:

 

si tu mets juste fwrite va-t-il bien écrire le fichier bit par bit comme on l'avait fait avant? (je ne suis pas le plus au point sur les pointeurs, etc, j'avoue ... ^ ^

 

pour être franc j'ai un code qui marche et je ne compte plus y toucher.

 

Par contre j'ai encore d'autre exercixes et maintenant que j'ai trouvé le maitre du C je vais venir ici directement au lieu de galérer dans mon coin! (du coup je continuerais ce thread je ne le cloture pas :))

 

Merci beaucoup Foetus!

Lien vers le commentaire
Partager sur d’autres sites

J'avoue que je suis un peu largué!

C'est juste une remarque ;) pense-y à tête réposée.

J'ai édité mon code, avec un nouveau paramètre optionnel :siffle: ou :ane:

 

 

si tu mets juste fwrite va-t-il bien écrire le fichier bit par bit comme on l'avait fait avant? (je ne suis pas le plus au point sur les pointeurs, etc, j'avoue ... ^ ^

Non regarde la documentation de fwrite: le troisième paramètre c'est le nombre d'éléments que tu veux écrire

 

Donc au lieu de faire une boucle et d'écrire couleurs par couleurs, tu peux dire à fwrite d'écrire newLargeur couleurs.

Parce que dans ton code, tu calcules une ligne de ton image de sortie.

 

Et tu peux même aller plus loin, et rajouter le padding à la fin de scancolor, pour dire à fwrite d'écrire (newLargeur couleurs + newPad). :francais:

Ansi supprimer également la boucle qui ecrit les zéros à la fin de chaque ligne de ton image de sortie.

 

Après que va faire fwrite si on lui demande d'écrire X éléments?

Je pense que cela va dépendre de la taille du buffer d'écriture en mémoire (comme je l'ai dit avant à la fin de mon message), mais on ne s'attend pas qu'il écrive élément par élément :mad2:

Lien vers le commentaire
Partager sur d’autres sites

Archivé

Ce sujet est désormais archivé et ne peut plus recevoir de nouvelles réponses.

×
×
  • Créer...