Etirer/rétrécir une image bmp sans stretchblt

Description

C'est un code qui permet de changer la résolution d'une image avec deux méthodes pour l'agrandissement (avec ou sans moyenne)
Le principe est expliqué dans un fichier txt joint dans le zip
3 fonctions : lire un bmp24 bits, le scaler, et l'enregistrer

Lancez le prog, il ouvrira image.bmp et créera une image de double taille avec ou sans la moyenne et une image de taille la moitié.
On peut aussi stretcher l'image comme l'on veut : agrandir un coté et rétrecir l'autre, ou toute autre configuration

Source / Exemple :


/*-----------------------------------------------------------------------------------------------*
//
//                                      ScaleImage
//
//Fait par         : MaegisInstinct (maegisinstinct@free.fr)
//
//le               : 29/07/2004 à 20:27:37
//
//Description      : Permet d'etirer/étrecir une image
					 Lire le .txt pour avoir des explications sur la méthode de Scale
//
/*----------------------------------------------------------------------------------------------*/

#include <windows.h>

#define PARTDEC(a) (a-(double)(int)a)		//retourne la partie décimale d'un double

struct PIXEL
{
	BYTE b;
	BYTE g;
	BYTE r;
};

/*--------------------------------*/
//Change la resolution d'une image
/*--------------------------------*/
void Scale(const PIXEL* src,DWORD srcwidth,DWORD srcheight,PIXEL* data,DWORD datawidth,DWORD dataheight,BOOL moyenne_etirement)
{
	DWORD	i,j,k,l;
	PIXEL*	save_data; 
	double	xratio,yratio;
	double	precx = 0.0,precy = 0.0;
	double	currentx,currenty;
	double	coeff;						//somme des coeffs pour la moyenne
	double	temp;
	double	somme_r,somme_g,somme_b;

	xratio = (double)srcwidth/(double)datawidth;
	yratio = (double)srcheight/(double)dataheight;
	save_data = data;
	currenty = 0.0;

	for(j=0;j<dataheight;j++)			//Pour chaque pixel du but
	{
		currentx = 0.0;
		currenty += yratio;
		for(i=0;i<datawidth;i++)
		{
			currentx += xratio;
			coeff = 0.0;
			somme_r = 0.0;
			somme_g = 0.0;
			somme_b = 0.0;
		
			//Calcul de la moyenne
			for(l=0;l<(unsigned int)yratio+1;l++)		//Pour chaque pixel de la source contenu dans le pixel du but
			{
				for(k=0;k<(unsigned int)xratio+1;k++)
				{
				//Coeff en x
					if (k==0)
						temp = 1.0-PARTDEC(precx);
					else if (k==(unsigned int)xratio)
						temp = xratio-(double)((int)xratio-1)-(1.0-PARTDEC(precx));
					else
						temp = 1;
				//Coeff en y
					if (l==0)
						temp = temp*(1.0-PARTDEC(precy));
					else if (l==(unsigned int)yratio)
						temp = temp*(yratio-(double)((int)yratio-1)-(1.0-PARTDEC(precy)));

					if ((int)precx+k<srcwidth && (int)precy+l<srcheight)		//si on est dans les limites
					{
						somme_r += src[(int)precx+k+((int)precy+l)*srcwidth].r*temp;
						somme_g += src[(int)precx+k+((int)precy+l)*srcwidth].g*temp;
						somme_b += src[(int)precx+k+((int)precy+l)*srcwidth].b*temp;
						coeff += temp;
					}

					if (moyenne_etirement)  //Moyenne lors de l'etirement si souhaité
					{
						if (xratio<1. && (int)currentx-(int)precx==1 && PARTDEC(currentx) != 0.)
						{
							temp = PARTDEC(currentx);
							somme_r += src[(int)precx+1 + (int)precy*srcwidth].r*temp;
							somme_g += src[(int)precx+1 + (int)precy*srcwidth].g*temp;
							somme_b += src[(int)precx+1 + (int)precy*srcwidth].b*temp;
							coeff += temp;
							temp = -1.0;
						}
						if (yratio<1. && (int)currenty-(int)precy==1 && PARTDEC(currenty) != 0.)
						{
							if (temp == -1.0)		//on compte le quatrieme carré
							{
								temp = PARTDEC(currenty)*PARTDEC(currentx);
								somme_r += src[(int)precx+1 + ((int)(precy)+1)*srcwidth].r*temp;
								somme_g += src[(int)precx+1 + ((int)(precy)+1)*srcwidth].g*temp;
								somme_b += src[(int)precx+1 + ((int)(precy)+1)*srcwidth].b*temp;
								coeff += temp;
							}
							temp = PARTDEC(currenty);
							somme_r += src[(int)precx + ((int)(precy)+1)*srcwidth].r*temp;
							somme_g += src[(int)precx + ((int)(precy)+1)*srcwidth].g*temp;
							somme_b += src[(int)precx + ((int)(precy)+1)*srcwidth].b*temp;
							coeff += temp;
						}
					}
				}
			}
			data->r = (BYTE)(somme_r/coeff);
			data->g = (BYTE)(somme_g/coeff);
			data->b = (BYTE)(somme_b/coeff);
			data++;
			precx = currentx;
		}
		precy = currenty;
		precx = 0.0;
	}
	data = save_data;
}

/*---------------------------------*/
//Enregistre un fichier bmp24 bits
/*---------------------------------*/
BOOL SaveBmp24(char *path,PIXEL *data,int width,int height)
{
	BITMAPFILEHEADER	fileheader;
	BITMAPINFOHEADER	infoheader;
	HANDLE				fichier;
	DWORD				dummy;
	int					size;
	int					bourrage = 0;
	int					i,j,k;
	char				*image = NULL;

	fichier = CreateFile(path,
						 GENERIC_WRITE,
						 FILE_SHARE_READ,
						 NULL,
						 CREATE_ALWAYS,
						 FILE_ATTRIBUTE_NORMAL,
						 NULL);
	if (fichier == INVALID_HANDLE_VALUE)
		return FALSE;

	fileheader.bfType = 0x4D42;	//"bm"
	fileheader.bfSize = 54 + width*height*3;
	fileheader.bfReserved2 = 0;
	fileheader.bfReserved1 = 0;
	fileheader.bfOffBits = 54;

	infoheader.biSize = sizeof(BITMAPINFOHEADER);
	infoheader.biWidth = width;
	infoheader.biHeight = height;
	infoheader.biPlanes = 1;
	infoheader.biBitCount = 24;
	infoheader.biCompression = 0;
	infoheader.biSizeImage = width*height;
	infoheader.biXPelsPerMeter = 0;
	infoheader.biYPelsPerMeter = 0;
	infoheader.biClrImportant = 0;
	infoheader.biClrUsed = 0;

	while ((3*width+bourrage) % 4 != 0)	//calcul du nb de bits de bourrage (3 car 24bits = 3octs)
		bourrage++;

	size = width*height;

	image = new char[size*3+bourrage*height];
	if (image == NULL)
	{
		CloseHandle(fichier);
		return FALSE;
	}
	
	for(i=0;i<height;i++)
	{
		for(j=0;j<width;j++)
		{
			image[i*(3*width+bourrage)+3*j]		= data[(height-i-1)*width+j].b;
			image[i*(3*width+bourrage)+3*j+1]	= data[(height-i-1)*width+j].g;
			image[i*(3*width+bourrage)+3*j+2]	= data[(height-i-1)*width+j].r;
		}
		for(k=1;k<bourrage;k++)
			image[i*(3*width+bourrage)+3*j+k] = 0;
	}

	WriteFile(fichier,&fileheader,14,&dummy,NULL);
	WriteFile(fichier,&infoheader,40,&dummy,NULL);
	WriteFile(fichier,image,size*3+bourrage*height,&dummy,NULL);

	CloseHandle(fichier);
	return TRUE;
}

/*---------------------*/
//Ouvre un bmp 24 bits
/*---------------------*/
BOOL GetBmp24(char* chemin,PIXEL **data,DWORD& width,DWORD& height)
{
	BITMAPFILEHEADER	fileheader;
	BITMAPINFOHEADER	infoheader;
	HANDLE				fichier;
	DWORD				dummy,i,j;
	DWORD				size;
	DWORD				bourrage	= 0;
	PIXEL				temp;
	BYTE				*buffer		= NULL;

	fichier = CreateFile(chemin,
						 GENERIC_READ,
						 FILE_SHARE_READ,
						 NULL,
						 OPEN_EXISTING,
						 FILE_ATTRIBUTE_NORMAL,
						 NULL);
	if (fichier == INVALID_HANDLE_VALUE)
		return FALSE;

	ReadFile(fichier,&fileheader,14,&dummy,NULL);
	ReadFile(fichier,&infoheader,40,&dummy,NULL);
	width = infoheader.biWidth;
	height = infoheader.biHeight;

	while ((3*width+bourrage) % 4 != 0)		//gestion du bourrage
		bourrage++;

	if (fileheader.bfType != 0x4D42 || infoheader.biBitCount != 24 
		|| infoheader.biCompression != 0)
	{
		CloseHandle(fichier);
		return FALSE;
	}
	size = width*height;

	buffer = new BYTE[size*3+bourrage*height];
	if (buffer == NULL)
		return FALSE;

	SetFilePointer(fichier,fileheader.bfOffBits,NULL,FILE_BEGIN);

	ReadFile(fichier,buffer,size*3+bourrage*height,&dummy,NULL);

	(*data) = new PIXEL[size];
	if ((*data) == NULL)
	{
		delete[] buffer;
		return FALSE;
	}

	for(i=0;i<height;i++)
	{
		memcpy((*data)+(i*width),buffer+i*(3*width+bourrage),width*3);
	}

	//remet dans le bon sens
	for(i=0;i<(height/2);i++)
	{
		for(j=0;j<width;j++)
		{
			temp  = (*data)[i*width+j];
			(*data)[i*width+j] = (*data)[(height-1-i)*width+j];
			(*data)[(height-1-i)*width+j] = temp;
		}
	}
	

	CloseHandle(fichier);
	delete[] buffer;
	return TRUE;
}

/*--------------*/
//Fonction Main
/*--------------*/
int APIENTRY WinMain(HINSTANCE hInstance,
					 HINSTANCE hPrevInstance,
					 LPSTR lpCmdLine,
					 int nShowCmd)
{
	PIXEL *data,*scaleddata;
	DWORD width,height;

	if (GetBmp24("image.bmp",&data,width,height))
	{
		scaleddata = new PIXEL[width*height*4];
		Scale(data,width,height,scaleddata,width/2,height/2,FALSE);
		SaveBmp24("Halfimage.bmp",scaleddata,width/2,height/2);
		Scale(data,width,height,scaleddata,width*2,height*2,FALSE);
		SaveBmp24("Doubleimage.bmp",scaleddata,width*2,height*2);
		Scale(data,width,height,scaleddata,width*2,height*2,TRUE);
		SaveBmp24("Doubleimagemoyenne.bmp",scaleddata,width*2,height*2);
		
		delete[] data;
		delete[] scaleddata;
		return 0;
	}
	return -1;
}

Conclusion :


La difference en l'agrandissement avec ou sans la moyenne se voit sur des petites images
(Essayez sur des 8*8 ou 16*16 ou sur des icones à agrandir fortement)

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.