Witam!
Piszę programik do wczytywania pliku bmp bez użycia zewnętrznych bibliotek i do (jak na razie tylko) zapisu do nowego pliku.
Wszystko ładnie się wczytuje i zapisuje, nawet dla plików ważących ~30MB ale ... problem polega na tym, że mimo tego ze bitmapa jest 24bitowa to program podczas wczytywania kolorów "bardziej skomplikowanych"(które zostały namalowane np pędzlem w paincie z win7) odczytuje je błędnie, jako czarny.
Jeśli program napotka tego typu 'błąd' to już do końca wczytywania ciągnie ten błąd(nie czyta dalszych pikseli poprawnie tylko jako czarne).
'Odkryłem', że takim problematycznym kolorem jest np żółty:(R=243;G=193;B=26;). Strzelam, że jest więcej tego typu kolorów, które z niewiadomych mi przyczyn źle się wczytują. Dodam, że program nie wyrzuca żadnych wyjątków(exceptions). Jest na to jakaś rada ? Coś istotnego pominąłem? Bardzo liczę na jakąkolwiek pomoc.
Pewien przykład:
obrazek, który wczytuje:
obrazek,który się zapisał:
Kod całego programu:
//#ifdef WIN32
#include "stdafx.h"
#include <windows.h>
//#endif
#ifndef WIN32
typedef unsigned long DWORD;
typedef unsigned short WORD;
typedef unsigned int UNINT32;
typedef unsigned char BYTE;
typedef long long DWORD64;/**/
#endif
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <stdint.h>
using namespace std;
class bmpfile_magic {
public:
WORD bfType;
};
class bmpfile_header {
public:
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
};
class HeaderDIB{
public:
DWORD biSize; //Wielkość nagłówka informacyjnego. Długość stąd do końca nagłówka – 40, czasem mniej
DWORD biWidth; //Szerokość obrazu w pikselach
DWORD biHeight; //Wysokość obrazu w pikselach
WORD biPlanes; //Liczba warstw kolorów, zwykle 1
WORD biBitCount; //Liczba bitów na piksel
DWORD biCompression; //Algorytm kompresji
DWORD biSizeImage; //Rozmiar samego rysunku
DWORD biXPelsPerMeter; //Rozdzielczość pozioma
DWORD biYPelsPerMeter; //Rozdzielczość pionowa
DWORD biClrUsed; //Liczba kolorów w palecie
BYTE biClrImportant; //Liczba ważnych kolorów w palecie (gdy 0 to wszystkie są ważne); pole to stosuje się przy animacji bitmap poprzez rotację kolorów. Oznacza od którego koloru paleta ma być podmieniana.
BYTE biClrRotation; //flaga sygnalizująca czy ma następować rotacja palety (domyślnie 0-brak rotacji). Jeśli flaga jest ustawiona na 1 następuje podmiana palety.
WORD biReserved;
};
class pixel{
public:
BYTE B,G,R;
};
class RGBQuad {
public:
BYTE rgbBlue;
BYTE rgbGreen;
BYTE rgbRed;
BYTE rgbReserved;
};
const short BITMAP_MAGIC_NUMBER=19778;
void toString(pixel p){
cout<<(int)p.R<<"\t"<<(int)p.G<<"\t"<<(int)p.B<<endl;
}
class Picture{
pixel ** obraz;
pixel ** nowy;
bmpfile_header naglowek;
HeaderDIB NaglowekDIB;
int width,height;
bmpfile_magic bmpmag;
public:
Picture(string nazwa){
fstream plikIN;
plikIN.open(nazwa.c_str(),std::ios::in);
if( ! plikIN.is_open() ){
cout<<"Blad otwarcia pliku: "<<nazwa.c_str()<<endl;
exit(-1);
}
try{
plikIN.read((reinterpret_cast<char*>(&bmpmag)),sizeof(bmpmag));
}
catch (exception& e)
{
cout << "Standard exception: " << e.what() << endl;
}
if(bmpmag.bfType!=BITMAP_MAGIC_NUMBER)
{
cout<<"to nie jest bmp, exiting!";
getchar();
exit(-1);
}
try{
plikIN.read((reinterpret_cast<char*>(&naglowek)),sizeof(naglowek));
}
catch (exception& e)
{
cout << "Standard exception: " << e.what() << endl;
}
cout<<"Rozmiar pliku: "<<nazwa.c_str()<<" wynosi: "<<naglowek.bfSize<<endl;
try{
plikIN.read((reinterpret_cast<char*>(&NaglowekDIB)),sizeof(NaglowekDIB));
}
catch (exception& e)
{
cout << "Standard exception: " << e.what() << endl;
}
width = NaglowekDIB.biWidth;
height= NaglowekDIB.biHeight;
cout<<"Wymiary obrazka: "<<width<<" x "<<height<<endl;
cout<<"Liczba bitow na pixel: "<<NaglowekDIB.biBitCount<<endl;
cout<<"naglowek.bfOffBits: "<<naglowek.bfOffBits<<endl;
try{
plikIN.seekg(naglowek.bfOffBits,ios::beg);
}
catch (exception& e)
{
cout << "Standard exception: " << e.what() << endl;
}
if (NaglowekDIB.biBitCount != 24)
{
//jest jeszcze paleta kolorow<--do odczytania/ominiecia
//load the palette for 8 bits per pixel
int numColours=1<<NaglowekDIB.biBitCount;
RGBQuad *colours;
if(NaglowekDIB.biBitCount==8) {
colours=new RGBQuad[numColours];
plikIN.read( reinterpret_cast<char*>(&colours),sizeof(RGBQuad)*numColours);
}
}
else
{
try{
obraz = new pixel*[height];
for(int i=0 ; i < height ; i++)
obraz[i] = new pixel [width];
}
catch (bad_alloc e)
{
cout << "Standard exception: " << e.what() << endl;
}
//przesuniecie do offsetu danych
//plik.seekg(naglowek.bfOffBits,ios::beg);
cout<<"\tR\tG\tB"<<endl;
for(int i=0 ; i < height ; i++){
for ( int j=0 ; j < width ; j++)
{
pixel p;
p.G=p.B=p.R=0;
try{
plikIN.read( reinterpret_cast<char*>(&p) ,sizeof(pixel) );
}
catch (exception& e)
{
cout << "Standard exception: " << e.what() << endl;
}
if(p.B==0 && p.G==0 && p.R==0)
{
//(w tym miejscu pojawia blad!)
//jesli tu wejdzie to od tego miejsca do konca wczytywania kazdy pixel jest odczytywany jako czarny: r=0 b =0 g=0
//jesli napotka kolory np ten nizej to dalej juz zle wczytuje
//p.B=26;
//p.G=193;
//p.R=243;
}
obraz[i][j]=p;
if ( (width-1) == j)
{
BYTE a=0;
//uzupelnienie wiersza danych do wielokrotnosci 4 zerami
for (int k=0 ; k<width%4;k++) {
try{
plikIN.read( reinterpret_cast<char*>(&a) ,sizeof(a) );
}
catch (exception& e)
{
cout << "Standard exception: " << e.what() << endl;
}
}
}
}
}
}
try{
plikIN.close();
}
catch (exception& e)
{
cout << "Standard exception: " << e.what() << endl;
}
}
void obroc(){
//obrot obrazu o 90st lewo;
/*
//rezerwacja pamieci dla nowego pliku:
nowy = new pixel*[width];
for(int i=0 ; i < width ; i++)
nowy[i] = new pixel [height];
//po rezerwacji:
//obracanki cacanka...
for(int i=0 ; i < height ; i++){
for(int j=0; j < width; j++){
nowy[j][i] = obraz[i][width-j-1];
}
}
*/
nowy = obraz;
}
void save(string nazwa){
fstream plikOUT;
plikOUT.open(nazwa.c_str(), ios::trunc|ios::out);
if( ! plikOUT.is_open() ){
cout<<"Blad otwarcia pliku: "<<nazwa.c_str()<<endl;
//throw new exception("Error: opening file");
}
try
{
plikOUT.write((reinterpret_cast<char*>(&bmpmag)),sizeof(bmpmag));
}
catch (exception& e)
{
cout << "Standard exception: " << e.what() << endl;
}
try{
plikOUT.write((reinterpret_cast<char*>(&naglowek)),sizeof(naglowek));
}
catch (exception& e)
{
cout << "Standard exception: " << e.what() << endl;
}
try{
plikOUT.write((reinterpret_cast<char*>(&NaglowekDIB)),sizeof(NaglowekDIB));
}
catch (exception& e)
{
cout << "Standard exception: " << e.what() << endl;
}
for (int i=0 ; i< height ;i++)
{
try{
plikOUT.write((reinterpret_cast<char*>(nowy[i])),width*sizeof(pixel));
}
catch (exception& e)
{
cout << "Standard exception: " << e.what() << endl;
}
BYTE a=0;
for (int k=0 ; k<width%4;k++) {
try{
plikOUT.write( reinterpret_cast<char*>(&a) ,sizeof(a) );
}
catch (exception& e)
{
cout << "Standard exception: " << e.what() << endl;
}
}
}
try{
plikOUT.close();
}
catch (exception& e)
{
cout << "Standard exception: " << e.what() << endl;
}
/**/
}
};
int /*_t*/main(/*int argc*/)
{
Picture *MyPicture;
string name = "plik.bmp";
// string name = "24bits.bmp";
// string name = "256col.bmp";
// string name = "16col.bmp";
// string name = "monochr.bmp";
string obr = "rotated_.bmp";
try{
MyPicture=new Picture( name );
MyPicture->obroc();
MyPicture->save(obr);
}catch( exception e ){
cout<<"Exc: "<<e.what()<<endl;
getchar();
}
return 0;
}
i w ładniejszej wersji: http://wklej.org/id/855184/
Dzięki za każdą pomoc!