#include "ET++.ph" #ifdef __GNUG__ #pragma implementation #endif #include "Bitmap.h" #include "Class.h" #include "DevBitmap.h" #include "Error.h" #include "Storage.h" #include "WindowSystem.h" #include "String.h" #include "OrdColl.h" #include "FileData.h" #include "ColorMapper.h" #include "System.h" #include "ET_stdio.h" #include "HexFilter.h" #include "LZWFilter.h" #include "RLEFilter.h" #include "A85Filter.h" static ColorMapper *gMonoMapper; static ColorMapper *GetMonoMapper() { if (gMonoMapper == 0) { gMonoMapper= new MonoMapper(); gMonoMapper->Ref(); } return gMonoMapper; } ONEXIT(Bitmap) { SafeUnref(gMonoMapper); } #define MAXCPP 3 struct XPMelem { char name[MAXCPP+1]; u_long pixel; }; char *Bitmap::ReadXPM(char *data[]) { register int ix, i, x, y; register char *cp, *buf; char wbuf[1000]; int line= 0, tablen, s, len, cpp, depth; Point e; char *delim= " \t"; XPMelem *tab; RGB rgb; if (data[line] == 0) return "short file"; strcpy(wbuf, data[line++]); if (sscanf(wbuf, "%d %d %d %d", &e.x, &e.y, &len, &cpp) != 4) return "bad format"; if (len <= 2) depth= 1; else if (len <= 4) depth= 2; else if (len <= 16) depth= 4; else if (len <= 256) depth= 8; else depth= 24; dbm= gWindowSystem->MakeDevBitmap(e, 0, depth); SafeRef(dbm); if (depth == 1) cmapper= GetMonoMapper(); else if (depth <= 8) cmapper= new IndexMapper(1 << depth); else cmapper= new DirectMapper; SafeRef(cmapper); tablen= 128*MAXCPP; tab= new XPMelem[tablen]; for (s= 0; s < len; s++) { char *c, *m, *cc; if ((buf= data[line++]) == 0) return "short color map"; strcpy(wbuf, &buf[cpp]); cp= strtok(wbuf, delim); c= m= 0; while (cp) { char code[10]; strcpy(code, cp); cp= strtok(0, delim); if (cp == 0) break; if (strcmp(code, "c") == 0) c= cp; else if (strcmp(code, "m") == 0) m= cp; cp= strtok(0, delim); } if (c == 0) c= m; if (m == 0) m= c; if (gColor) cc= c; else cc= m; if (cc == 0) continue; gInkManager->ParseColor(rgb, cc); ChangeRGB(s, &rgb); for (i= 0; i < tablen; i++) { ix= (*buf + i) % tablen; if (tab[ix].name[0] == 0) { strncpy(tab[ix].name, buf, cpp); tab[ix].pixel= s; break; } } } for (y= 0; y < e.y; y++) { if ((cp= data[line]) == 0) break; for (x= 0; x < e.x; x++) { if (cpp == 1) ix= *cp++; else { for (i= 0; i < tablen; i++) { ix= (*cp + i) % tablen; if (strncmp(tab[ix].name, cp, cpp) == 0) break; } if (i == tablen) { fprintf(stderr, "not found\n"); break; } cp+= cpp; } SetPixel(x, y, tab[ix].pixel); } line++; } delete tab; return 0; } //---- SmartBitmap ------------------------------------------------------------- SmartBitmap::SmartBitmap(int w, int h, u_short *b) : size(w,h) { u.bits= b; tag= 1; } SmartBitmap::SmartBitmap(const Point &s, u_short *b) : size(s) { u.bits= b; tag= 1; } SmartBitmap::SmartBitmap(const char *nm) { u.name= nm; tag= 2; } SmartBitmap::SmartBitmap(const char *xpm[]) { u.xpmdata= xpm; tag= 3; } SmartBitmap::SmartBitmap(char *xpm[]) { u.xpmdata= (const char**) xpm; tag= 3; } SmartBitmap::~SmartBitmap() { if (tag == 0) { SafeDelete(u.bm); } } Bitmap *SmartBitmap::MakeBitmap() { Bitmap *bm= 0; switch (tag) { case 1: if (u.bits) bm= new Bitmap(size, u.bits); break; case 2: if (u.name) { FileData *fd; if (u.name[0] == '/') fd= new FileData(u.name); else fd= new FileData(form("/%s/src/images/%s", gEtDir, u.name)); bm= (Bitmap*) fd->AsObject(Meta(Bitmap)); delete fd; } break; case 3: bm= new Bitmap(u.xpmdata); break; default: fprintf(stderr, "SmartBitmap::MakeBitmap(): oops\n"); break; } tag= 0; return u.bm= bm; } //---- Bitmap ------------------------------------------------------------------ NewMetaImpl(Bitmap,Ink, (TP(dbm), TP(cmapper))); Bitmap::Bitmap(const char *xpmdata[]) { char *msg= ReadXPM((char**)xpmdata); if (msg) fprintf(stderr, "ReadXPM: %s\n", msg); } Bitmap::Bitmap(const Point &sz, u_short depth, ColorMapper *cm) { WindowSystem::WSInit(); dbm= gWindowSystem->MakeDevBitmap(sz, 0, depth); SafeRef(dbm); cmapper= cm; SafeRef(cmapper); } Bitmap::Bitmap(const Point &sz, u_short depth) { WindowSystem::WSInit(); dbm= gWindowSystem->MakeDevBitmap(sz, 0, depth); SafeRef(dbm); if (depth == 1) cmapper= GetMonoMapper(); else if (depth <= 8) cmapper= new IndexMapper(1 << depth); else cmapper= new DirectMapper; SafeRef(cmapper); } Bitmap::Bitmap(const Point &sz, u_short *im) { WindowSystem::WSInit(); dbm= gWindowSystem->MakeDevBitmap(sz, im, 1); SafeRef(dbm); cmapper= GetMonoMapper(); SafeRef(cmapper); } Bitmap::Bitmap(int w, int h, u_short *im) { WindowSystem::WSInit(); dbm= gWindowSystem->MakeDevBitmap(Point(w, h), im, 1); SafeRef(dbm); cmapper= GetMonoMapper(); SafeRef(cmapper); } Bitmap::Bitmap(DevBitmap *d) { WindowSystem::WSInit(); dbm= d; SafeRef(dbm); int depth= dbm->Depth(); if (depth == 1) cmapper= GetMonoMapper(); else if (depth <= 8) cmapper= new IndexMapper(1 << depth); else cmapper= new DirectMapper; SafeRef(cmapper); } Bitmap::Bitmap(const char*) { WindowSystem::WSInit(); fprintf(stderr, "Bitmap::Bitmap((char*): not yet implemented\n"); dbm= 0; } Bitmap::~Bitmap() { SafeUnref(dbm); SafeUnref(cmapper); } void Bitmap::CopyPixel(const Rectangle &t, Bitmap *from, const Point &fromorigin) { Rectangle to(t); to.Clip(Size()); to.extent= Min(to.extent, from->Size()-fromorigin); if (to.IsNotEmpty()) dbm->DevBitBlt(to.origin.x, to.origin.y, to.extent.x, to.extent.y, eBitCopy, from->GetDevBitmap(), fromorigin.x, fromorigin.y); } void Bitmap::Fill(u_long pixel) { if (dbm) dbm->DevBitBlt(0, 0, Size().x, Size().y, eBitSet, 0, 0, 0, pixel); } void Bitmap::FillRect(const Rectangle &r, u_long pixel) { Rectangle t(r); t.Clip(Size()); if (dbm) dbm->DevBitBlt(t.origin.x, t.origin.y, t.extent.x, t.extent.y, eBitSet, 0, 0, 0, pixel); } Point Bitmap::Size() { return dbm->Size(); } int Bitmap::ShortsPerLine() { return ((dbm->Size().x-1)/16+1)*dbm->Depth(); } int Bitmap::BytesPerLine() { return dbm->BytesPerLine(); } int Bitmap::GetDepth() { return dbm->Depth(); } void Bitmap::SetDevBitmap(DevBitmap *d) { AssignRef(&dbm, d); } void Bitmap::SetInk(Port *port) { port->DevSetPattern(this); } void Bitmap::SetPixel(u_int x, u_int y, u_long val) { dbm->SetPixel(x, y, val); dbm->changed= TRUE; } u_long Bitmap::GetPixel(u_int x, u_int y) { return dbm->GetPixel(x, y); } void Bitmap::SetRGB(u_int x, u_int y, RGB *rgb) { u_long pixel; if (cmapper->RGB2Pixel(rgb, &pixel)) SetPixel(x, y, pixel); } void Bitmap::GetRGB(u_int x, u_int y, RGB *result) { cmapper->Pixel2RGB(GetPixel(x, y), result); } u_long Bitmap::MaxPixelValue() { return cmapper->MaxPixel(); } void Bitmap::PixelToRGB(u_long pixel, RGB *result) { cmapper->Pixel2RGB(pixel, result); } void Bitmap::ExpandDepth() { register int x, y; DevBitmap *newdbm; ColorMapper *newcmapper; Point sz(Size()); int depth= GetDepth(); RGB c; if (depth == 1) { newdbm= gWindowSystem->MakeDevBitmap(sz, 0, 4); newcmapper= new IndexMapper(16); } else if (depth == 4) { newdbm= gWindowSystem->MakeDevBitmap(sz, 0, 8); newcmapper= new IndexMapper(256); } else { newdbm= gWindowSystem->MakeDevBitmap(sz, 0, 24); newcmapper= new DirectMapper; } for (y= 0; y < sz.y; y++) { for (x= 0; x < sz.x; x++) { u_long px= dbm->GetPixel(x, y); cmapper->Pixel2RGB(px, &c); newcmapper->RGB2Pixel(&c, &px); newdbm->SetPixel(x, y, px); } } dbm->Unref(); dbm= newdbm; dbm->Ref(); cmapper->Unref(); cmapper= newcmapper; cmapper->Ref(); } bool Bitmap::RGB2Pixel(RGB *rgb, u_long *pixel) { if (!cmapper->RGB2Pixel(rgb, pixel)) { ExpandDepth(); if (!cmapper->RGB2Pixel(rgb, pixel)) { fprintf(stderr, "cannot happen\n"); return FALSE; } } dbm->changed= TRUE; return TRUE; } bool Bitmap::ChangeRGB(u_long pixel, RGB *rgb) { if (!cmapper->ChangeRGB(pixel, rgb)) { ExpandDepth(); if (!cmapper->ChangeRGB(pixel, rgb)) { fprintf(stderr, "cannot happen\n"); return FALSE; } } dbm->changed= TRUE; return TRUE; } Object *Bitmap::deepclone() { if (IsA() == Meta(Bitmap)) { Bitmap *bm= new Bitmap(Size(), GetDepth()); SafeUnref(bm->dbm); if (dbm) { bm->dbm= dbm->MakeCopy(); bm->dbm->Ref(); } if (cmapper) { bm->cmapper= cmapper; bm->cmapper->Ref(); } return bm; } return 0; } void Bitmap::Show(Rectangle*, Port*) { } OStream &Bitmap::PrintOn(OStream &s) { int version= 200, coding= 0; BitmapInfo bi(Size(), GetDepth(), 1); Object::PrintOn(s); if (bi.rowlen * Size().y > 100) { if (GetDepth() > 1) coding= 3; else coding= 2; } s << Size() SP << GetDepth() SP << version SP << coding SP << cmapper NL; if (coding == 0) { s.Push(new HexEncoder); } else if (coding == 1) { s.Push(new HexEncoder); s.Push(new RLEEncoder); } else if (coding == 2) { s.Push(new A85Encoder); s.Push(new RLEEncoder); } else if (coding == 3) { s.Push(new A85Encoder); s.Push(new LZWEncoder); } dbm->WriteData(&bi, s); if (coding > 0) s.Pop(); s.Pop(); return s; } IStream &Bitmap::ReadFrom(IStream &s) { int coding, depth, version; Point size; SafeUnref(dbm); Object::ReadFrom(s); s >> size >> depth >> coding; dbm= gWindowSystem->MakeDevBitmap(size, 0, depth); SafeRef(dbm); if (coding < 200) { // old version int cmsize; version= 0; if (depth == 1) cmapper= GetMonoMapper(); else if (depth <= 8) cmapper= new IndexMapper(1 << depth); else cmapper= new DirectMapper; s >> cmsize; if (cmsize > 0) { s >> cmsize; if (cmsize > 0) { RGB c; for (int i= 0; i < cmsize; i++) { s >> c.red >> c.green >> c.blue; cmapper->ChangeRGB(i, &c); } } } if (coding >= 100) { version= 100; coding-= 100; } } else { // new version version= coding; s >> coding >> cmapper; } SafeRef(cmapper); if (coding == 0) { s.Push(new HexDecoder); } else if (coding == 1) { s.Push(new HexDecoder); s.Push(new RLEDecoder(TRUE)); } else if (coding == 2) { s.Push(new A85Decoder); s.Push(new RLEDecoder(FALSE)); } else if (coding == 3) { s.Push(new A85Decoder); s.Push(new LZWDecoder); } BitmapInfo bi(Size(), depth, 1); dbm->ReadData(&bi, s); if (version == 100) { DevBitmap *mask= gWindowSystem->MakeDevBitmap(size, 0, 1); SafeRef(mask); BitmapInfo bi(Size(), 1, 1); mask->ReadData(&bi, s); mask->Unref(); } if (coding > 0) s.Pop(); s.Pop(); return s; }