Для аналогичных целей я храню данные в виде несжатого растрового изображения с массивом указателей, который отображает их в виде двумерного пиксельного массива для прямого доступа к пикселям. Поэтому я думаю, что вы должны сделать что-то подобное. В некоторых случаях мне нужны также разные типы. Тогда класс, содержащий данные изображения, имеет дескриптор типа обычно float*
и DWORD*
и двумерный массив, сопоставленный с одномерным массивом, который представляет изображение. Это отделит кодировку файла изображения от его представления. Из этого вам просто нужен загрузчик / заставка, которая кодирует / декодирует между этим представлением и файлом.
Вот пример того, что я использую (на C ++ / VCL ):
//------------------------------------------------------------------------------
int picture_load(Graphics::TBitmap *bmp,AnsiString name,int *_alpha)
{
if (bmp==NULL) { _errorlog+="picture_load bmp is NULL\n"; return 0; }
if (!FileExists(name)){ _errorlog+="picture_load file \""+name+"\" dont exist\n"; return 0; }
bmp->HandleType=bmDIB;
bmp->PixelFormat=pf32bit;
AnsiString ext=ExtractFileExt(name).LowerCase();
for(;;)
{
if (ext==".bmp")
{
bmp->LoadFromFile(name);
break;
}
if (ext==".jpg")
{
TJPEGImage *jpg=new TJPEGImage;
#ifdef _mmap_h
if (jpg) mmap_new('GL',jpg,sizeof(TJPEGImage));
#endif
if (jpg==NULL) { _errorlog+="picture_load not enough memory\n"; return 0; }
jpg->LoadFromFile(name);
bmp->Assign(jpg);
#ifdef _mmap_h
mmap_del('GL',jpg);
#endif
delete jpg;
break;
}
if (ext==".png")
{
TPNGObject *png=new TPNGObject;
#ifdef _mmap_h
if (png) mmap_new('GL',png,sizeof(TJPEGImage));
#endif
if (png==NULL) { _errorlog+="picture_load not enough memory\n"; return 0; }
png->LoadFromFile(name);
bmp->Assign(png);
#ifdef _mmap_h
mmap_del('GL',png);
#endif
delete png;
break;
}
if ((ext==".sgi")||(ext==".rgb"))
{
sgi sss;
sss.load(name);
bmp->Width=sss.rgba->Width;
bmp->Height=sss.rgba->Height;
bmp->Canvas->Draw(0,0,sss.rgba);
break;
}
if (ext==".pcx")
{
unsigned int *p,c;
int x,y,adr;
int hnd,siz,l,xs,ys;
unsigned int pal[256],r,g,b;
Byte *dat;
for(;;)
{
hnd=FileOpen(name,fmOpenRead);
if (hnd<0) { _errorlog+="picture_load file \""+name+"\" dont exist\n"; return 0; }
siz=FileSeek(hnd,0,2);
FileSeek(hnd,0,0);
dat=new Byte[siz];
#ifdef _mmap_h
if (dat) mmap_new('GL',dat,siz*sizeof(BYTE));
#endif
if (dat==NULL) { FileClose(hnd); _errorlog+="picture_load not enough memory\n"; return 0; }
FileRead(hnd,dat,siz);
FileClose(hnd);
adr=siz-3*256;
for (l=0;l<256;l++)
{
r=dat[adr]; adr++; r&=255;
g=dat[adr]; adr++; g&=255;
b=dat[adr]; adr++; b&=255;
c=(r<<16)|(g<<8)|(b);
c&=0x00FFFFFF;
pal[l]=c;
}
xs=int(dat[ 8])-int(dat[4])+((int(dat[ 9])-int(dat[5]))<<8)+1;
ys=int(dat[10])-int(dat[6])+((int(dat[11])-int(dat[7]))<<8)+1;
bmp->HandleType=bmDIB;
bmp->PixelFormat=pf32bit;
bmp->Width=xs;
bmp->Height=ys;
xs=bmp->Width;
ys=bmp->Height;
adr=128;
for (y=0;y<ys;y++)
{
p=(unsigned int*)bmp->ScanLine[y];
for (x=0;x<xs;)
{
c=dat[adr];
if (c<192) l=1;
else{
l=c&63;
adr++;
c=dat[adr];
}
adr++;
for (;l>0;l--)
{
if (x>=xs) break;
p[x]=pal[c];
x++;
}
}
}
#ifdef _mmap_h
mmap_del('GL',dat);
#endif
delete[] dat;
break;
}
break;
}
if (ext==".dds")
{
DDS::load(bmp,name);
_errorlog+=DDS::_errorlog;
DDS::_errorlog="";
break;
}
_errorlog+="picture_load unsuported file extension \""+ext+"\"\n";
return 0;
}
bmp->HandleType=bmDIB;
if (_alpha) _alpha[0]=(bmp->PixelFormat==pf32bit);
bmp->PixelFormat=pf32bit;
return 1;
}
//------------------------------------------------------------------------------
int picture_save(Graphics::TBitmap *bmp,AnsiString name)
{
if (bmp==NULL) { _errorlog+="picture_load bmp is NULL\n"; return 0; }
bmp->HandleType=bmDIB;
bmp->PixelFormat=pf32bit;
AnsiString ext=ExtractFileExt(name).LowerCase();
for(;;)
{
if (ext==".bmp")
{
bmp->SaveToFile(name);
break;
}
if (ext==".jpg")
{
TJPEGImage *jpg=new TJPEGImage;
#ifdef _mmap_h
if (jpg) mmap_new('GL',jpg,sizeof(TJPEGImage));
#endif
if (jpg==NULL) { _errorlog+="picture_load not enough memory\n"; return 0; }
jpg->Assign(bmp);
jpg->SaveToFile(name);
#ifdef _mmap_h
mmap_del('GL',jpg);
#endif
delete jpg;
break;
}
if (ext==".png")
{
TPNGObject *png=new TPNGObject;
#ifdef _mmap_h
if (png) mmap_new('GL',png,sizeof(TJPEGImage));
#endif
if (png==NULL) { _errorlog+="picture_load not enough memory\n"; return 0; }
png->Assign(bmp);
png->SaveToFile(name);
#ifdef _mmap_h
mmap_del('GL',png);
#endif
delete png;
break;
}
_errorlog+="picture_load unsuported file extension \""+ext+"\"\n";
return 0;
}
return 1;
}
//------------------------------------------------------------------------------
Поэтому я выбираю формат на основе расширения имени файла и использую соответствующий объект / lib / code для кодирования / декодирования ...
Я также был вынужден использовать другой стиль декодирования (более сложный) в некоторых приложениях для двумерных векторных данных, который определяет формат файла по его заголовкам, потому что многие пользователи обычно используют Проводник Windows и очень часто повреждают расширения по ошибке и поскольку сегодняшние пользователи не знают, что означают расширения имени файла и файла, и они также имеют тенденцию переименовывать то, что им не следует задумывать.
bool decode_interface_class::load(AnsiString name)
{
int hnd=-1;
int siz=0,siz0=0;
BYTE *dat=NULL;
reset();
#ifdef decode_interface_log
decode_id.num=0;
decode_log="";
#endif
decode_cfg =true;
decode_col =true;
decode_tool=true;
decode_ext=ExtractFileExt(name).LowerCase();
decoded_ext=".";
decoded_info="";
decode_emf emf;
decode_wmf wmf;
decode_dkr dkr;
decode_dk3 dk3;
decode_box box;
decode_bxl bxl;
decode_dxf dxf;
decode_svg svg;
decode_v2x v2x;
decode_v2d v2d;
const int _size=4096;
BYTE head[_size];
#ifdef decode_interface_log
siz=0; // find minimal size
if (siz<_decode_emf_hdr) siz=_decode_emf_hdr;
if (siz<_decode_wmf_hdr) siz=_decode_wmf_hdr;
if (siz<_decode_dkr_hdr) siz=_decode_dkr_hdr;
if (siz<_decode_dk3_hdr) siz=_decode_dk3_hdr;
if (siz<_decode_box_hdr) siz=_decode_box_hdr;
if (siz<_decode_bxl_hdr) siz=_decode_bxl_hdr;
if (siz<_decode_dxf_hdr) siz=_decode_dxf_hdr;
if (siz<_decode_svg_hdr) siz=_decode_svg_hdr;
if (siz<_decode_v2x_hdr) siz=_decode_v2x_hdr;
if (siz<_decode_v2d_hdr) siz=_decode_v2d_hdr;
if (siz>_size)
{
decode_log+="Decoding header size too small needed to be "+AnsiString(siz)+" Bytes.\r\n";
}
#endif
hnd=FileOpen(name,fmOpenRead);
if (hnd<0)
{
#ifdef decode_interface_log
decode_log+="File "+name+" not found.\r\n";
#endif
return false;
}
siz=FileSeek(hnd,0,2);
FileSeek(hnd,0,0);
dat=new BYTE[siz];
if (dat==NULL)
{
#ifdef decode_interface_log
decode_log+="Not enough memory need: "+AnsiString(siz)+" Bytes.\r\n";
#endif
FileClose(hnd);
return false;
}
siz0=siz;
siz=FileRead(hnd,dat,siz);
FileClose(hnd);
if (siz!=siz0)
{
#ifdef decode_interface_log
decode_log+="Disc drive or file system error.\r\n";
#endif
}
// file signature detection
for (int i=0;i<_size;i++) if (i<siz) head[i]=dat[i]; else head[i]=0;
if (emf.is_header(head,_size,siz)) { decoded_ext=_decode_emf_ext; emf.load(this[0],dat,siz); }
else if (wmf.is_header(head,_size,siz)) { decoded_ext=_decode_wmf_ext; wmf.load(this[0],dat,siz); }
else if (dkr.is_header(head,_size,siz)) { decoded_ext=_decode_dkr_ext; dkr.load(this[0],dat,siz); }
else if (dk3.is_header(head,_size,siz)) { decoded_ext=_decode_dk3_ext; dk3.load(this[0],dat,siz); }
else if (box.is_header(head,_size,siz)) { decoded_ext=_decode_box_ext; box.load(this[0],dat,siz); }
else if (bxl.is_header(head,_size,siz)) { decoded_ext=_decode_bxl_ext; bxl.load(this[0],dat,siz); }
else if (dxf.is_header(head,_size,siz)) { decoded_ext=_decode_dxf_ext; dxf.load(this[0],dat,siz); } // toto koli rychlost ku koncu (hlada string)
else if (svg.is_header(head,_size,siz)) { decoded_ext=_decode_svg_ext; svg.load(this[0],dat,siz); } // toto koli rychlost ku koncu (hlada string)
else if (v2x.is_header(head,_size,siz)) { decoded_ext=_decode_v2x_ext; v2x.load(this[0],dat,siz); } // toto az na konci pre bezpecnost (nema signaturu)
else if (v2d.is_header(head,_size,siz)) { decoded_ext=_decode_v2d_ext; v2d.load(this[0],dat,siz); } // toto az na konci pre bezpecnost (nema signaturu)
// if fail use file extension
else if (decode_ext==_decode_emf_ext) { decoded_ext=_decode_emf_ext; emf.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
else if (decode_ext==_decode_wmf_ext) { decoded_ext=_decode_wmf_ext; wmf.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
else if (decode_ext==_decode_dkr_ext) { decoded_ext=_decode_dkr_ext; dkr.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
else if (decode_ext==_decode_dk3_ext) { decoded_ext=_decode_dk3_ext; dk3.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
else if (decode_ext==_decode_box_ext) { decoded_ext=_decode_box_ext; box.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
else if (decode_ext==_decode_bxl_ext) { decoded_ext=_decode_bxl_ext; bxl.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
else if (decode_ext==_decode_dxf_ext) { decoded_ext=_decode_dxf_ext; dxf.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
else if (decode_ext==_decode_svg_ext) { decoded_ext=_decode_svg_ext; svg.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
else if (decode_ext==_decode_v2x_ext) { decoded_ext=_decode_v2x_ext; v2x.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
else if (decode_ext==_decode_v2d_ext) { decoded_ext=_decode_v2d_ext; v2d.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
// if fail then error
else{
#ifdef decode_interface_log
decode_log+="File "+name+" not recognized.\r\n";
#endif
}
if (decode_cfg)
{
if (!decode_col )
{
if (decode_tool) set_cfgs (dk3_charaktool ,33);
set_colors(dk3_charakcolor,33);
}
if (!decode_tool) set_tools (dk3_charaktool ,33);
}
#ifdef decode_interface_log
if (decode_ext!=decoded_ext)
decode_log+="Wrong file extension in "+name+" should be \""+decoded_ext+"\"\r\n";
hnd=FileCreate(ExtractFilePath(Application->ExeName)+"svg_decode.log");
FileWrite(hnd,decode_log.c_str(),decode_log.Length());
FileClose(hnd);
#endif
compute();
compute_objsize();
if (dat) delete[] dat;
return true;
}
Поэтому я сначала загружаю до 4096 байт в память (размер зависит от поддерживаемых форматов файлов) и проверяю сигнатуру форматов файлов для каждого поддерживаемого формата файлов. При первом успехе используйте этот формат файла для декодирования файла ...
Каждый поддерживаемый тип файла должен иметь функцию, которая определяет его подпись здесь WMF пример:
bool decode_wmf::is_header(BYTE *head,DWORD size,DWORD filesize)
{
dst=NULL;
if (size<_decode_wmf_hdr) return 0;
if (((DWORD*)(head+0))[0]==0x9AC6CDD7) return 1; // placeable wmf
WORD *dw=(WORD*)head,a;
a=dw[0]; // type mem/file
if ((a!=0)&&(a!=1)) return 0;
a=dw[1]; // header size
if (a!=9) return 0;
// a=dw[2]; // version
// if (a!=) return 0;
return 1;
}
Порядок форматов файлов должен быть тщательно продуман, так как самые медленные декодеры должны следовать за более быстрыми. Кроме того, некоторые файловые форматы не имеют подписи, и их обнаружение выполняется путем поиска ошибки формата. Они должны идти последними.
Осторожно, оба загрузчика ожидают общего представления данных для каждого поддерживаемого файлового формата.