* reworked GUI to have better layout and be more font-sensitive

* added option to specify max number of colors
* improved palette creation (quite an improvement with my test images,
	but a better color reduction algorithm surely exist)
* more to come with regards to transparency (for examply, being able to
	specify the transparent index seems like complete bogus to me)


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@14294 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2005-10-02 16:59:06 +00:00
parent 6e7679be67
commit 3647107a2e
10 changed files with 706 additions and 405 deletions
@@ -13,6 +13,8 @@
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Additional authors: Stephan Aßmus, <[email protected]>
#include "GIFSave.h" #include "GIFSave.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@@ -26,7 +28,14 @@ const int32 seven_sixteenth = (int32)((7.0 / 16.0) * 32768);
extern bool debug; extern bool debug;
GIFSave::GIFSave(BBitmap *bitmap, BPositionIO *output) { class ColorCache : public HashItem {
public:
unsigned char index;
};
// constructor
GIFSave::GIFSave(BBitmap *bitmap, BPositionIO *output)
{
color_space cs = bitmap->ColorSpace(); color_space cs = bitmap->ColorSpace();
if (cs != B_RGB32 && cs != B_RGBA32 && cs != B_RGB32_BIG && cs != B_RGBA32_BIG) { if (cs != B_RGB32 && cs != B_RGBA32 && cs != B_RGB32_BIG && cs != B_RGBA32_BIG) {
if (debug) printf("GIFSave::GIFSave() - Unknown color space\n"); if (debug) printf("GIFSave::GIFSave() - Unknown color space\n");
@@ -36,9 +45,11 @@ GIFSave::GIFSave(BBitmap *bitmap, BPositionIO *output) {
fatalerror = false; fatalerror = false;
prefs = new Prefs(); prefs = new Prefs();
if (prefs->palettemode == OPTIMAL_PALETTE) palette = new SavePalette(bitmap); if (prefs->palettemode == OPTIMAL_PALETTE)
else palette = new SavePalette(prefs->palettemode); palette = new SavePalette(bitmap, prefs->palette_size_in_bits);
if (palette->fatalerror) { else
palette = new SavePalette(prefs->palettemode);
if (!palette->IsValid()) {
fatalerror = true; fatalerror = true;
return; return;
} }
@@ -86,33 +97,32 @@ GIFSave::GIFSave(BBitmap *bitmap, BPositionIO *output) {
} }
} }
palette->usetransparent = prefs->usetransparent; palette->SetUseTransparent(prefs->usetransparent);
if (prefs->usetransparent) { if (prefs->usetransparent) {
if (prefs->usetransparentindex) { if (prefs->usetransparentindex) {
palette->transparentindex = prefs->transparentindex; palette->SetTransparentIndex(prefs->transparentindex);
if (debug) printf("GIFSave::GIFSave() - Using transparent index %d\n", palette->transparentindex); if (debug)
printf("GIFSave::GIFSave() - Using transparent index %d\n", palette->TransparentIndex());
} else { } else {
palette->transparentindex = -1; bool found = palette->SetTransparentColor((uint8)prefs->transparentred,
for (int x = 0; x < palette->size; x++) { (uint8)prefs->transparentred,
if (palette->pal[x].red == prefs->transparentred && (uint8)prefs->transparentblue);
palette->pal[x].green == prefs->transparentgreen && if (found) {
palette->pal[x].blue == prefs->transparentblue) { if (debug) {
printf("GIFSave::GIFSave() - Found transparent color %d,%d,%d at index %d\n",
palette->transparentindex = x; prefs->transparentred, prefs->transparentgreen, prefs->transparentblue,
if (debug) printf("GIFSave::GIFSave() - Found transparent color %d,%d,%d at index %d\n", prefs->transparentred, palette->TransparentIndex());
prefs->transparentgreen, prefs->transparentblue, x);
break;
} }
} } else {
if (palette->transparentindex == -1) { if (debug) {
palette->usetransparent = false; printf("GIFSave::GIFSave() - Did not find color %d,%d,%d - deactivating transparency\n",
palette->transparentindex = 0;
if (debug) printf("GIFSave::GIFSave() - Did not find color %d,%d,%d - deactivating transparency\n",
prefs->transparentred, prefs->transparentgreen, prefs->transparentblue); prefs->transparentred, prefs->transparentgreen, prefs->transparentblue);
} }
} }
}
} else { } else {
if (debug) printf("GIFSave::GIFSave() - Not using transparency\n"); if (debug)
printf("GIFSave::GIFSave() - Not using transparency\n");
} }
this->output = output; this->output = output;
@@ -140,38 +150,50 @@ GIFSave::GIFSave(BBitmap *bitmap, BPositionIO *output) {
output->Write(&t, 1); output->Write(&t, 1);
} }
void GIFSave::WriteGIFHeader() { // destructor
GIFSave::~GIFSave()
{
delete palette;
delete prefs;
}
// WriteGIFHeader
void
GIFSave::WriteGIFHeader()
{
// Standard header // Standard header
unsigned char header[] = {'G', 'I', 'F', '8', '9', 'a', 0, 0, 0, 0, 0, 0, 0}; unsigned char header[] = {'G', 'I', 'F', '8', '9', 'a', 0, 0, 0, 0, 0, 0, 0};
header[6] = width & 0xff; header[6] = width & 0xff;
header[7] = (width & 0xff00) >> 8; header[7] = (width & 0xff00) >> 8;
header[8] = height & 0xff; header[8] = height & 0xff;
header[9] = (height & 0xff00) >> 8; header[9] = (height & 0xff00) >> 8;
header[10] = 0xf0 | (palette->size_in_bits - 1); header[10] = 0xf0 | (palette->SizeInBits() - 1);
header[11] = palette->backgroundindex; header[11] = palette->BackgroundIndex();
output->Write(header, 13); output->Write(header, 13);
// Global palette // Global palette
int size = 1 << palette->size_in_bits; int size = (1 << palette->SizeInBits()) * 3;
char c[256 * 3]; // can't be bigger than this uint8* buffer = new uint8[size]; // can't be bigger than this
for (int x = 0; x < size; x++) { palette->GetColors(buffer, size);
c[x * 3] = palette->pal[x].red; output->Write(buffer, size);
c[x * 3 + 1] = palette->pal[x].green; delete[] buffer;
c[x * 3 + 2] = palette->pal[x].blue;
}
output->Write(c, size * 3);
} }
void GIFSave::WriteGIFControlBlock() { // WriteGIFControlBlock
void
GIFSave::WriteGIFControlBlock()
{
unsigned char b[8] = {0x21, 0xf9, 0x04, 0, 0, 0, 0, 0x00}; unsigned char b[8] = {0x21, 0xf9, 0x04, 0, 0, 0, 0, 0x00};
if (palette->usetransparent) { if (palette->UseTransparent()) {
b[3] = b[3] | 1; b[3] = b[3] | 1;
b[6] = palette->transparentindex; b[6] = palette->TransparentIndex();
} }
output->Write(b, 8); output->Write(b, 8);
} }
void GIFSave::WriteGIFImageHeader() { // WriteGIFImageHeader
void GIFSave::WriteGIFImageHeader()
{
unsigned char header[10]; unsigned char header[10];
header[0] = 0x2c; header[0] = 0x2c;
header[1] = header[2] = 0; header[1] = header[2] = 0;
@@ -187,7 +209,9 @@ void GIFSave::WriteGIFImageHeader() {
output->Write(header, 10); output->Write(header, 10);
} }
void GIFSave::WriteGIFImageData() { // WriteGIFImageData
void GIFSave::WriteGIFImageData()
{
InitFrame(); InitFrame();
code_value = (short *)malloc(HASHSIZE * 2); code_value = (short *)malloc(HASHSIZE * 2);
prefix_code = (short *)malloc(HASHSIZE * 2); prefix_code = (short *)malloc(HASHSIZE * 2);
@@ -232,7 +256,10 @@ void GIFSave::WriteGIFImageData() {
free(append_char); free(append_char);
} }
void GIFSave::OutputCode(short code, int BITS, bool flush) { // OutputCode
void
GIFSave::OutputCode(short code, int BITS, bool flush)
{
if (!flush) { if (!flush) {
bit_buffer |= (unsigned int) code << bit_count; bit_buffer |= (unsigned int) code << bit_count;
bit_count += BITS; bit_count += BITS;
@@ -266,7 +293,10 @@ void GIFSave::OutputCode(short code, int BITS, bool flush) {
} }
} }
void GIFSave::ResetHashtable() { // ResetHashtable
void
GIFSave::ResetHashtable()
{
for (int q = 0; q < HASHSIZE; q++) { for (int q = 0; q < HASHSIZE; q++) {
code_value[q] = -1; code_value[q] = -1;
prefix_code[q] = 0; prefix_code[q] = 0;
@@ -274,7 +304,10 @@ void GIFSave::ResetHashtable() {
} }
} }
int GIFSave::CheckHashtable(int s, unsigned char c) { // CheckHashtable
int
GIFSave::CheckHashtable(int s, unsigned char c)
{
if (s == -1) return c; if (s == -1) return c;
int hashindex = HASH(s, c); int hashindex = HASH(s, c);
int nextindex; int nextindex;
@@ -286,7 +319,10 @@ int GIFSave::CheckHashtable(int s, unsigned char c) {
return -1; return -1;
} }
void GIFSave::AddToHashtable(int s, unsigned char c) { // AddToHashtable
void
GIFSave::AddToHashtable(int s, unsigned char c)
{
int hashindex = HASH(s, c); int hashindex = HASH(s, c);
while (code_value[hashindex] != -1) hashindex = (hashindex + HASHSTEP) % HASHSIZE; while (code_value[hashindex] != -1) hashindex = (hashindex + HASHSTEP) % HASHSIZE;
code_value[hashindex] = next_code; code_value[hashindex] = next_code;
@@ -294,7 +330,10 @@ void GIFSave::AddToHashtable(int s, unsigned char c) {
append_char[next_code] = c; append_char[next_code] = c;
} }
unsigned char GIFSave::NextPixel(int pixel) { // NextPixel
unsigned char
GIFSave::NextPixel(int pixel)
{
int bpr = bitmap->BytesPerRow(); int bpr = bitmap->BytesPerRow();
color_space cs = bitmap->ColorSpace(); color_space cs = bitmap->ColorSpace();
unsigned char r, g, b; unsigned char r, g, b;
@@ -377,9 +416,13 @@ unsigned char GIFSave::NextPixel(int pixel) {
return cc->index; return cc->index;
} }
void GIFSave::InitFrame() { // InitFrame
code_size = palette->size_in_bits; void
if (code_size == 1) code_size++; GIFSave::InitFrame()
{
code_size = palette->SizeInBits();
if (code_size == 1)
code_size++;
BITS = code_size + 1; BITS = code_size + 1;
clear_code = 1 << code_size; clear_code = 1 << code_size;
end_code = clear_code + 1; end_code = clear_code + 1;
@@ -398,9 +441,3 @@ void GIFSave::InitFrame() {
gifbits = (unsigned char *)bitmap->Bits(); gifbits = (unsigned char *)bitmap->Bits();
} }
GIFSave::~GIFSave() {
delete palette;
delete prefs;
}
@@ -41,8 +41,8 @@ status_t GetBitmap(BPositionIO *in, BBitmap **out);
/* Required data */ /* Required data */
char translatorName[] = "GIF Images"; char translatorName[] = "GIF Images";
char translatorInfo[] = "GIF image translator v1.3"; char translatorInfo[] = "GIF image translator v1.4";
int32 translatorVersion = 0x130; int32 translatorVersion = 0x140;
translation_format inputFormats[] = { translation_format inputFormats[] = {
{ GIF_TYPE, B_TRANSLATOR_BITMAP, 0.8, 0.8, "image/gif", "GIF image" }, { GIF_TYPE, B_TRANSLATOR_BITMAP, 0.8, 0.8, "image/gif", "GIF image" },
+245 -162
View File
@@ -13,19 +13,26 @@
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include "GIFView.h" // Additional authors: Stephan Aßmus, <[email protected]>
#include "SavePalette.h"
#include "Prefs.h"
#include <InterfaceKit.h>
#include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <InterfaceKit.h>
#include <String.h>
#include "Prefs.h"
#include "SavePalette.h"
#include "GIFView.h"
extern int32 translatorVersion; extern int32 translatorVersion;
extern char translatorName[]; extern char translatorName[];
GIFView::GIFView(BRect rect, const char *name) : // constructor
BView(rect, name, B_FOLLOW_ALL, B_WILL_DRAW) { GIFView::GIFView(BRect rect, const char *name)
: BView(rect, name, B_FOLLOW_ALL, B_WILL_DRAW)
{
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
font_height fh; font_height fh;
@@ -39,111 +46,146 @@ GIFView::GIFView(BRect rect, const char *name) :
char version_string[100]; char version_string[100];
sprintf(version_string, "v%d.%d.%d %s", (int)(translatorVersion >> 8), (int)((translatorVersion >> 4) & 0xf), sprintf(version_string, "v%d.%d.%d %s", (int)(translatorVersion >> 8), (int)((translatorVersion >> 4) & 0xf),
(int)(translatorVersion & 0xf), __DATE__); (int)(translatorVersion & 0xf), __DATE__);
r.top = r.bottom + 20;
be_plain_font->GetHeight(&fh); be_plain_font->GetHeight(&fh);
r.bottom = r.top + fh.ascent + fh.descent; r.bottom = r.top + fh.ascent + fh.descent;
r.left = r.right + 2.0 * r.Height();
r.right = r.left + be_plain_font->StringWidth(version_string); r.right = r.left + be_plain_font->StringWidth(version_string);
BStringView *version = new BStringView(r, "Version", version_string); BStringView *version = new BStringView(r, "Version", version_string);
version->SetFont(be_plain_font); version->SetFont(be_plain_font);
AddChild(version); AddChild(version);
BFont small(be_plain_font);
small.SetSize(max_c(7.0, small.Size() * 0.7));
const char *copyright_string = "© 2003 Daniel Switkin, [email protected]"; const char *copyright_string = "© 2003 Daniel Switkin, [email protected]";
r.top = r.bottom + 10; r.top = r.bottom + 5;
r.left = 10;
r.bottom = r.top + fh.ascent + fh.descent; r.bottom = r.top + fh.ascent + fh.descent;
r.right = r.left + be_plain_font->StringWidth(copyright_string); r.right = rect.right - 10;
BStringView *copyright = new BStringView(r, "Copyright", copyright_string); BStringView *copyright = new BStringView(r, "Copyright", copyright_string);
copyright->SetFont(be_plain_font); copyright->SetFont(&small);
AddChild(copyright); AddChild(copyright);
websafe = new BMenuItem("websafe", new BMessage(GV_WEB_SAFE), 0, 0); //menu fields (Palette & Colors)
beossystem = new BMenuItem("BeOS system", new BMessage(GV_BEOS_SYSTEM), 0, 0); fWebSafeMI = new BMenuItem("Websafe", new BMessage(GV_WEB_SAFE), 0, 0);
greyscale = new BMenuItem("greyscale", new BMessage(GV_GREYSCALE), 0, 0); fBeOSSystemMI = new BMenuItem("BeOS System", new BMessage(GV_BEOS_SYSTEM), 0, 0);
optimal = new BMenuItem("optimal", new BMessage(GV_OPTIMAL), 0, 0); fGreyScaleMI = new BMenuItem("Greyscale", new BMessage(GV_GREYSCALE), 0, 0);
palettepopupmenu = new BPopUpMenu("PalettePopUpMenu", true, true, B_ITEMS_IN_COLUMN); fOptimalMI = new BMenuItem("Optimal", new BMessage(GV_OPTIMAL), 0, 0);
palettepopupmenu->AddItem(websafe); fPaletteM = new BPopUpMenu("PalettePopUpMenu", true, true, B_ITEMS_IN_COLUMN);
palettepopupmenu->AddItem(beossystem); fPaletteM->AddItem(fWebSafeMI);
palettepopupmenu->AddItem(greyscale); fPaletteM->AddItem(fBeOSSystemMI);
palettepopupmenu->AddItem(optimal); fPaletteM->AddItem(fGreyScaleMI);
fPaletteM->AddItem(fOptimalMI);
r.top = r.bottom + 10; fColorCountM = new BPopUpMenu("ColorCountPopUpMenu", true, true, B_ITEMS_IN_COLUMN);
int32 count = 2;
for (int32 i = 0; i < 8; i++) {
BMessage* message = new BMessage(GV_SET_COLOR_COUNT);
message->AddInt32("size in bits", i + 1);
BString label;
label << count;
fColorCountMI[i] = new BMenuItem(label.String(), message, 0, 0);
fColorCountM->AddItem(fColorCountMI[i]);
count *= 2;
}
fColorCount256MI = fColorCountMI[7];
r.top = r.bottom + 5;
r.bottom = r.top + 24; r.bottom = r.top + 24;
r.right = r.left + be_plain_font->StringWidth("Palette:") + fPaletteMF = new BMenuField(r, "PaletteMenuField", "Palette",
be_plain_font->StringWidth("BeOS system") + 32; fPaletteM, B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE);
palettemenufield = new BMenuField(r, "PaletteMenuField", "Palette:", AddChild(fPaletteMF);
palettepopupmenu, B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE);
AddChild(palettemenufield);
palettemenufield->SetDivider(be_plain_font->StringWidth("Palette:") + 7);
r.top = palettemenufield->Frame().bottom + 5; r.top = r.bottom + 5;
r.bottom = r.top + 24;
fColorCountMF = new BMenuField(r, "ColorCountMenuField", "Colors",
fColorCountM, B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE);
AddChild(fColorCountMF);
// align menu fields
float maxLabelWidth = ceilf(max_c(be_plain_font->StringWidth("Colors"),
be_plain_font->StringWidth("Palette")));
fPaletteMF->SetDivider(maxLabelWidth + 7);
fColorCountMF->SetDivider(maxLabelWidth + 7);
// check boxen
r.top = fColorCountMF->Frame().bottom + 5;
r.bottom = r.top + 10; r.bottom = r.top + 10;
r.right = r.left + be_plain_font->StringWidth("Use dithering") + 20; fUseDitheringCB = new BCheckBox(r, "UseDithering", "Use dithering",
usedithering = new BCheckBox(r, "UseDithering", "Use dithering",
new BMessage(GV_USE_DITHERING)); new BMessage(GV_USE_DITHERING));
AddChild(usedithering); AddChild(fUseDitheringCB);
r.top = usedithering->Frame().bottom + 2; r.top = fUseDitheringCB->Frame().bottom + 2;
r.bottom = r.top + 10; r.bottom = r.top + 10;
r.right = r.left + be_plain_font->StringWidth("Write interlaced images") + 20; fInterlacedCB = new BCheckBox(r, "Interlaced", "Write interlaced images",
interlaced = new BCheckBox(r, "Interlaced", "Write interlaced images",
new BMessage(GV_INTERLACED)); new BMessage(GV_INTERLACED));
AddChild(interlaced); AddChild(fInterlacedCB);
r.top = interlaced->Frame().bottom + 2; r.top = fInterlacedCB->Frame().bottom + 2;
r.bottom = r.top + 10; r.bottom = r.top + 10;
r.right = r.left + be_plain_font->StringWidth("Write transparent images") + 20; fUseTransparentCB = new BCheckBox(r, "UseTransparent", "Write transparent images",
usetransparent = new BCheckBox(r, "UseTransparent", "Write transparent images",
new BMessage(GV_USE_TRANSPARENT)); new BMessage(GV_USE_TRANSPARENT));
AddChild(usetransparent); AddChild(fUseTransparentCB);
r.top = usetransparent->Frame().bottom + 2; // radio buttons
r.top = fUseTransparentCB->Frame().bottom + 2;
r.bottom = r.top + 10; r.bottom = r.top + 10;
r.right = r.left + be_plain_font->StringWidth("Use index:") + 20; r.right = r.left + be_plain_font->StringWidth("Use index") + 20;
usetransparentindex = new BRadioButton(r, "UseTransparentIndex", "Use index:", fUseTransparentIndexRB = new BRadioButton(r, "UseTransparentIndex", "Use index",
new BMessage(GV_USE_TRANSPARENT_INDEX)); new BMessage(GV_USE_TRANSPARENT_INDEX));
AddChild(usetransparentindex); AddChild(fUseTransparentIndexRB);
r.left = r.right + 1; r.left = r.right + 1;
r.right = r.left + 30; r.right = r.left + 30;
transparentindex = new BTextControl(r, "TransparentIndex", "", "0", fTransparentIndexTC = new BTextControl(r, "TransparentIndex", "", "0",
new BMessage(GV_TRANSPARENT_INDEX)); new BMessage(GV_TRANSPARENT_INDEX));
AddChild(transparentindex); AddChild(fTransparentIndexTC);
transparentindex->SetDivider(0); fTransparentIndexTC->SetDivider(0);
r.top = usetransparentindex->Frame().bottom + 0; r.top = fUseTransparentIndexRB->Frame().bottom + 0;
r.bottom = r.top + 10; r.bottom = r.top + 10;
r.left = 10; r.left = 10;
r.right = r.left + be_plain_font->StringWidth("Use rgb color:") + 20; r.right = r.left + be_plain_font->StringWidth("Use rgb color") + 20;
usetransparentcolor = new BRadioButton(r, "UseTransparentColor", "Use rgb color:", fUseTransparentColorRB = new BRadioButton(r, "UseTransparentColor", "Use rgb color",
new BMessage(GV_USE_TRANSPARENT_COLOR)); new BMessage(GV_USE_TRANSPARENT_COLOR));
AddChild(usetransparentcolor); AddChild(fUseTransparentColorRB);
r.left = r.right + 1; r.left = r.right + 1;
r.right = r.left + 30; r.right = r.left + 30;
transparentred = new BTextControl(r, "TransparentRed", "", "0", fTransparentRedTC = new BTextControl(r, "TransparentRed", "", "0",
new BMessage(GV_TRANSPARENT_RED)); new BMessage(GV_TRANSPARENT_RED));
AddChild(transparentred); AddChild(fTransparentRedTC);
transparentred->SetDivider(0); fTransparentRedTC->SetDivider(0);
r.left = r.right + 5; r.left = r.right + 5;
r.right = r.left + 30; r.right = r.left + 30;
transparentgreen = new BTextControl(r, "TransparentGreen", "", "0", fTransparentGreenTC = new BTextControl(r, "TransparentGreen", "", "0",
new BMessage(GV_TRANSPARENT_GREEN)); new BMessage(GV_TRANSPARENT_GREEN));
AddChild(transparentgreen); AddChild(fTransparentGreenTC);
transparentgreen->SetDivider(0); fTransparentGreenTC->SetDivider(0);
r.left = r.right + 5; r.left = r.right + 5;
r.right = r.left + 30; r.right = r.left + 30;
transparentblue = new BTextControl(r, "TransparentBlue", "", "0", fTransparentBlueTC = new BTextControl(r, "TransparentBlue", "", "0",
new BMessage(GV_TRANSPARENT_BLUE)); new BMessage(GV_TRANSPARENT_BLUE));
AddChild(transparentblue); AddChild(fTransparentBlueTC);
transparentblue->SetDivider(0); fTransparentBlueTC->SetDivider(0);
BTextView *ti = transparentindex->TextView(); // align text controls
BTextView *tr = transparentred->TextView(); float diff = fTransparentRedTC->Frame().left - fTransparentIndexTC->Frame().left;
BTextView *tg = transparentgreen->TextView(); if (diff > 0) {
BTextView *tb = transparentblue->TextView(); fTransparentIndexTC->MoveBy(diff, 0);
} else {
fTransparentRedTC->MoveBy(-diff, 0);
fTransparentGreenTC->MoveBy(-diff, 0);
fTransparentBlueTC->MoveBy(-diff, 0);
}
BTextView *ti = fTransparentIndexTC->TextView();
BTextView *tr = fTransparentRedTC->TextView();
BTextView *tg = fTransparentGreenTC->TextView();
BTextView *tb = fTransparentBlueTC->TextView();
for (uint32 x = 0; x < 256; x++) { for (uint32 x = 0; x < 256; x++) {
if (x < '0' || x > '9') { if (x < '0' || x > '9') {
@@ -157,156 +199,201 @@ GIFView::GIFView(BRect rect, const char *name) :
RestorePrefs(); RestorePrefs();
} }
void GIFView::RestorePrefs() { // destructor
prefs = new Prefs(); GIFView::~GIFView()
{
delete fPrefs;
}
switch (prefs->palettemode) { // RestorePrefs
void
GIFView::RestorePrefs()
{
fPrefs = new Prefs();
fColorCountMF->SetEnabled(false);
fUseDitheringCB->SetEnabled(true);
switch (fPrefs->palettemode) {
case WEB_SAFE_PALETTE: case WEB_SAFE_PALETTE:
websafe->SetMarked(true); fWebSafeMI->SetMarked(true);
break; break;
case BEOS_SYSTEM_PALETTE: case BEOS_SYSTEM_PALETTE:
beossystem->SetMarked(true); fBeOSSystemMI->SetMarked(true);
break; break;
case GREYSCALE_PALETTE: case GREYSCALE_PALETTE:
greyscale->SetMarked(true); fGreyScaleMI->SetMarked(true);
usedithering->SetEnabled(false); fUseDitheringCB->SetEnabled(false);
break; break;
case OPTIMAL_PALETTE: case OPTIMAL_PALETTE:
optimal->SetMarked(true); fOptimalMI->SetMarked(true);
fColorCountMF->SetEnabled(true);
break; break;
default: default:
prefs->palettemode = WEB_SAFE_PALETTE; fPrefs->palettemode = WEB_SAFE_PALETTE;
websafe->SetMarked(true); fWebSafeMI->SetMarked(true);
break; break;
} }
interlaced->SetValue(prefs->interlaced); if (fColorCountMF->IsEnabled() &&
fPrefs->palette_size_in_bits > 0 &&
if (greyscale->IsMarked()) usedithering->SetValue(false); fPrefs->palette_size_in_bits <= 8) {
else usedithering->SetValue(prefs->usedithering); // display the stored color count
usetransparent->SetValue(prefs->usetransparent); fColorCountMI[fPrefs->palette_size_in_bits - 1]->SetMarked(true);
usetransparentindex->SetValue(prefs->usetransparentindex);
usetransparentcolor->SetValue(!prefs->usetransparentindex);
if (prefs->usetransparent) {
usetransparentindex->SetEnabled(true);
usetransparentcolor->SetEnabled(true);
transparentindex->SetEnabled(prefs->usetransparentindex);
transparentred->SetEnabled(!prefs->usetransparentindex);
transparentgreen->SetEnabled(!prefs->usetransparentindex);
transparentblue->SetEnabled(!prefs->usetransparentindex);
} else { } else {
usetransparentindex->SetEnabled(false); // display 256 colors
usetransparentcolor->SetEnabled(false); fColorCount256MI->SetMarked(true);
transparentindex->SetEnabled(false); fPrefs->palette_size_in_bits = 8;
transparentred->SetEnabled(false); }
transparentgreen->SetEnabled(false);
transparentblue->SetEnabled(false); fInterlacedCB->SetValue(fPrefs->interlaced);
if (fGreyScaleMI->IsMarked()) fUseDitheringCB->SetValue(false);
else fUseDitheringCB->SetValue(fPrefs->usedithering);
fUseTransparentCB->SetValue(fPrefs->usetransparent);
fUseTransparentIndexRB->SetValue(fPrefs->usetransparentindex);
fUseTransparentColorRB->SetValue(!fPrefs->usetransparentindex);
if (fPrefs->usetransparent) {
fUseTransparentIndexRB->SetEnabled(true);
fUseTransparentColorRB->SetEnabled(true);
fTransparentIndexTC->SetEnabled(fPrefs->usetransparentindex);
fTransparentRedTC->SetEnabled(!fPrefs->usetransparentindex);
fTransparentGreenTC->SetEnabled(!fPrefs->usetransparentindex);
fTransparentBlueTC->SetEnabled(!fPrefs->usetransparentindex);
} else {
fUseTransparentIndexRB->SetEnabled(false);
fUseTransparentColorRB->SetEnabled(false);
fTransparentIndexTC->SetEnabled(false);
fTransparentRedTC->SetEnabled(false);
fTransparentGreenTC->SetEnabled(false);
fTransparentBlueTC->SetEnabled(false);
} }
char temp[4]; char temp[4];
sprintf(temp, "%d", prefs->transparentindex); sprintf(temp, "%d", fPrefs->transparentindex);
transparentindex->SetText(temp); fTransparentIndexTC->SetText(temp);
sprintf(temp, "%d", prefs->transparentred); sprintf(temp, "%d", fPrefs->transparentred);
transparentred->SetText(temp); fTransparentRedTC->SetText(temp);
sprintf(temp, "%d", prefs->transparentgreen); sprintf(temp, "%d", fPrefs->transparentgreen);
transparentgreen->SetText(temp); fTransparentGreenTC->SetText(temp);
sprintf(temp, "%d", prefs->transparentblue); sprintf(temp, "%d", fPrefs->transparentblue);
transparentblue->SetText(temp); fTransparentBlueTC->SetText(temp);
} }
void GIFView::AllAttached() { // AllAttached
void
GIFView::AllAttached()
{
BView::AllAttached(); BView::AllAttached();
BMessenger msgr(this); BMessenger msgr(this);
interlaced->SetTarget(msgr); fInterlacedCB->SetTarget(msgr);
usedithering->SetTarget(msgr); fUseDitheringCB->SetTarget(msgr);
usetransparent->SetTarget(msgr); fUseTransparentCB->SetTarget(msgr);
usetransparentindex->SetTarget(msgr); fUseTransparentIndexRB->SetTarget(msgr);
transparentindex->SetTarget(msgr); fTransparentIndexTC->SetTarget(msgr);
usetransparentcolor->SetTarget(msgr); fUseTransparentColorRB->SetTarget(msgr);
transparentred->SetTarget(msgr); fTransparentRedTC->SetTarget(msgr);
transparentgreen->SetTarget(msgr); fTransparentGreenTC->SetTarget(msgr);
transparentblue->SetTarget(msgr); fTransparentBlueTC->SetTarget(msgr);
websafe->SetTarget(msgr); fPaletteM->SetTargetForItems(msgr);
beossystem->SetTarget(msgr); fColorCountM->SetTargetForItems(msgr);
greyscale->SetTarget(msgr);
optimal->SetTarget(msgr);
} }
void GIFView::MessageReceived(BMessage *message) { // MessageReceived
void
GIFView::MessageReceived(BMessage *message)
{
switch (message->what) { switch (message->what) {
case GV_WEB_SAFE: case GV_WEB_SAFE:
prefs->palettemode = WEB_SAFE_PALETTE; fPrefs->palettemode = WEB_SAFE_PALETTE;
usedithering->SetEnabled(true); fUseDitheringCB->SetEnabled(true);
fColorCountMF->SetEnabled(false);
fColorCount256MI->SetMarked(true);
break; break;
case GV_BEOS_SYSTEM: case GV_BEOS_SYSTEM:
prefs->palettemode = BEOS_SYSTEM_PALETTE; fPrefs->palettemode = BEOS_SYSTEM_PALETTE;
usedithering->SetEnabled(true); fUseDitheringCB->SetEnabled(true);
fColorCountMF->SetEnabled(false);
fColorCount256MI->SetMarked(true);
break; break;
case GV_GREYSCALE: case GV_GREYSCALE:
prefs->palettemode = GREYSCALE_PALETTE; fPrefs->palettemode = GREYSCALE_PALETTE;
usedithering->SetEnabled(false); fUseDitheringCB->SetEnabled(false);
usedithering->SetValue(false); fUseDitheringCB->SetValue(false);
prefs->usedithering = false; fColorCountMF->SetEnabled(false);
fColorCount256MI->SetMarked(true);
fPrefs->usedithering = false;
break; break;
case GV_OPTIMAL: case GV_OPTIMAL:
prefs->palettemode = OPTIMAL_PALETTE; fPrefs->palettemode = OPTIMAL_PALETTE;
usedithering->SetEnabled(true); fUseDitheringCB->SetEnabled(true);
fColorCountMF->SetEnabled(true);
fColorCountMI[fPrefs->palette_size_in_bits - 1]->SetMarked(true);
break;
case GV_SET_COLOR_COUNT:
if (fColorCountMF->IsEnabled()) {
int32 sizeInBits;
if (message->FindInt32("size in bits", &sizeInBits) >= B_OK) {
if (sizeInBits > 0 && sizeInBits <= 8)
fPrefs->palette_size_in_bits = sizeInBits;
}
}
break; break;
case GV_INTERLACED: case GV_INTERLACED:
prefs->interlaced = interlaced->Value(); fPrefs->interlaced = fInterlacedCB->Value();
break; break;
case GV_USE_DITHERING: case GV_USE_DITHERING:
prefs->usedithering = usedithering->Value(); fPrefs->usedithering = fUseDitheringCB->Value();
break; break;
case GV_USE_TRANSPARENT: case GV_USE_TRANSPARENT:
prefs->usetransparent = usetransparent->Value(); fPrefs->usetransparent = fUseTransparentCB->Value();
if (prefs->usetransparent) { if (fPrefs->usetransparent) {
usetransparentindex->SetEnabled(true); fUseTransparentIndexRB->SetEnabled(true);
usetransparentcolor->SetEnabled(true); fUseTransparentColorRB->SetEnabled(true);
transparentindex->SetEnabled(usetransparentindex->Value()); fTransparentIndexTC->SetEnabled(fUseTransparentIndexRB->Value());
transparentred->SetEnabled(usetransparentcolor->Value()); fTransparentRedTC->SetEnabled(fUseTransparentColorRB->Value());
transparentgreen->SetEnabled(usetransparentcolor->Value()); fTransparentGreenTC->SetEnabled(fUseTransparentColorRB->Value());
transparentblue->SetEnabled(usetransparentcolor->Value()); fTransparentBlueTC->SetEnabled(fUseTransparentColorRB->Value());
} else { } else {
usetransparentindex->SetEnabled(false); fUseTransparentIndexRB->SetEnabled(false);
usetransparentcolor->SetEnabled(false); fUseTransparentColorRB->SetEnabled(false);
transparentindex->SetEnabled(false); fTransparentIndexTC->SetEnabled(false);
transparentred->SetEnabled(false); fTransparentRedTC->SetEnabled(false);
transparentgreen->SetEnabled(false); fTransparentGreenTC->SetEnabled(false);
transparentblue->SetEnabled(false); fTransparentBlueTC->SetEnabled(false);
} }
break; break;
case GV_USE_TRANSPARENT_INDEX: case GV_USE_TRANSPARENT_INDEX:
prefs->usetransparentindex = true; fPrefs->usetransparentindex = true;
transparentindex->SetEnabled(true); fTransparentIndexTC->SetEnabled(true);
transparentred->SetEnabled(false); fTransparentRedTC->SetEnabled(false);
transparentgreen->SetEnabled(false); fTransparentGreenTC->SetEnabled(false);
transparentblue->SetEnabled(false); fTransparentBlueTC->SetEnabled(false);
break; break;
case GV_TRANSPARENT_INDEX: case GV_TRANSPARENT_INDEX:
prefs->transparentindex = CheckInput(transparentindex); fPrefs->transparentindex = CheckInput(fTransparentIndexTC);
break; break;
case GV_USE_TRANSPARENT_COLOR: case GV_USE_TRANSPARENT_COLOR:
prefs->usetransparentindex = false; fPrefs->usetransparentindex = false;
transparentindex->SetEnabled(false); fTransparentIndexTC->SetEnabled(false);
transparentred->SetEnabled(true); fTransparentRedTC->SetEnabled(true);
transparentgreen->SetEnabled(true); fTransparentGreenTC->SetEnabled(true);
transparentblue->SetEnabled(true); fTransparentBlueTC->SetEnabled(true);
break; break;
case GV_TRANSPARENT_RED: case GV_TRANSPARENT_RED:
prefs->transparentred = CheckInput(transparentred); fPrefs->transparentred = CheckInput(fTransparentRedTC);
break; break;
case GV_TRANSPARENT_GREEN: case GV_TRANSPARENT_GREEN:
prefs->transparentgreen = CheckInput(transparentgreen); fPrefs->transparentgreen = CheckInput(fTransparentGreenTC);
break; break;
case GV_TRANSPARENT_BLUE: case GV_TRANSPARENT_BLUE:
prefs->transparentblue = CheckInput(transparentblue); fPrefs->transparentblue = CheckInput(fTransparentBlueTC);
break; break;
default: default:
BView::MessageReceived(message); BView::MessageReceived(message);
break; break;
} }
prefs->Save(); fPrefs->Save();
} }
int GIFView::CheckInput(BTextControl *control) { int GIFView::CheckInput(BTextControl *control) {
@@ -320,7 +407,3 @@ int GIFView::CheckInput(BTextControl *control) {
return value; return value;
} }
GIFView::~GIFView() {
delete prefs;
}
+33 -11
View File
@@ -13,10 +13,13 @@
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Additional authors: Stephan Aßmus, <[email protected]>
#ifndef GIFVIEW_H #ifndef GIFVIEW_H
#define GIFVIEW_H #define GIFVIEW_H
#include <View.h> #include <View.h>
class BMenuField; class BMenuField;
class BPopUpMenu; class BPopUpMenu;
class BMenuItem; class BMenuItem;
@@ -38,26 +41,45 @@ class Prefs;
#define GV_TRANSPARENT_RED 'gvtr' #define GV_TRANSPARENT_RED 'gvtr'
#define GV_TRANSPARENT_GREEN 'gvtg' #define GV_TRANSPARENT_GREEN 'gvtg'
#define GV_TRANSPARENT_BLUE 'gvtb' #define GV_TRANSPARENT_BLUE 'gvtb'
#define GV_SET_COLOR_COUNT 'gvcc'
class GIFView : public BView { class GIFView : public BView {
public: public:
GIFView(BRect rect, const char* name); GIFView(BRect rect, const char* name);
~GIFView(); virtual ~GIFView();
void MessageReceived(BMessage *message);
void AllAttached();
Prefs *prefs; virtual void MessageReceived(BMessage* message);
BMenuField *palettemenufield; virtual void AllAttached();
BPopUpMenu *palettepopupmenu;
BMenuItem *websafe, *beossystem, *greyscale, *optimal;
BCheckBox *interlaced, *usetransparent, *usedithering;
BRadioButton *usetransparentindex, *usetransparentcolor;
BTextControl *transparentindex, *transparentred,
*transparentgreen, *transparentblue;
private: private:
void RestorePrefs(); void RestorePrefs();
int CheckInput(BTextControl* control); int CheckInput(BTextControl* control);
Prefs* fPrefs;
BMenuField* fPaletteMF;
BPopUpMenu* fPaletteM;
BMenuItem* fWebSafeMI;
BMenuItem* fBeOSSystemMI;
BMenuItem* fGreyScaleMI;
BMenuItem* fOptimalMI;
BMenuField* fColorCountMF;
BPopUpMenu* fColorCountM;
BMenuItem* fColorCountMI[8];
BMenuItem* fColorCount256MI;
BCheckBox* fInterlacedCB;
BCheckBox* fUseTransparentCB;
BCheckBox* fUseDitheringCB;
BRadioButton* fUseTransparentIndexRB;
BRadioButton* fUseTransparentColorRB;
BTextControl* fTransparentIndexTC;
BTextControl* fTransparentRedTC;
BTextControl* fTransparentGreenTC;
BTextControl* fTransparentBlueTC;
}; };
#endif #endif
@@ -13,6 +13,8 @@
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Additional authors: Stephan Aßmus, <[email protected]>
#include "Prefs.h" #include "Prefs.h"
#include <File.h> #include <File.h>
#include <Path.h> #include <Path.h>
@@ -26,6 +28,7 @@ Prefs::Prefs() {
usedithering = true; usedithering = true;
transparentindex = transparentred = transparentgreen = transparentindex = transparentred = transparentgreen =
transparentblue = palettemode = 0; transparentblue = palettemode = 0;
palette_size_in_bits = 8;
BPath path; BPath path;
find_directory(B_USER_SETTINGS_DIRECTORY, &path); find_directory(B_USER_SETTINGS_DIRECTORY, &path);
@@ -47,6 +50,8 @@ Prefs::Prefs() {
if (!GetBool("usedithering", &usedithering, &db)) return; if (!GetBool("usedithering", &usedithering, &db)) return;
int di = 0; int di = 0;
if (!GetInt("palettemode", &palettemode, &di)) return; if (!GetInt("palettemode", &palettemode, &di)) return;
di = 8;
if (!GetInt("palettesize", &palette_size_in_bits, &di)) return;
di = 0; di = 0;
if (!GetInt("transparentindex", &transparentindex, &di)) return; if (!GetInt("transparentindex", &transparentindex, &di)) return;
di = 0; di = 0;
@@ -111,6 +116,7 @@ void Prefs::Save() {
if (!PutBool("usetransparentindex", &usetransparentindex)) return; if (!PutBool("usetransparentindex", &usetransparentindex)) return;
if (!PutBool("usedithering", &usedithering)) return; if (!PutBool("usedithering", &usedithering)) return;
if (!PutInt("palettemode", &palettemode)) return; if (!PutInt("palettemode", &palettemode)) return;
if (!PutInt("palettesize", &palette_size_in_bits)) return;
if (!PutInt("transparentindex", &transparentindex)) return; if (!PutInt("transparentindex", &transparentindex)) return;
if (!PutInt("transparentred", &transparentred)) return; if (!PutInt("transparentred", &transparentred)) return;
if (!PutInt("transparentgreen", &transparentgreen)) return; if (!PutInt("transparentgreen", &transparentgreen)) return;
@@ -13,6 +13,8 @@
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Additional authors: Stephan Aßmus, <[email protected]>
#ifndef PREFS_H #ifndef PREFS_H
#define PREFS_H #define PREFS_H
@@ -26,7 +28,7 @@ class Prefs {
bool interlaced, usetransparent, usetransparentindex, bool interlaced, usetransparent, usetransparentindex,
usedithering; usedithering;
int transparentindex, transparentred, transparentgreen, int transparentindex, transparentred, transparentgreen,
transparentblue, palettemode; transparentblue, palettemode, palette_size_in_bits;
private: private:
bool GetInt(char *name, int *value, int *defaultvalue); bool GetInt(char *name, int *value, int *defaultvalue);
bool GetBool(char *name, bool *value, bool *defaultvalue); bool GetBool(char *name, bool *value, bool *defaultvalue);
@@ -13,6 +13,8 @@
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Additional authors: Stephan Aßmus, <[email protected]>
#include "SFHash.h" #include "SFHash.h"
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
@@ -46,7 +48,9 @@ void SFHash::AddItem(HashItem *item) {
} }
} }
HashItem *SFHash::GetItem(unsigned int key) { HashItem*
SFHash::GetItem(unsigned int key)
{
int pos = key % size; int pos = key % size;
HashItem *item = main_array[pos]; HashItem *item = main_array[pos];
@@ -57,7 +61,9 @@ HashItem *SFHash::GetItem(unsigned int key) {
return NULL; return NULL;
} }
unsigned int SFHash::CountItems() { unsigned int
SFHash::CountItems()
{
unsigned int count = 0; unsigned int count = 0;
for (int x = 0; x < this->size; x++) { for (int x = 0; x < this->size; x++) {
HashItem *item = main_array[x]; HashItem *item = main_array[x];
@@ -69,7 +75,9 @@ unsigned int SFHash::CountItems() {
return count; return count;
} }
HashItem *SFHash::NextItem() { HashItem*
SFHash::NextItem()
{
if (iterate_pos >= size) { if (iterate_pos >= size) {
Rewind(); Rewind();
return NULL; return NULL;
@@ -13,6 +13,8 @@
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Additional authors: Stephan Aßmus, <[email protected]>
#ifndef SFHASH_H #ifndef SFHASH_H
#define SFHASH_H #define SFHASH_H
@@ -36,6 +38,7 @@ class SFHash {
void Rewind(); void Rewind();
bool fatalerror; bool fatalerror;
private: private:
int size, iterate_pos, iterate_depth; int size, iterate_pos, iterate_depth;
HashItem **main_array; HashItem **main_array;
@@ -13,6 +13,10 @@
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Additional authors: Stephan Aßmus, <[email protected]>
#include <new>
#include "SavePalette.h" #include "SavePalette.h"
#include <Bitmap.h> #include <Bitmap.h>
#include <stdlib.h> #include <stdlib.h>
@@ -21,6 +25,7 @@
extern bool debug; extern bool debug;
// "web safe palette"
const rgb_color wsp[256] = { const rgb_color wsp[256] = {
{0xff, 0xff, 0xff, 0xff}, {0xff, 0xff, 0xcc, 0xff}, {0xff, 0xff, 0xff, 0xff}, {0xff, 0xff, 0xcc, 0xff},
{0xff, 0xff, 0x99, 0xff}, {0xff, 0xff, 0x66, 0xff}, {0xff, 0xff, 0x99, 0xff}, {0xff, 0xff, 0x66, 0xff},
@@ -152,64 +157,109 @@ const rgb_color wsp[256] = {
{0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff} {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}
}; };
ColorItem::ColorItem(unsigned int k, unsigned int c) { class ColorItem : public HashItem {
public:
ColorItem(unsigned int k, unsigned int c,
uint8 r, uint8 g, uint8 b)
: count(c),
red(r),
green(g),
blue(b)
{
key = k; key = k;
count = c;
} }
unsigned int count;
uint8 red;
uint8 green;
uint8 blue;
};
SavePalette::SavePalette() { // constructor
pal = new rgb_color[256]; SavePalette::SavePalette(int mode)
backgroundindex = 0; : pal(new(nothrow) rgb_color[256]),
usetransparent = false; fSize(0),
transparentindex = 0; fSizeInBits(8),
size = size_in_bits = 0; fMode(mode),
fatalerror = false; fUseTransparent(false),
mode = WEB_SAFE_PALETTE; fTransparentIndex(0),
} fBackgroundIndex(0),
fFatalError(pal == NULL)
SavePalette::SavePalette(int predefined) { {
pal = new rgb_color[256]; if (IsValid()) {
backgroundindex = 0; if (fMode == WEB_SAFE_PALETTE) {
usetransparent = false;
transparentindex = 0;
fatalerror = false;
mode = predefined;
size_in_bits = 8;
if (predefined == WEB_SAFE_PALETTE) {
memcpy(pal, wsp, sizeof(rgb_color) * 256); memcpy(pal, wsp, sizeof(rgb_color) * 256);
size = 216; fSize = 216;
} else if (predefined == BEOS_SYSTEM_PALETTE) { } else if (fMode == BEOS_SYSTEM_PALETTE) {
color_map *map = (color_map *)system_colors(); color_map *map = (color_map *)system_colors();
memcpy(pal, map->color_list, sizeof(rgb_color) * 256); memcpy(pal, map->color_list, sizeof(rgb_color) * 256);
size = 256; fSize = 256;
} else if (predefined == GREYSCALE_PALETTE) { } else if (fMode == GREYSCALE_PALETTE) {
for (int x = 0; x < 256; x++) { for (int i = 0; i < 256; i++) {
pal[x].red = pal[x].green = pal[x].blue = x; pal[i].red = pal[i].green = pal[i].blue = i;
pal[x].alpha = 0xff; pal[i].alpha = 0xff;
}
fSize = 256;
} }
size = 256;
} }
} }
SavePalette::SavePalette(BBitmap *bitmap) { // make_key
pal = new rgb_color[256]; static int
backgroundindex = 0; make_key(uint8 r, uint8 g, uint8 b, uint8 bits)
usetransparent = false; {
transparentindex = 0; r = r >> (8 - bits);
fatalerror = false; g = g >> (8 - bits);
mode = OPTIMAL_PALETTE; b = b >> (8 - bits);
return (r << (bits * 2)) | (g << bits) | b;
}
// touch_color_item
static bool
touch_color_item(SFHash& hash, unsigned int key, uint8 r, uint8 g, uint8 b)
{
ColorItem* ci = (ColorItem*)hash.GetItem(key);
if (ci == NULL) {
ci = new(nothrow) ColorItem(key, 1, r, g, b);
if (ci == NULL) {
if (debug)
printf("Out of memory in touch_color_item()\n");
return false;
}
hash.AddItem((HashItem *)ci);
} else {
ci->count++;
// use brightest color
ci->red = max_c(ci->red, r);
ci->green = max_c(ci->green, g);
ci->blue = max_c(ci->blue, b);
}
return true;
}
// constructor
SavePalette::SavePalette(BBitmap *bitmap, int32 maxSizeInBits)
: pal(new(nothrow) rgb_color[256]),
fSize(0),
fSizeInBits(0),
fMode(OPTIMAL_PALETTE),
fUseTransparent(false),
fTransparentIndex(0),
fBackgroundIndex(0),
fFatalError(pal == NULL)
{
if (!IsValid())
return;
SFHash hash(1 << 16); SFHash hash(1 << 16);
if (hash.fatalerror) { if (hash.fatalerror) {
if (debug) if (debug)
printf("Out of memory in SavePalette(BBitmap *)\n"); printf("Out of memory in SavePalette(BBitmap *)\n");
fatalerror = true; fFatalError = true;
return; return;
} }
unsigned char r, g, b;
// reject unsupported color spaces
// TODO: B_CMAP8 and B_GRAY8 should be really easy to support as well!!
color_space cs = bitmap->ColorSpace(); color_space cs = bitmap->ColorSpace();
if (cs != B_RGB32 && cs != B_RGBA32 && cs != B_RGB32_BIG && cs != B_RGBA32_BIG) { if (cs != B_RGB32 && cs != B_RGBA32 && cs != B_RGB32_BIG && cs != B_RGBA32_BIG) {
if (debug) { if (debug) {
@@ -217,111 +267,177 @@ SavePalette::SavePalette(BBitmap *bitmap) {
printf("%d %d %d %d or 0x%x\n", (cs & 0xff000000) >> 24, (cs & 0xff0000) >> 16, printf("%d %d %d %d or 0x%x\n", (cs & 0xff000000) >> 24, (cs & 0xff0000) >> 16,
(cs & 0xff00) >> 8, cs & 0xff, cs); (cs & 0xff00) >> 8, cs & 0xff, cs);
} }
fatalerror = true; fFatalError = true;
return; return;
} }
BRect rect = bitmap->Bounds(); BRect rect = bitmap->Bounds();
int height = rect.IntegerHeight() + 1; uint32 height = rect.IntegerHeight() + 1;
int width = rect.IntegerWidth() + 1; uint32 width = rect.IntegerWidth() + 1;
unsigned char *bits = (unsigned char *)bitmap->Bits(); uint8* bits = (uint8*)bitmap->Bits();
uint32 bpr = bitmap->BytesPerRow();
for (int y = 0; y < height; y++) { uint8 r, g, b;
for (int x = 0; x < width; x++) { uint8 useBits = 3 + maxSizeInBits / 2;
if (cs == B_RGB32 || cs == B_RGBA32) { if (cs == B_RGB32 || cs == B_RGBA32) {
b = bits[0]; for (uint32 y = 0; y < height; y++) {
g = bits[1]; uint8* handle = bits;
r = bits[2]; for (uint32 x = 0; x < width; x++) {
} else { b = handle[0];
r = bits[1]; g = handle[1];
g = bits[2]; r = handle[2];
b = bits[3]; handle += 4;
}
bits += 4;
unsigned int key = (r << 16) + (g << 8) + b; uint32 key = make_key(r, g, b, useBits);
ColorItem *ci = (ColorItem *)hash.GetItem(key); if (!touch_color_item(hash, key, r, g, b)) {
if (ci == NULL) {
ci = new ColorItem(key, 1);
if (ci == NULL) {
if (debug) printf("Out of memory in SavePalette(BBitmap *)\n"); if (debug) printf("Out of memory in SavePalette(BBitmap *)\n");
fatalerror = true; fFatalError = true;
return; return;
} }
hash.AddItem((HashItem *)ci);
} else {
ci->count++;
} }
bits += bpr;
}
} else if ((cs == B_RGB32_BIG || cs == B_RGBA32_BIG)) {
for (uint32 y = 0; y < height; y++) {
uint8* handle = bits;
for (uint32 x = 0; x < width; x++) {
b = handle[2];
g = handle[1];
r = handle[0];
handle += 4;
uint32 key = make_key(r, g, b, useBits);
if (!touch_color_item(hash, key, r, g, b)) {
if (debug) printf("Out of memory in SavePalette(BBitmap *)\n");
fFatalError = true;
return;
}
}
bits += bpr;
} }
} }
int unique_colors = hash.CountItems(); int unique_colors = hash.CountItems();
size_in_bits = 1; while (((1 << fSizeInBits) < unique_colors) && (fSizeInBits < maxSizeInBits))
while (((1 << size_in_bits) < unique_colors) && (size_in_bits < 8)) size_in_bits++; fSizeInBits++;
size = 1 << size_in_bits; fSize = 1 << fSizeInBits;
ColorItem **topcolors = (ColorItem **)malloc(size * 4); ColorItem **topcolors = (ColorItem **)malloc(fSize * 4);
if (topcolors == NULL) { if (topcolors == NULL) {
if (debug) printf("Out of memory in SavePalette(BBitmap *)\n"); if (debug) printf("Out of memory in SavePalette(BBitmap *)\n");
fatalerror = true; fFatalError = true;
return; return;
} }
ColorItem *dummy = new ColorItem(0, 0); ColorItem *dummy = new ColorItem(0, 0, 0, 0, 0);
for (int x = 0; x < size; x++) topcolors[x] = dummy; for (int i = 0; i < fSize; i++)
topcolors[i] = dummy;
for (int x = 0; x < unique_colors; x++) { for (int i = 0; i < unique_colors; i++) {
ColorItem *ci = (ColorItem *)hash.NextItem(); ColorItem *ci = (ColorItem *)hash.NextItem();
for (int y = 0; y < size; y++) { for (int j = 0; j < fSize; j++) {
if (ci->count > topcolors[y]->count) { if (ci->count > topcolors[j]->count) {
for (int z = size - 1; z > y; z--) { for (int k = fSize - 1; k > j; k--) {
topcolors[z] = topcolors[z-1]; topcolors[k] = topcolors[k - 1];
} }
topcolors[y] = ci; topcolors[j] = ci;
break; break;
} }
} }
} }
for (int x = 0; x < size; x++) { for (int i = 0; i < fSize; i++) {
pal[x].red = topcolors[x]->key >> 16; pal[i].red = topcolors[i]->red;
pal[x].green = (topcolors[x]->key & 0xff00) >> 8; pal[i].green = topcolors[i]->green;
pal[x].blue = topcolors[x]->key & 0xff; pal[i].blue = topcolors[i]->blue;
pal[x].alpha = 0xff; pal[i].alpha = 0xff;
} }
delete dummy; delete dummy;
free(topcolors); free(topcolors);
} }
/* Standard mapping services once a palette is loaded */ // destructor
unsigned char SavePalette::IndexForColor(unsigned char red, unsigned char green, SavePalette::~SavePalette()
unsigned char blue) { {
if (mode == GREYSCALE_PALETTE) {
unsigned char result = (red + (green << 1) + blue) >> 2;
return result;
}
unsigned char best = 0;
int min = 255 * 3;
for (int x = 0; x < size && min != 0; x++) {
int diff = abs(red - pal[x].red);
diff += abs(green - pal[x].green);
diff += abs(blue - pal[x].blue);
if (diff < min) {
min = diff;
best = x;
}
}
return best;
}
unsigned char SavePalette::IndexForColor(rgb_color color) {
return IndexForColor(color.red, color.green, color.blue);
}
SavePalette::~SavePalette() {
delete[] pal; delete[] pal;
} }
// IndexForColor
//
// standard mapping services once a palette is loaded
uint8
SavePalette::IndexForColor(uint8 red, uint8 green, uint8 blue)
{
uint8 index = 0;
if (fMode == GREYSCALE_PALETTE) {
index = (308 * red + 600 * green + 116 * blue) / 1024;
} else {
int closestDistance = 255 * 255 * 3;
for (int i = 0; i < fSize && closestDistance != 0; i++) {
int rd = (int)red - (int)pal[i].red;
int gd = (int)green - (int)pal[i].green;
int bd = (int)blue - (int)pal[i].blue;
int distanceAtIndex = rd * rd + gd * gd + bd * bd;
if (distanceAtIndex < closestDistance) {
closestDistance = distanceAtIndex;
index = i;
}
}
}
return index;
}
// SetUseTransparent
void
SavePalette::SetUseTransparent(bool use)
{
fUseTransparent = use;
}
// SetTransparentIndex
void
SavePalette::SetTransparentIndex(int index)
{
fTransparentIndex = max_c(fSize - 1, index);
}
// SetTransparentColor
bool
SavePalette::SetTransparentColor(uint8 red, uint8 green, uint8 blue)
{
bool found = false;
for (int i = 0; i < fSize; i++) {
if (pal[i].red == red &&
pal[i].green == green &&
pal[i].blue == blue) {
fTransparentIndex = i;
found = true;
break;
}
}
if (!found) {
fTransparentIndex = 0;
fUseTransparent = false;
}
return found;
}
// GetColors
void
SavePalette::GetColors(uint8* buffer, int size) const
{
int maxIndex = max_c(size / 3, fSize) - 1;
for (int i = 0; i <= maxIndex; i++) {
*buffer++ = pal[i].red;
*buffer++ = pal[i].green;
*buffer++ = pal[i].blue;
}
int rest = (maxIndex + 1) * 3;
if (rest < size)
memset(buffer, 0, size - rest);
}
@@ -27,34 +27,58 @@ enum {
OPTIMAL_PALETTE OPTIMAL_PALETTE
}; };
class ColorItem : public HashItem {
public:
ColorItem(unsigned int k, unsigned int c);
unsigned int count;
};
class ColorCache : public HashItem {
public:
unsigned char index;
};
class SavePalette { class SavePalette {
public: public:
SavePalette(int predefined); SavePalette(int mode);
SavePalette(BBitmap *bitmap); SavePalette(BBitmap *bitmap,
SavePalette(); int32 maxSizeInBits = 8);
~SavePalette(); virtual ~SavePalette();
unsigned char IndexForColor(unsigned char red, unsigned char green, inline bool IsValid() const
unsigned char blue); { return !fFatalError; }
unsigned char IndexForColor(rgb_color color);
uint8 IndexForColor(uint8 red, uint8 green, uint8 blue);
inline uint8 IndexForColor(const rgb_color& color);
void SetUseTransparent(bool use);
inline bool UseTransparent() const
{ return fUseTransparent; }
void SetTransparentIndex(int index);
inline int TransparentIndex() const
{ return fTransparentIndex; }
bool SetTransparentColor(uint8 red,
uint8 green,
uint8 blue);
inline int SizeInBits() const
{ return fSizeInBits; }
inline int BackgroundIndex() const
{ return fBackgroundIndex; }
void GetColors(uint8* buffer, int size) const;
rgb_color* pal; rgb_color* pal;
int size, size_in_bits, mode;
bool usetransparent; private:
int backgroundindex, transparentindex; int fSize;
bool fatalerror; int fSizeInBits;
int fMode;
bool fUseTransparent;
int fTransparentIndex;
int fBackgroundIndex;
bool fFatalError;
}; };
// IndexForColor
inline uint8
SavePalette::IndexForColor(const rgb_color& color)
{
return IndexForColor(color.red, color.green, color.blue);
}
#endif #endif