diff --git a/src/add-ons/translators/giftranslator/GIFSave.cpp b/src/add-ons/translators/giftranslator/GIFSave.cpp index 4c4f1ade5e..4ea1d4e06f 100644 --- a/src/add-ons/translators/giftranslator/GIFSave.cpp +++ b/src/add-ons/translators/giftranslator/GIFSave.cpp @@ -13,6 +13,8 @@ // //////////////////////////////////////////////////////////////////////////////// +// Additional authors: Stephan Aßmus, + #include "GIFSave.h" #include #include @@ -26,7 +28,14 @@ const int32 seven_sixteenth = (int32)((7.0 / 16.0) * 32768); 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(); if (cs != B_RGB32 && cs != B_RGBA32 && cs != B_RGB32_BIG && cs != B_RGBA32_BIG) { if (debug) printf("GIFSave::GIFSave() - Unknown color space\n"); @@ -36,9 +45,11 @@ GIFSave::GIFSave(BBitmap *bitmap, BPositionIO *output) { fatalerror = false; prefs = new Prefs(); - if (prefs->palettemode == OPTIMAL_PALETTE) palette = new SavePalette(bitmap); - else palette = new SavePalette(prefs->palettemode); - if (palette->fatalerror) { + if (prefs->palettemode == OPTIMAL_PALETTE) + palette = new SavePalette(bitmap, prefs->palette_size_in_bits); + else + palette = new SavePalette(prefs->palettemode); + if (!palette->IsValid()) { fatalerror = true; return; } @@ -86,33 +97,32 @@ GIFSave::GIFSave(BBitmap *bitmap, BPositionIO *output) { } } - palette->usetransparent = prefs->usetransparent; + palette->SetUseTransparent(prefs->usetransparent); if (prefs->usetransparent) { if (prefs->usetransparentindex) { - palette->transparentindex = prefs->transparentindex; - if (debug) printf("GIFSave::GIFSave() - Using transparent index %d\n", palette->transparentindex); + palette->SetTransparentIndex(prefs->transparentindex); + if (debug) + printf("GIFSave::GIFSave() - Using transparent index %d\n", palette->TransparentIndex()); } else { - palette->transparentindex = -1; - for (int x = 0; x < palette->size; x++) { - if (palette->pal[x].red == prefs->transparentred && - palette->pal[x].green == prefs->transparentgreen && - palette->pal[x].blue == prefs->transparentblue) { - - palette->transparentindex = x; - if (debug) printf("GIFSave::GIFSave() - Found transparent color %d,%d,%d at index %d\n", prefs->transparentred, - prefs->transparentgreen, prefs->transparentblue, x); - break; + bool found = palette->SetTransparentColor((uint8)prefs->transparentred, + (uint8)prefs->transparentred, + (uint8)prefs->transparentblue); + if (found) { + if (debug) { + printf("GIFSave::GIFSave() - Found transparent color %d,%d,%d at index %d\n", + prefs->transparentred, prefs->transparentgreen, prefs->transparentblue, + palette->TransparentIndex()); + } + } else { + if (debug) { + printf("GIFSave::GIFSave() - Did not find color %d,%d,%d - deactivating transparency\n", + prefs->transparentred, prefs->transparentgreen, prefs->transparentblue); } - } - if (palette->transparentindex == -1) { - palette->usetransparent = false; - palette->transparentindex = 0; - if (debug) printf("GIFSave::GIFSave() - Did not find color %d,%d,%d - deactivating transparency\n", - prefs->transparentred, prefs->transparentgreen, prefs->transparentblue); } } } else { - if (debug) printf("GIFSave::GIFSave() - Not using transparency\n"); + if (debug) + printf("GIFSave::GIFSave() - Not using transparency\n"); } this->output = output; @@ -140,38 +150,50 @@ GIFSave::GIFSave(BBitmap *bitmap, BPositionIO *output) { output->Write(&t, 1); } -void GIFSave::WriteGIFHeader() { +// destructor +GIFSave::~GIFSave() +{ + delete palette; + delete prefs; +} + +// WriteGIFHeader +void +GIFSave::WriteGIFHeader() +{ // Standard header unsigned char header[] = {'G', 'I', 'F', '8', '9', 'a', 0, 0, 0, 0, 0, 0, 0}; header[6] = width & 0xff; header[7] = (width & 0xff00) >> 8; header[8] = height & 0xff; header[9] = (height & 0xff00) >> 8; - header[10] = 0xf0 | (palette->size_in_bits - 1); - header[11] = palette->backgroundindex; + header[10] = 0xf0 | (palette->SizeInBits() - 1); + header[11] = palette->BackgroundIndex(); output->Write(header, 13); // Global palette - int size = 1 << palette->size_in_bits; - char c[256 * 3]; // can't be bigger than this - for (int x = 0; x < size; x++) { - c[x * 3] = palette->pal[x].red; - c[x * 3 + 1] = palette->pal[x].green; - c[x * 3 + 2] = palette->pal[x].blue; - } - output->Write(c, size * 3); + int size = (1 << palette->SizeInBits()) * 3; + uint8* buffer = new uint8[size]; // can't be bigger than this + palette->GetColors(buffer, size); + output->Write(buffer, size); + delete[] buffer; } -void GIFSave::WriteGIFControlBlock() { +// WriteGIFControlBlock +void +GIFSave::WriteGIFControlBlock() +{ unsigned char b[8] = {0x21, 0xf9, 0x04, 0, 0, 0, 0, 0x00}; - if (palette->usetransparent) { + if (palette->UseTransparent()) { b[3] = b[3] | 1; - b[6] = palette->transparentindex; + b[6] = palette->TransparentIndex(); } output->Write(b, 8); } -void GIFSave::WriteGIFImageHeader() { +// WriteGIFImageHeader +void GIFSave::WriteGIFImageHeader() +{ unsigned char header[10]; header[0] = 0x2c; header[1] = header[2] = 0; @@ -187,7 +209,9 @@ void GIFSave::WriteGIFImageHeader() { output->Write(header, 10); } -void GIFSave::WriteGIFImageData() { +// WriteGIFImageData +void GIFSave::WriteGIFImageData() +{ InitFrame(); code_value = (short *)malloc(HASHSIZE * 2); prefix_code = (short *)malloc(HASHSIZE * 2); @@ -232,7 +256,10 @@ void GIFSave::WriteGIFImageData() { free(append_char); } -void GIFSave::OutputCode(short code, int BITS, bool flush) { +// OutputCode +void +GIFSave::OutputCode(short code, int BITS, bool flush) +{ if (!flush) { bit_buffer |= (unsigned int) code << bit_count; 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++) { code_value[q] = -1; 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; int hashindex = HASH(s, c); int nextindex; @@ -286,7 +319,10 @@ int GIFSave::CheckHashtable(int s, unsigned char c) { return -1; } -void GIFSave::AddToHashtable(int s, unsigned char c) { +// AddToHashtable +void +GIFSave::AddToHashtable(int s, unsigned char c) +{ int hashindex = HASH(s, c); while (code_value[hashindex] != -1) hashindex = (hashindex + HASHSTEP) % HASHSIZE; code_value[hashindex] = next_code; @@ -294,7 +330,10 @@ void GIFSave::AddToHashtable(int s, unsigned char c) { append_char[next_code] = c; } -unsigned char GIFSave::NextPixel(int pixel) { +// NextPixel +unsigned char +GIFSave::NextPixel(int pixel) +{ int bpr = bitmap->BytesPerRow(); color_space cs = bitmap->ColorSpace(); unsigned char r, g, b; @@ -340,7 +379,7 @@ unsigned char GIFSave::NextPixel(int pixel) { cc->index = palette->IndexForColor(r, g, b); hash->AddItem((HashItem *)cc); } - + if (prefs->usedithering) { int x = pixel % width; // Don't carry error on to next line when interlaced because @@ -352,10 +391,10 @@ unsigned char GIFSave::NextPixel(int pixel) { blue_error[y] = 0; } } - - int32 red_total_error = palette->pal[cc->index].red - r; - int32 green_total_error = palette->pal[cc->index].green - g; - int32 blue_total_error = palette->pal[cc->index].blue - b; + + int32 red_total_error = palette->pal[cc->index].red - r; + int32 green_total_error = palette->pal[cc->index].green - g; + int32 blue_total_error = palette->pal[cc->index].blue - b; red_side_error = (red_error[x + 1] + (red_total_error * seven_sixteenth)) >> 15; blue_side_error = (blue_error[x + 1] + (blue_total_error * seven_sixteenth)) >> 15; @@ -368,7 +407,7 @@ unsigned char GIFSave::NextPixel(int pixel) { red_error[x] += (red_total_error * five_sixteenth); green_error[x] += (green_total_error * five_sixteenth); blue_error[x] += (blue_total_error * five_sixteenth); - + red_error[x + 1] = (red_total_error * one_sixteenth); green_error[x + 1] = (green_total_error * one_sixteenth); blue_error[x + 1] = (blue_total_error * one_sixteenth); @@ -377,9 +416,13 @@ unsigned char GIFSave::NextPixel(int pixel) { return cc->index; } -void GIFSave::InitFrame() { - code_size = palette->size_in_bits; - if (code_size == 1) code_size++; +// InitFrame +void +GIFSave::InitFrame() +{ + code_size = palette->SizeInBits(); + if (code_size == 1) + code_size++; BITS = code_size + 1; clear_code = 1 << code_size; end_code = clear_code + 1; @@ -398,9 +441,3 @@ void GIFSave::InitFrame() { gifbits = (unsigned char *)bitmap->Bits(); } - -GIFSave::~GIFSave() { - delete palette; - delete prefs; -} - diff --git a/src/add-ons/translators/giftranslator/GIFTranslator.cpp b/src/add-ons/translators/giftranslator/GIFTranslator.cpp index 5789a9583b..6d1025dd00 100644 --- a/src/add-ons/translators/giftranslator/GIFTranslator.cpp +++ b/src/add-ons/translators/giftranslator/GIFTranslator.cpp @@ -41,8 +41,8 @@ status_t GetBitmap(BPositionIO *in, BBitmap **out); /* Required data */ char translatorName[] = "GIF Images"; -char translatorInfo[] = "GIF image translator v1.3"; -int32 translatorVersion = 0x130; +char translatorInfo[] = "GIF image translator v1.4"; +int32 translatorVersion = 0x140; translation_format inputFormats[] = { { GIF_TYPE, B_TRANSLATOR_BITMAP, 0.8, 0.8, "image/gif", "GIF image" }, diff --git a/src/add-ons/translators/giftranslator/GIFView.cpp b/src/add-ons/translators/giftranslator/GIFView.cpp index 36cbc50ceb..45734eda27 100644 --- a/src/add-ons/translators/giftranslator/GIFView.cpp +++ b/src/add-ons/translators/giftranslator/GIFView.cpp @@ -13,19 +13,26 @@ // //////////////////////////////////////////////////////////////////////////////// -#include "GIFView.h" -#include "SavePalette.h" -#include "Prefs.h" -#include -#include +// Additional authors: Stephan Aßmus, + #include +#include + +#include +#include + +#include "Prefs.h" +#include "SavePalette.h" + +#include "GIFView.h" extern int32 translatorVersion; extern char translatorName[]; -GIFView::GIFView(BRect rect, const char *name) : - BView(rect, name, B_FOLLOW_ALL, B_WILL_DRAW) { - +// constructor +GIFView::GIFView(BRect rect, const char *name) + : BView(rect, name, B_FOLLOW_ALL, B_WILL_DRAW) +{ SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); font_height fh; @@ -39,111 +46,146 @@ GIFView::GIFView(BRect rect, const char *name) : char version_string[100]; sprintf(version_string, "v%d.%d.%d %s", (int)(translatorVersion >> 8), (int)((translatorVersion >> 4) & 0xf), (int)(translatorVersion & 0xf), __DATE__); - r.top = r.bottom + 20; be_plain_font->GetHeight(&fh); 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); BStringView *version = new BStringView(r, "Version", version_string); version->SetFont(be_plain_font); AddChild(version); - + + BFont small(be_plain_font); + small.SetSize(max_c(7.0, small.Size() * 0.7)); const char *copyright_string = "© 2003 Daniel Switkin, software@switkin.com"; - r.top = r.bottom + 10; + r.top = r.bottom + 5; + r.left = 10; 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); - copyright->SetFont(be_plain_font); + copyright->SetFont(&small); AddChild(copyright); + + //menu fields (Palette & Colors) + fWebSafeMI = new BMenuItem("Websafe", new BMessage(GV_WEB_SAFE), 0, 0); + fBeOSSystemMI = new BMenuItem("BeOS System", new BMessage(GV_BEOS_SYSTEM), 0, 0); + fGreyScaleMI = new BMenuItem("Greyscale", new BMessage(GV_GREYSCALE), 0, 0); + fOptimalMI = new BMenuItem("Optimal", new BMessage(GV_OPTIMAL), 0, 0); + fPaletteM = new BPopUpMenu("PalettePopUpMenu", true, true, B_ITEMS_IN_COLUMN); + fPaletteM->AddItem(fWebSafeMI); + fPaletteM->AddItem(fBeOSSystemMI); + fPaletteM->AddItem(fGreyScaleMI); + fPaletteM->AddItem(fOptimalMI); + + 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]; - websafe = new BMenuItem("websafe", new BMessage(GV_WEB_SAFE), 0, 0); - beossystem = new BMenuItem("BeOS system", new BMessage(GV_BEOS_SYSTEM), 0, 0); - greyscale = new BMenuItem("greyscale", new BMessage(GV_GREYSCALE), 0, 0); - optimal = new BMenuItem("optimal", new BMessage(GV_OPTIMAL), 0, 0); - palettepopupmenu = new BPopUpMenu("PalettePopUpMenu", true, true, B_ITEMS_IN_COLUMN); - palettepopupmenu->AddItem(websafe); - palettepopupmenu->AddItem(beossystem); - palettepopupmenu->AddItem(greyscale); - palettepopupmenu->AddItem(optimal); - - r.top = r.bottom + 10; + r.top = r.bottom + 5; r.bottom = r.top + 24; - r.right = r.left + be_plain_font->StringWidth("Palette:") + - be_plain_font->StringWidth("BeOS system") + 32; - palettemenufield = new BMenuField(r, "PaletteMenuField", "Palette:", - palettepopupmenu, B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE); - AddChild(palettemenufield); - palettemenufield->SetDivider(be_plain_font->StringWidth("Palette:") + 7); + fPaletteMF = new BMenuField(r, "PaletteMenuField", "Palette", + fPaletteM, B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE); + AddChild(fPaletteMF); + + 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); - r.top = palettemenufield->Frame().bottom + 5; + // 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.right = r.left + be_plain_font->StringWidth("Use dithering") + 20; - usedithering = new BCheckBox(r, "UseDithering", "Use dithering", + fUseDitheringCB = new BCheckBox(r, "UseDithering", "Use dithering", new BMessage(GV_USE_DITHERING)); - AddChild(usedithering); - - r.top = usedithering->Frame().bottom + 2; + AddChild(fUseDitheringCB); + + r.top = fUseDitheringCB->Frame().bottom + 2; r.bottom = r.top + 10; - r.right = r.left + be_plain_font->StringWidth("Write interlaced images") + 20; - interlaced = new BCheckBox(r, "Interlaced", "Write interlaced images", + fInterlacedCB = new BCheckBox(r, "Interlaced", "Write interlaced images", 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.right = r.left + be_plain_font->StringWidth("Write transparent images") + 20; - usetransparent = new BCheckBox(r, "UseTransparent", "Write transparent images", + fUseTransparentCB = new BCheckBox(r, "UseTransparent", "Write transparent images", new BMessage(GV_USE_TRANSPARENT)); - AddChild(usetransparent); - - r.top = usetransparent->Frame().bottom + 2; + AddChild(fUseTransparentCB); + + // radio buttons + r.top = fUseTransparentCB->Frame().bottom + 2; r.bottom = r.top + 10; - r.right = r.left + be_plain_font->StringWidth("Use index:") + 20; - usetransparentindex = new BRadioButton(r, "UseTransparentIndex", "Use index:", + r.right = r.left + be_plain_font->StringWidth("Use index") + 20; + fUseTransparentIndexRB = new BRadioButton(r, "UseTransparentIndex", "Use index", new BMessage(GV_USE_TRANSPARENT_INDEX)); - AddChild(usetransparentindex); + AddChild(fUseTransparentIndexRB); r.left = r.right + 1; r.right = r.left + 30; - transparentindex = new BTextControl(r, "TransparentIndex", "", "0", + fTransparentIndexTC = new BTextControl(r, "TransparentIndex", "", "0", new BMessage(GV_TRANSPARENT_INDEX)); - AddChild(transparentindex); - transparentindex->SetDivider(0); + AddChild(fTransparentIndexTC); + fTransparentIndexTC->SetDivider(0); - r.top = usetransparentindex->Frame().bottom + 0; + r.top = fUseTransparentIndexRB->Frame().bottom + 0; r.bottom = r.top + 10; r.left = 10; - r.right = r.left + be_plain_font->StringWidth("Use rgb color:") + 20; - usetransparentcolor = new BRadioButton(r, "UseTransparentColor", "Use rgb color:", + r.right = r.left + be_plain_font->StringWidth("Use rgb color") + 20; + fUseTransparentColorRB = new BRadioButton(r, "UseTransparentColor", "Use rgb color", new BMessage(GV_USE_TRANSPARENT_COLOR)); - AddChild(usetransparentcolor); + AddChild(fUseTransparentColorRB); r.left = r.right + 1; r.right = r.left + 30; - transparentred = new BTextControl(r, "TransparentRed", "", "0", + fTransparentRedTC = new BTextControl(r, "TransparentRed", "", "0", new BMessage(GV_TRANSPARENT_RED)); - AddChild(transparentred); - transparentred->SetDivider(0); + AddChild(fTransparentRedTC); + fTransparentRedTC->SetDivider(0); r.left = r.right + 5; r.right = r.left + 30; - transparentgreen = new BTextControl(r, "TransparentGreen", "", "0", + fTransparentGreenTC = new BTextControl(r, "TransparentGreen", "", "0", new BMessage(GV_TRANSPARENT_GREEN)); - AddChild(transparentgreen); - transparentgreen->SetDivider(0); + AddChild(fTransparentGreenTC); + fTransparentGreenTC->SetDivider(0); r.left = r.right + 5; r.right = r.left + 30; - transparentblue = new BTextControl(r, "TransparentBlue", "", "0", + fTransparentBlueTC = new BTextControl(r, "TransparentBlue", "", "0", new BMessage(GV_TRANSPARENT_BLUE)); - AddChild(transparentblue); - transparentblue->SetDivider(0); - - BTextView *ti = transparentindex->TextView(); - BTextView *tr = transparentred->TextView(); - BTextView *tg = transparentgreen->TextView(); - BTextView *tb = transparentblue->TextView(); + AddChild(fTransparentBlueTC); + fTransparentBlueTC->SetDivider(0); + + // align text controls + float diff = fTransparentRedTC->Frame().left - fTransparentIndexTC->Frame().left; + if (diff > 0) { + 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++) { if (x < '0' || x > '9') { @@ -157,156 +199,201 @@ GIFView::GIFView(BRect rect, const char *name) : RestorePrefs(); } -void GIFView::RestorePrefs() { - prefs = new Prefs(); - - switch (prefs->palettemode) { +// destructor +GIFView::~GIFView() +{ + delete fPrefs; +} + +// RestorePrefs +void +GIFView::RestorePrefs() +{ + fPrefs = new Prefs(); + + fColorCountMF->SetEnabled(false); + fUseDitheringCB->SetEnabled(true); + + switch (fPrefs->palettemode) { case WEB_SAFE_PALETTE: - websafe->SetMarked(true); + fWebSafeMI->SetMarked(true); break; case BEOS_SYSTEM_PALETTE: - beossystem->SetMarked(true); + fBeOSSystemMI->SetMarked(true); break; case GREYSCALE_PALETTE: - greyscale->SetMarked(true); - usedithering->SetEnabled(false); + fGreyScaleMI->SetMarked(true); + fUseDitheringCB->SetEnabled(false); break; case OPTIMAL_PALETTE: - optimal->SetMarked(true); + fOptimalMI->SetMarked(true); + fColorCountMF->SetEnabled(true); break; default: - prefs->palettemode = WEB_SAFE_PALETTE; - websafe->SetMarked(true); + fPrefs->palettemode = WEB_SAFE_PALETTE; + fWebSafeMI->SetMarked(true); break; } - - interlaced->SetValue(prefs->interlaced); - - if (greyscale->IsMarked()) usedithering->SetValue(false); - else usedithering->SetValue(prefs->usedithering); - usetransparent->SetValue(prefs->usetransparent); - 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); + + if (fColorCountMF->IsEnabled() && + fPrefs->palette_size_in_bits > 0 && + fPrefs->palette_size_in_bits <= 8) { + // display the stored color count + fColorCountMI[fPrefs->palette_size_in_bits - 1]->SetMarked(true); } else { - usetransparentindex->SetEnabled(false); - usetransparentcolor->SetEnabled(false); - transparentindex->SetEnabled(false); - transparentred->SetEnabled(false); - transparentgreen->SetEnabled(false); - transparentblue->SetEnabled(false); + // display 256 colors + fColorCount256MI->SetMarked(true); + fPrefs->palette_size_in_bits = 8; + } + + 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]; - sprintf(temp, "%d", prefs->transparentindex); - transparentindex->SetText(temp); - sprintf(temp, "%d", prefs->transparentred); - transparentred->SetText(temp); - sprintf(temp, "%d", prefs->transparentgreen); - transparentgreen->SetText(temp); - sprintf(temp, "%d", prefs->transparentblue); - transparentblue->SetText(temp); + sprintf(temp, "%d", fPrefs->transparentindex); + fTransparentIndexTC->SetText(temp); + sprintf(temp, "%d", fPrefs->transparentred); + fTransparentRedTC->SetText(temp); + sprintf(temp, "%d", fPrefs->transparentgreen); + fTransparentGreenTC->SetText(temp); + sprintf(temp, "%d", fPrefs->transparentblue); + fTransparentBlueTC->SetText(temp); } -void GIFView::AllAttached() { +// AllAttached +void +GIFView::AllAttached() +{ BView::AllAttached(); BMessenger msgr(this); - interlaced->SetTarget(msgr); - usedithering->SetTarget(msgr); - usetransparent->SetTarget(msgr); - usetransparentindex->SetTarget(msgr); - transparentindex->SetTarget(msgr); - usetransparentcolor->SetTarget(msgr); - transparentred->SetTarget(msgr); - transparentgreen->SetTarget(msgr); - transparentblue->SetTarget(msgr); - websafe->SetTarget(msgr); - beossystem->SetTarget(msgr); - greyscale->SetTarget(msgr); - optimal->SetTarget(msgr); + fInterlacedCB->SetTarget(msgr); + fUseDitheringCB->SetTarget(msgr); + fUseTransparentCB->SetTarget(msgr); + fUseTransparentIndexRB->SetTarget(msgr); + fTransparentIndexTC->SetTarget(msgr); + fUseTransparentColorRB->SetTarget(msgr); + fTransparentRedTC->SetTarget(msgr); + fTransparentGreenTC->SetTarget(msgr); + fTransparentBlueTC->SetTarget(msgr); + fPaletteM->SetTargetForItems(msgr); + fColorCountM->SetTargetForItems(msgr); } -void GIFView::MessageReceived(BMessage *message) { +// MessageReceived +void +GIFView::MessageReceived(BMessage *message) +{ switch (message->what) { case GV_WEB_SAFE: - prefs->palettemode = WEB_SAFE_PALETTE; - usedithering->SetEnabled(true); + fPrefs->palettemode = WEB_SAFE_PALETTE; + fUseDitheringCB->SetEnabled(true); + fColorCountMF->SetEnabled(false); + fColorCount256MI->SetMarked(true); break; case GV_BEOS_SYSTEM: - prefs->palettemode = BEOS_SYSTEM_PALETTE; - usedithering->SetEnabled(true); + fPrefs->palettemode = BEOS_SYSTEM_PALETTE; + fUseDitheringCB->SetEnabled(true); + fColorCountMF->SetEnabled(false); + fColorCount256MI->SetMarked(true); break; case GV_GREYSCALE: - prefs->palettemode = GREYSCALE_PALETTE; - usedithering->SetEnabled(false); - usedithering->SetValue(false); - prefs->usedithering = false; + fPrefs->palettemode = GREYSCALE_PALETTE; + fUseDitheringCB->SetEnabled(false); + fUseDitheringCB->SetValue(false); + fColorCountMF->SetEnabled(false); + fColorCount256MI->SetMarked(true); + fPrefs->usedithering = false; break; case GV_OPTIMAL: - prefs->palettemode = OPTIMAL_PALETTE; - usedithering->SetEnabled(true); + fPrefs->palettemode = OPTIMAL_PALETTE; + 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; case GV_INTERLACED: - prefs->interlaced = interlaced->Value(); + fPrefs->interlaced = fInterlacedCB->Value(); break; case GV_USE_DITHERING: - prefs->usedithering = usedithering->Value(); + fPrefs->usedithering = fUseDitheringCB->Value(); break; case GV_USE_TRANSPARENT: - prefs->usetransparent = usetransparent->Value(); - if (prefs->usetransparent) { - usetransparentindex->SetEnabled(true); - usetransparentcolor->SetEnabled(true); - transparentindex->SetEnabled(usetransparentindex->Value()); - transparentred->SetEnabled(usetransparentcolor->Value()); - transparentgreen->SetEnabled(usetransparentcolor->Value()); - transparentblue->SetEnabled(usetransparentcolor->Value()); + fPrefs->usetransparent = fUseTransparentCB->Value(); + if (fPrefs->usetransparent) { + fUseTransparentIndexRB->SetEnabled(true); + fUseTransparentColorRB->SetEnabled(true); + fTransparentIndexTC->SetEnabled(fUseTransparentIndexRB->Value()); + fTransparentRedTC->SetEnabled(fUseTransparentColorRB->Value()); + fTransparentGreenTC->SetEnabled(fUseTransparentColorRB->Value()); + fTransparentBlueTC->SetEnabled(fUseTransparentColorRB->Value()); } else { - usetransparentindex->SetEnabled(false); - usetransparentcolor->SetEnabled(false); - transparentindex->SetEnabled(false); - transparentred->SetEnabled(false); - transparentgreen->SetEnabled(false); - transparentblue->SetEnabled(false); + fUseTransparentIndexRB->SetEnabled(false); + fUseTransparentColorRB->SetEnabled(false); + fTransparentIndexTC->SetEnabled(false); + fTransparentRedTC->SetEnabled(false); + fTransparentGreenTC->SetEnabled(false); + fTransparentBlueTC->SetEnabled(false); } break; case GV_USE_TRANSPARENT_INDEX: - prefs->usetransparentindex = true; - transparentindex->SetEnabled(true); - transparentred->SetEnabled(false); - transparentgreen->SetEnabled(false); - transparentblue->SetEnabled(false); + fPrefs->usetransparentindex = true; + fTransparentIndexTC->SetEnabled(true); + fTransparentRedTC->SetEnabled(false); + fTransparentGreenTC->SetEnabled(false); + fTransparentBlueTC->SetEnabled(false); break; case GV_TRANSPARENT_INDEX: - prefs->transparentindex = CheckInput(transparentindex); + fPrefs->transparentindex = CheckInput(fTransparentIndexTC); break; case GV_USE_TRANSPARENT_COLOR: - prefs->usetransparentindex = false; - transparentindex->SetEnabled(false); - transparentred->SetEnabled(true); - transparentgreen->SetEnabled(true); - transparentblue->SetEnabled(true); + fPrefs->usetransparentindex = false; + fTransparentIndexTC->SetEnabled(false); + fTransparentRedTC->SetEnabled(true); + fTransparentGreenTC->SetEnabled(true); + fTransparentBlueTC->SetEnabled(true); break; case GV_TRANSPARENT_RED: - prefs->transparentred = CheckInput(transparentred); + fPrefs->transparentred = CheckInput(fTransparentRedTC); break; case GV_TRANSPARENT_GREEN: - prefs->transparentgreen = CheckInput(transparentgreen); + fPrefs->transparentgreen = CheckInput(fTransparentGreenTC); break; case GV_TRANSPARENT_BLUE: - prefs->transparentblue = CheckInput(transparentblue); + fPrefs->transparentblue = CheckInput(fTransparentBlueTC); break; default: BView::MessageReceived(message); break; } - prefs->Save(); + fPrefs->Save(); } int GIFView::CheckInput(BTextControl *control) { @@ -320,7 +407,3 @@ int GIFView::CheckInput(BTextControl *control) { return value; } -GIFView::~GIFView() { - delete prefs; -} - diff --git a/src/add-ons/translators/giftranslator/GIFView.h b/src/add-ons/translators/giftranslator/GIFView.h index 38cce8b158..404752d5bc 100644 --- a/src/add-ons/translators/giftranslator/GIFView.h +++ b/src/add-ons/translators/giftranslator/GIFView.h @@ -13,10 +13,13 @@ // //////////////////////////////////////////////////////////////////////////////// +// Additional authors: Stephan Aßmus, + #ifndef GIFVIEW_H #define GIFVIEW_H #include + class BMenuField; class BPopUpMenu; class BMenuItem; @@ -38,26 +41,45 @@ class Prefs; #define GV_TRANSPARENT_RED 'gvtr' #define GV_TRANSPARENT_GREEN 'gvtg' #define GV_TRANSPARENT_BLUE 'gvtb' +#define GV_SET_COLOR_COUNT 'gvcc' class GIFView : public BView { - public: - GIFView(BRect rect, const char *name); - ~GIFView(); - void MessageReceived(BMessage *message); - void AllAttached(); + public: + GIFView(BRect rect, const char* name); + virtual ~GIFView(); + + virtual void MessageReceived(BMessage* message); + virtual void AllAttached(); - Prefs *prefs; - BMenuField *palettemenufield; - BPopUpMenu *palettepopupmenu; - BMenuItem *websafe, *beossystem, *greyscale, *optimal; - BCheckBox *interlaced, *usetransparent, *usedithering; - BRadioButton *usetransparentindex, *usetransparentcolor; - BTextControl *transparentindex, *transparentred, - *transparentgreen, *transparentblue; - - private: - void RestorePrefs(); - int CheckInput(BTextControl *control); + private: + void RestorePrefs(); + 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 diff --git a/src/add-ons/translators/giftranslator/Prefs.cpp b/src/add-ons/translators/giftranslator/Prefs.cpp index 3da553e391..1142d41038 100644 --- a/src/add-ons/translators/giftranslator/Prefs.cpp +++ b/src/add-ons/translators/giftranslator/Prefs.cpp @@ -13,6 +13,8 @@ // //////////////////////////////////////////////////////////////////////////////// +// Additional authors: Stephan Aßmus, + #include "Prefs.h" #include #include @@ -26,7 +28,8 @@ Prefs::Prefs() { usedithering = true; transparentindex = transparentred = transparentgreen = transparentblue = palettemode = 0; - + palette_size_in_bits = 8; + BPath path; find_directory(B_USER_SETTINGS_DIRECTORY, &path); path.Append("GIFTranslator_settings"); @@ -47,6 +50,8 @@ Prefs::Prefs() { if (!GetBool("usedithering", &usedithering, &db)) return; int di = 0; if (!GetInt("palettemode", &palettemode, &di)) return; + di = 8; + if (!GetInt("palettesize", &palette_size_in_bits, &di)) return; di = 0; if (!GetInt("transparentindex", &transparentindex, &di)) return; di = 0; @@ -111,6 +116,7 @@ void Prefs::Save() { if (!PutBool("usetransparentindex", &usetransparentindex)) return; if (!PutBool("usedithering", &usedithering)) return; if (!PutInt("palettemode", &palettemode)) return; + if (!PutInt("palettesize", &palette_size_in_bits)) return; if (!PutInt("transparentindex", &transparentindex)) return; if (!PutInt("transparentred", &transparentred)) return; if (!PutInt("transparentgreen", &transparentgreen)) return; diff --git a/src/add-ons/translators/giftranslator/Prefs.h b/src/add-ons/translators/giftranslator/Prefs.h index dd3c046428..7a1e357ca5 100644 --- a/src/add-ons/translators/giftranslator/Prefs.h +++ b/src/add-ons/translators/giftranslator/Prefs.h @@ -13,6 +13,8 @@ // //////////////////////////////////////////////////////////////////////////////// +// Additional authors: Stephan Aßmus, + #ifndef PREFS_H #define PREFS_H @@ -26,7 +28,7 @@ class Prefs { bool interlaced, usetransparent, usetransparentindex, usedithering; int transparentindex, transparentred, transparentgreen, - transparentblue, palettemode; + transparentblue, palettemode, palette_size_in_bits; private: bool GetInt(char *name, int *value, int *defaultvalue); bool GetBool(char *name, bool *value, bool *defaultvalue); diff --git a/src/add-ons/translators/giftranslator/SFHash.cpp b/src/add-ons/translators/giftranslator/SFHash.cpp index 0fb418cdb4..005c156f02 100644 --- a/src/add-ons/translators/giftranslator/SFHash.cpp +++ b/src/add-ons/translators/giftranslator/SFHash.cpp @@ -13,6 +13,8 @@ // //////////////////////////////////////////////////////////////////////////////// +// Additional authors: Stephan Aßmus, + #include "SFHash.h" #include #include @@ -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; HashItem *item = main_array[pos]; @@ -57,7 +61,9 @@ HashItem *SFHash::GetItem(unsigned int key) { return NULL; } -unsigned int SFHash::CountItems() { +unsigned int +SFHash::CountItems() +{ unsigned int count = 0; for (int x = 0; x < this->size; x++) { HashItem *item = main_array[x]; @@ -69,7 +75,9 @@ unsigned int SFHash::CountItems() { return count; } -HashItem *SFHash::NextItem() { +HashItem* +SFHash::NextItem() +{ if (iterate_pos >= size) { Rewind(); return NULL; diff --git a/src/add-ons/translators/giftranslator/SFHash.h b/src/add-ons/translators/giftranslator/SFHash.h index 0cfc7770e4..4bd47e9256 100644 --- a/src/add-ons/translators/giftranslator/SFHash.h +++ b/src/add-ons/translators/giftranslator/SFHash.h @@ -13,6 +13,8 @@ // //////////////////////////////////////////////////////////////////////////////// +// Additional authors: Stephan Aßmus, + #ifndef SFHASH_H #define SFHASH_H @@ -26,16 +28,17 @@ class HashItem { class SFHash { public: - SFHash(int size = 4096); - ~SFHash(); - - void AddItem(HashItem *item); - HashItem *GetItem(unsigned int key); - unsigned int CountItems(); - HashItem *NextItem(); - void Rewind(); - + SFHash(int size = 4096); + ~SFHash(); + + void AddItem(HashItem *item); + HashItem* GetItem(unsigned int key); + unsigned int CountItems(); + HashItem* NextItem(); + void Rewind(); + bool fatalerror; + private: int size, iterate_pos, iterate_depth; HashItem **main_array; diff --git a/src/add-ons/translators/giftranslator/SavePalette.cpp b/src/add-ons/translators/giftranslator/SavePalette.cpp index 323063db00..02feb912c1 100644 --- a/src/add-ons/translators/giftranslator/SavePalette.cpp +++ b/src/add-ons/translators/giftranslator/SavePalette.cpp @@ -13,6 +13,10 @@ // //////////////////////////////////////////////////////////////////////////////// +// Additional authors: Stephan Aßmus, + +#include + #include "SavePalette.h" #include #include @@ -21,6 +25,7 @@ extern bool debug; +// "web safe palette" const rgb_color wsp[256] = { {0xff, 0xff, 0xff, 0xff}, {0xff, 0xff, 0xcc, 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} }; -ColorItem::ColorItem(unsigned int k, unsigned int c) { - key = k; - count = c; -} - -SavePalette::SavePalette() { - pal = new rgb_color[256]; - backgroundindex = 0; - usetransparent = false; - transparentindex = 0; - size = size_in_bits = 0; - fatalerror = false; - mode = WEB_SAFE_PALETTE; -} - -SavePalette::SavePalette(int predefined) { - pal = new rgb_color[256]; - backgroundindex = 0; - usetransparent = false; - transparentindex = 0; - fatalerror = false; - - mode = predefined; - size_in_bits = 8; - - if (predefined == WEB_SAFE_PALETTE) { - memcpy(pal, wsp, sizeof(rgb_color) * 256); - size = 216; - } else if (predefined == BEOS_SYSTEM_PALETTE) { - color_map *map = (color_map *)system_colors(); - memcpy(pal, map->color_list, sizeof(rgb_color) * 256); - size = 256; - } else if (predefined == GREYSCALE_PALETTE) { - for (int x = 0; x < 256; x++) { - pal[x].red = pal[x].green = pal[x].blue = x; - pal[x].alpha = 0xff; +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; + } + unsigned int count; + uint8 red; + uint8 green; + uint8 blue; +}; + +// constructor +SavePalette::SavePalette(int mode) + : pal(new(nothrow) rgb_color[256]), + fSize(0), + fSizeInBits(8), + fMode(mode), + fUseTransparent(false), + fTransparentIndex(0), + fBackgroundIndex(0), + fFatalError(pal == NULL) +{ + if (IsValid()) { + if (fMode == WEB_SAFE_PALETTE) { + memcpy(pal, wsp, sizeof(rgb_color) * 256); + fSize = 216; + } else if (fMode == BEOS_SYSTEM_PALETTE) { + color_map *map = (color_map *)system_colors(); + memcpy(pal, map->color_list, sizeof(rgb_color) * 256); + fSize = 256; + } else if (fMode == GREYSCALE_PALETTE) { + for (int i = 0; i < 256; i++) { + pal[i].red = pal[i].green = pal[i].blue = i; + pal[i].alpha = 0xff; + } + fSize = 256; } - size = 256; } } -SavePalette::SavePalette(BBitmap *bitmap) { - pal = new rgb_color[256]; - backgroundindex = 0; - usetransparent = false; - transparentindex = 0; - fatalerror = false; - mode = OPTIMAL_PALETTE; +// make_key +static int +make_key(uint8 r, uint8 g, uint8 b, uint8 bits) +{ + r = r >> (8 - bits); + g = g >> (8 - bits); + 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); if (hash.fatalerror) { if (debug) printf("Out of memory in SavePalette(BBitmap *)\n"); - fatalerror = true; + fFatalError = true; 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(); if (cs != B_RGB32 && cs != B_RGBA32 && cs != B_RGB32_BIG && cs != B_RGBA32_BIG) { 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, (cs & 0xff00) >> 8, cs & 0xff, cs); } - fatalerror = true; + fFatalError = true; return; } - BRect rect = bitmap->Bounds(); - int height = rect.IntegerHeight() + 1; - int width = rect.IntegerWidth() + 1; - unsigned char *bits = (unsigned char *)bitmap->Bits(); + BRect rect = bitmap->Bounds(); + uint32 height = rect.IntegerHeight() + 1; + uint32 width = rect.IntegerWidth() + 1; + uint8* bits = (uint8*)bitmap->Bits(); + uint32 bpr = bitmap->BytesPerRow(); - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - if (cs == B_RGB32 || cs == B_RGBA32) { - b = bits[0]; - g = bits[1]; - r = bits[2]; - } else { - r = bits[1]; - g = bits[2]; - b = bits[3]; - } - bits += 4; - - unsigned int key = (r << 16) + (g << 8) + b; - ColorItem *ci = (ColorItem *)hash.GetItem(key); - if (ci == NULL) { - ci = new ColorItem(key, 1); - if (ci == NULL) { - if (debug) printf("Out of memory in SavePalette(BBitmap *)\n"); - fatalerror = true; + uint8 r, g, b; + uint8 useBits = 3 + maxSizeInBits / 2; + if (cs == B_RGB32 || cs == B_RGBA32) { + for (uint32 y = 0; y < height; y++) { + uint8* handle = bits; + for (uint32 x = 0; x < width; x++) { + b = handle[0]; + g = handle[1]; + r = handle[2]; + 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; - } - 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(); - size_in_bits = 1; - while (((1 << size_in_bits) < unique_colors) && (size_in_bits < 8)) size_in_bits++; - size = 1 << size_in_bits; + while (((1 << fSizeInBits) < unique_colors) && (fSizeInBits < maxSizeInBits)) + fSizeInBits++; + fSize = 1 << fSizeInBits; - ColorItem **topcolors = (ColorItem **)malloc(size * 4); + ColorItem **topcolors = (ColorItem **)malloc(fSize * 4); if (topcolors == NULL) { if (debug) printf("Out of memory in SavePalette(BBitmap *)\n"); - fatalerror = true; + fFatalError = true; return; } - ColorItem *dummy = new ColorItem(0, 0); - for (int x = 0; x < size; x++) topcolors[x] = dummy; + ColorItem *dummy = new ColorItem(0, 0, 0, 0, 0); + 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(); - for (int y = 0; y < size; y++) { - if (ci->count > topcolors[y]->count) { - for (int z = size - 1; z > y; z--) { - topcolors[z] = topcolors[z-1]; + for (int j = 0; j < fSize; j++) { + if (ci->count > topcolors[j]->count) { + for (int k = fSize - 1; k > j; k--) { + topcolors[k] = topcolors[k - 1]; } - topcolors[y] = ci; + topcolors[j] = ci; break; } } } - for (int x = 0; x < size; x++) { - pal[x].red = topcolors[x]->key >> 16; - pal[x].green = (topcolors[x]->key & 0xff00) >> 8; - pal[x].blue = topcolors[x]->key & 0xff; - pal[x].alpha = 0xff; + for (int i = 0; i < fSize; i++) { + pal[i].red = topcolors[i]->red; + pal[i].green = topcolors[i]->green; + pal[i].blue = topcolors[i]->blue; + pal[i].alpha = 0xff; } delete dummy; free(topcolors); } -/* Standard mapping services once a palette is loaded */ -unsigned char SavePalette::IndexForColor(unsigned char red, unsigned char green, - unsigned char blue) { +// destructor +SavePalette::~SavePalette() +{ + 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; - 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; + 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 best; + return index; } -unsigned char SavePalette::IndexForColor(rgb_color color) { - return IndexForColor(color.red, color.green, color.blue); +// SetUseTransparent +void +SavePalette::SetUseTransparent(bool use) +{ + fUseTransparent = use; } -SavePalette::~SavePalette() { - delete [] pal; +// 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); +} diff --git a/src/add-ons/translators/giftranslator/SavePalette.h b/src/add-ons/translators/giftranslator/SavePalette.h index d8200cfe49..2420e55005 100644 --- a/src/add-ons/translators/giftranslator/SavePalette.h +++ b/src/add-ons/translators/giftranslator/SavePalette.h @@ -27,34 +27,58 @@ enum { 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 { public: - SavePalette(int predefined); - SavePalette(BBitmap *bitmap); - SavePalette(); - ~SavePalette(); + SavePalette(int mode); + SavePalette(BBitmap *bitmap, + int32 maxSizeInBits = 8); + virtual ~SavePalette(); - unsigned char IndexForColor(unsigned char red, unsigned char green, - unsigned char blue); - unsigned char IndexForColor(rgb_color color); + inline bool IsValid() const + { return !fFatalError; } - rgb_color *pal; - int size, size_in_bits, mode; - bool usetransparent; - int backgroundindex, transparentindex; - bool fatalerror; + 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; + + private: + int fSize; + 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 +