Cześć,
Na zaliczenie przedmiotu na studiach mam wykonać projekt polegający na stworzenie enkodera i dekodera formatu graficznego BMP do nowego pliku graficzne. Obraz ma być przekształcony 256-stopniowej skali szarości oraz kompresowany za pomocą RLE.
Wykonałem dekoder i enkoder zgodnie ze specyfikacją, niestety wszelkie próby zmiany obrazu kolorowego w skalę szarości nie powiodły się.
Bardzo proszę o pomoc/sugestie co robię nie tak.
Zamieszczam kod enkoder.
#include <stdio.h> //obsluga plikow
#include <windows.h>
#include <iostream>
#define BITMAP_ID 0x4D42 //format BMP
#define PSM_ID 0x5053 //format BMP
using namespace std;
typedef struct PSMFILEHEADER
{
short ident;
int roz_pliku;
int off_kolor;
int off_piksel;
} PSMFILEHEADER;
typedef struct PSMINFOHEADER
{
int roz_nag;
int szerokosc;
int wysokosc;
int kompresja;
int rozdz_poz;
int rozdz_pion;
int kolor;
int predykator;
} PSMINFOHEADER;
static unsigned char *LoadBmp(char *filename, BITMAPINFOHEADER *bitmapInfoHeader)
{
FILE *filePtr; // wskaznik pliku
BITMAPFILEHEADER bitmapFileHeader; // naglowek pliku
unsigned char *bitmapImage; // bufor obrazu
int imageIdx = 0; // licznik bajtow obrazu
unsigned char tempRGB; // zmienna zamiany skladowych
// otwiera plik w trybie "read binary"
filePtr = fopen(filename, "rb");
if (filePtr == NULL)
return NULL;
// wczytuje naglowek pliku BMP
fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr);
// wczytuje naglowek obrazu zapisanego w pliku
fread(bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, filePtr);
// sprawdza czy jest to plik BMP
if (bitmapFileHeader.bfType != BITMAP_ID)
{
fclose(filePtr);
cout<<"Bledny plik BMP!"<<endl;
return NULL;
}
else
{
cout<<"Poprawny plik BMP!"<<endl;
}
if (bitmapInfoHeader->biCompression != BI_RGB)
{
fclose(filePtr);
cout<<"Obraz skapresowany!"<<endl;
return NULL;
}
else
{
cout<<"Brak kompresji!"<<endl;
}
/*if (bitmapInfoHeader->biBitCount != 8)
{
fclose(filePtr);
cout<<"To nie jest obraz 8bit!"<<endl;
return NULL;
}
else
{
cout<<"Obraz 8bit!"<<endl;
}*/
// ustawia wskaznik pliku na poczatku danych opisujacych obraz
fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET);
// przydziela pamiec na bufor obrazu
bitmapImage = (unsigned char*)malloc(bitmapInfoHeader->biSizeImage);
// sprawdza, czy pamiec zostala przydzielona
if (!bitmapImage)
{
free(bitmapImage);
fclose(filePtr);
cout<<"Pamiec nie przydzielona!"<<endl;
return NULL;
}
else
{
cout<<"Pamiec przydzielona!"<<endl;
}
// wczytuje dane obrazu
fread(bitmapImage, 1, bitmapInfoHeader->biSizeImage, filePtr);
// sprawdza czy operacja powiodla sie
if (bitmapImage == NULL)
{
fclose(filePtr);
cout<<"Nie wczytano obrazu!"<<endl;
return NULL;
}
else
{
cout<<"Wczytano obraz!"<<endl<<endl;
}
// zamienia skladowe R i B
for (imageIdx = 0; imageIdx < (int)bitmapInfoHeader->biSizeImage; imageIdx+=3)
{
tempRGB = bitmapImage[imageIdx];
bitmapImage[imageIdx] = bitmapImage[imageIdx + 2];
bitmapImage[imageIdx + 2] = tempRGB;
}
// zamyka plik i zwraca wskaznik bufora zawierajacego obraz
fclose(filePtr);
return bitmapImage;
}
static int WritePSM(char *filename, int width, int height, unsigned char *imageData)
{
FILE *filePtr; // wskaznik pliku
BITMAPFILEHEADER bitmapFileHeader; // naglowek pliku BMP
BITMAPINFOHEADER bitmapInfoHeader; // naglowek obrazu BMP
PSMFILEHEADER PSMFileHeader; // naglowek pliku PSM
PSMINFOHEADER PSMInfoHeader; // naglowek obrazu PSM
RGBQUAD quad;
int tryb, imageIdx; // tryb barwy, indeks obrazu
unsigned char tempRGB; // zmienna zamiany skladowych
unsigned int skala_szar;
// otwiera plik do zapisu w trybie "writing binary"
filePtr = fopen(filename, "wb");
if (!filePtr)
return 0;
// definiuje naglowek pliku
PSMFileHeader.roz_pliku = sizeof(PSMFILEHEADER);
PSMFileHeader.ident = PSM_ID;
PSMFileHeader.off_kolor = width*abs(height)*3;
PSMFileHeader.off_piksel = sizeof(PSMFILEHEADER) + sizeof(PSMINFOHEADER);
// definiuje naglowek PSM
PSMInfoHeader.roz_nag = sizeof(PSMINFOHEADER);
PSMInfoHeader.szerokosc = width;
PSMInfoHeader.wysokosc = height;
PSMInfoHeader.kompresja = BI_RGB;
PSMInfoHeader.rozdz_poz = bitmapInfoHeader.biXPelsPerMeter;
PSMInfoHeader.rozdz_pion = -bitmapInfoHeader.biYPelsPerMeter;
cout<<"Wybierz czy obraz ma byc kolorowy czy w skali szarosci: "<<endl<<endl;
cout<<"Obraz kolorowy - 1 Skala szarosci - 0"<<endl;
cin>>tryb;
cout<<endl;
PSMInfoHeader.kolor=tryb;
cout<<"Obraz: "<<PSMInfoHeader.kolor<<endl;
int predykator;
// zapisuje naglowek pliku PSM
fwrite(&PSMFileHeader, 1, sizeof(PSMFILEHEADER), filePtr);
// zapisuje naglowek PSM
fwrite(&PSMInfoHeader, 1, sizeof(PSMINFOHEADER), filePtr);
if(tryb==1) //obraz kolorowy
{
fwrite(imageData, 1, PSMFileHeader.off_kolor, filePtr);
}
else // obraz w skali szarosci
{
for (imageIdx = 0; imageIdx < (int)bitmapInfoHeader.biSizeImage; imageIdx++)
{
tempRGB = (int)(0.229*imageData[imageIdx]+0.587*imageData[imageIdx+1]+0.114*imageData[imageIdx+2]);
imageData[imageIdx]=tempRGB;
}
fwrite(imageData, 1, PSMFileHeader.off_kolor, filePtr);
}
// zamyka plik
fclose(filePtr);
cout<<endl;
cout<<"Kodowanie wykonano poprawnie!"<<endl;
cout<<"Utworzono plik: "<<endl;
cout<<"Rozmiar pliku: "<<PSMFileHeader.off_kolor<<endl;
cout<<"Szerokosc obrazu: "<<PSMInfoHeader.szerokosc<<endl;
cout<<"Wysokosc obrazu: "<<PSMInfoHeader.wysokosc<<endl;
cout<<"Rozdzielczosc pozioma: "<<PSMInfoHeader.rozdz_poz<<endl;
cout<<"Rozdzielczosc pionowa: "<<PSMInfoHeader.rozdz_pion<<endl;
cout<<"Bit/pixel: "<<bitmapInfoHeader.biBitCount<<endl;
cout<<"Paleta kolorow: "<<bitmapInfoHeader.biClrUsed<<endl;
cout<<"Obraz: ";
if(PSMInfoHeader.kolor==1)
cout<<"Kolorowy"<<endl;
else
cout<<"Skala Szarosci"<<endl;
cout<<"Kompresja: "<<PSMInfoHeader.kompresja<<endl;
return 1;
}
int main()
{
// wczytywanie obrazu w formacie BMP
char *filename = "./obraz.bmp";
BITMAPINFOHEADER myBitmapInfoHeader;
unsigned char *bitmapImage;
bitmapImage = LoadBmp(filename, &myBitmapInfoHeader);
// zapis obrazu w formacie PSM
char* filename2 = "./obraz.psm";
int result, width, height;
width = (int) myBitmapInfoHeader.biWidth;
height = (int) myBitmapInfoHeader.biHeight;
result = WritePSM(filename2, width, height, bitmapImage);
}
Pozdrawiam,
Meniu