a couple of fixes for determining transparent pixels with regard to dithering, new auto transparency mode (from alpha channel) replaces nonsense index mode (the index mode is nonsense, because there is no control over which color gets which index, therefor, the user is better of specifying the specific color, which is supported)

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@14334 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2005-10-06 23:22:41 +00:00
parent ece4feca93
commit 994ae14bb5
7 changed files with 201 additions and 119 deletions
@@ -97,10 +97,9 @@ GIFSave::GIFSave(BBitmap *bitmap, BPositionIO *output)
}
}
palette->SetUseTransparent(prefs->usetransparent);
if (prefs->usetransparent) {
if (prefs->usetransparentindex) {
palette->SetTransparentIndex(prefs->transparentindex);
if (prefs->usetransparentauto) {
palette->PrepareForAutoTransparency();
if (debug)
printf("GIFSave::GIFSave() - Using transparent index %d\n", palette->TransparentIndex());
} else {
@@ -329,27 +328,36 @@ GIFSave::NextPixel(int pixel)
{
int bpr = bitmap->BytesPerRow();
color_space cs = bitmap->ColorSpace();
unsigned char r, g, b;
bool useAlphaForTransparency = prefs->usetransparentauto && cs == B_RGBA32 || cs == B_RGBA32_BIG;
unsigned char r, g, b, a;
if (cs == B_RGB32 || cs == B_RGBA32) {
b = gifbits[0];
g = gifbits[1];
r = gifbits[2];
a = gifbits[3];
} else {
a = gifbits[0];
r = gifbits[1];
g = gifbits[2];
b = gifbits[3];
}
gifbits += 4;
pos += 4;
if (!prefs->usetransparent || prefs->usetransparentauto ||
r != prefs->transparentred ||
g != prefs->transparentgreen ||
b != prefs->transparentblue) {
if (prefs->usedithering) {
if (pixel % width == 0) {
red_side_error = green_side_error = blue_side_error = 0;
if (prefs->usedithering) {
if (pixel % width == 0) {
red_side_error = green_side_error = blue_side_error = 0;
}
b = min_c(255, max_c(0, b - blue_side_error));
g = min_c(255, max_c(0, g - green_side_error));
r = min_c(255, max_c(0, r - red_side_error));
}
b = min_c(255, max_c(0, b - blue_side_error));
g = min_c(255, max_c(0, g - green_side_error));
r = min_c(255, max_c(0, r - red_side_error));
}
if (prefs->interlaced) {
@@ -363,7 +371,7 @@ GIFSave::NextPixel(int pixel)
gifbits = (unsigned char *)bitmap->Bits() + (bpr * row);
}
}
/*
unsigned int key = (r << 16) + (g << 8) + b;
ColorCache *cc = (ColorCache *)hash->GetItem(key);
if (cc == NULL) {
@@ -406,7 +414,44 @@ GIFSave::NextPixel(int pixel)
blue_error[x + 1] = (blue_total_error * one_sixteenth);
}
return cc->index;
return cc->index;*/
int index = palette->IndexForColor(r, g, b, useAlphaForTransparency ? a : 255);
if (index != palette->TransparentIndex() && prefs->usedithering) {
int x = pixel % width;
// Don't carry error on to next line when interlaced because
// that line won't be adjacent, hence error is meaningless
if (prefs->interlaced && x == width - 1) {
for (int32 y = -1; y < width + 1; y++) {
red_error[y] = 0;
green_error[y] = 0;
blue_error[y] = 0;
}
}
int32 red_total_error = palette->pal[index].red - r;
int32 green_total_error = palette->pal[index].green - g;
int32 blue_total_error = palette->pal[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;
green_side_error = (green_error[x + 1] + (green_total_error * seven_sixteenth)) >> 15;
red_error[x - 1] += (red_total_error * three_sixteenth);
green_error[x - 1] += (green_total_error * three_sixteenth);
blue_error[x - 1] += (blue_total_error * three_sixteenth);
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);
}
return index;
}
// InitFrame
@@ -131,23 +131,16 @@ GIFView::GIFView(BRect rect, const char *name)
// radio buttons
r.top = fUseTransparentCB->Frame().bottom + 2;
r.bottom = r.top + 10;
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(fUseTransparentIndexRB);
r.right = r.left + be_plain_font->StringWidth("Automatic (from alpha channel)") + 20;
fUseTransparentAutoRB = new BRadioButton(r, "UseTransparentAuto", "Automatic (from alpha channel)",
new BMessage(GV_USE_TRANSPARENT_AUTO));
AddChild(fUseTransparentAutoRB);
r.left = r.right + 1;
r.right = r.left + 30;
fTransparentIndexTC = new BTextControl(r, "TransparentIndex", "", "0",
new BMessage(GV_TRANSPARENT_INDEX));
AddChild(fTransparentIndexTC);
fTransparentIndexTC->SetDivider(0);
r.top = fUseTransparentIndexRB->Frame().bottom + 0;
r.top = fUseTransparentAutoRB->Frame().bottom + 0;
r.bottom = r.top + 10;
r.left = 10;
r.right = r.left + be_plain_font->StringWidth("Use rgb color") + 20;
fUseTransparentColorRB = 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(fUseTransparentColorRB);
@@ -172,24 +165,12 @@ GIFView::GIFView(BRect rect, const char *name)
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') {
ti->DisallowChar(x);
tr->DisallowChar(x);
tg->DisallowChar(x);
tb->DisallowChar(x);
@@ -251,27 +232,23 @@ GIFView::RestorePrefs()
if (fGreyScaleMI->IsMarked()) fUseDitheringCB->SetValue(false);
else fUseDitheringCB->SetValue(fPrefs->usedithering);
fUseTransparentCB->SetValue(fPrefs->usetransparent);
fUseTransparentIndexRB->SetValue(fPrefs->usetransparentindex);
fUseTransparentColorRB->SetValue(!fPrefs->usetransparentindex);
fUseTransparentAutoRB->SetValue(fPrefs->usetransparentauto);
fUseTransparentColorRB->SetValue(!fPrefs->usetransparentauto);
if (fPrefs->usetransparent) {
fUseTransparentIndexRB->SetEnabled(true);
fUseTransparentAutoRB->SetEnabled(true);
fUseTransparentColorRB->SetEnabled(true);
fTransparentIndexTC->SetEnabled(fPrefs->usetransparentindex);
fTransparentRedTC->SetEnabled(!fPrefs->usetransparentindex);
fTransparentGreenTC->SetEnabled(!fPrefs->usetransparentindex);
fTransparentBlueTC->SetEnabled(!fPrefs->usetransparentindex);
fTransparentRedTC->SetEnabled(!fPrefs->usetransparentauto);
fTransparentGreenTC->SetEnabled(!fPrefs->usetransparentauto);
fTransparentBlueTC->SetEnabled(!fPrefs->usetransparentauto);
} else {
fUseTransparentIndexRB->SetEnabled(false);
fUseTransparentAutoRB->SetEnabled(false);
fUseTransparentColorRB->SetEnabled(false);
fTransparentIndexTC->SetEnabled(false);
fTransparentRedTC->SetEnabled(false);
fTransparentGreenTC->SetEnabled(false);
fTransparentBlueTC->SetEnabled(false);
}
char temp[4];
sprintf(temp, "%d", fPrefs->transparentindex);
fTransparentIndexTC->SetText(temp);
sprintf(temp, "%d", fPrefs->transparentred);
fTransparentRedTC->SetText(temp);
sprintf(temp, "%d", fPrefs->transparentgreen);
@@ -289,8 +266,7 @@ GIFView::AllAttached()
fInterlacedCB->SetTarget(msgr);
fUseDitheringCB->SetTarget(msgr);
fUseTransparentCB->SetTarget(msgr);
fUseTransparentIndexRB->SetTarget(msgr);
fTransparentIndexTC->SetTarget(msgr);
fUseTransparentAutoRB->SetTarget(msgr);
fUseTransparentColorRB->SetTarget(msgr);
fTransparentRedTC->SetTarget(msgr);
fTransparentGreenTC->SetTarget(msgr);
@@ -348,34 +324,27 @@ GIFView::MessageReceived(BMessage *message)
case GV_USE_TRANSPARENT:
fPrefs->usetransparent = fUseTransparentCB->Value();
if (fPrefs->usetransparent) {
fUseTransparentIndexRB->SetEnabled(true);
fUseTransparentAutoRB->SetEnabled(true);
fUseTransparentColorRB->SetEnabled(true);
fTransparentIndexTC->SetEnabled(fUseTransparentIndexRB->Value());
fTransparentRedTC->SetEnabled(fUseTransparentColorRB->Value());
fTransparentGreenTC->SetEnabled(fUseTransparentColorRB->Value());
fTransparentBlueTC->SetEnabled(fUseTransparentColorRB->Value());
} else {
fUseTransparentIndexRB->SetEnabled(false);
fUseTransparentAutoRB->SetEnabled(false);
fUseTransparentColorRB->SetEnabled(false);
fTransparentIndexTC->SetEnabled(false);
fTransparentRedTC->SetEnabled(false);
fTransparentGreenTC->SetEnabled(false);
fTransparentBlueTC->SetEnabled(false);
}
break;
case GV_USE_TRANSPARENT_INDEX:
fPrefs->usetransparentindex = true;
fTransparentIndexTC->SetEnabled(true);
case GV_USE_TRANSPARENT_AUTO:
fPrefs->usetransparentauto = true;
fTransparentRedTC->SetEnabled(false);
fTransparentGreenTC->SetEnabled(false);
fTransparentBlueTC->SetEnabled(false);
break;
case GV_TRANSPARENT_INDEX:
fPrefs->transparentindex = CheckInput(fTransparentIndexTC);
break;
case GV_USE_TRANSPARENT_COLOR:
fPrefs->usetransparentindex = false;
fTransparentIndexTC->SetEnabled(false);
fPrefs->usetransparentauto = false;
fTransparentRedTC->SetEnabled(true);
fTransparentGreenTC->SetEnabled(true);
fTransparentBlueTC->SetEnabled(true);
@@ -35,8 +35,7 @@ class Prefs;
#define GV_INTERLACED 'gvin'
#define GV_USE_DITHERING 'gvud'
#define GV_USE_TRANSPARENT 'gvut'
#define GV_USE_TRANSPARENT_INDEX 'gvui'
#define GV_TRANSPARENT_INDEX 'gvti'
#define GV_USE_TRANSPARENT_AUTO 'gvua'
#define GV_USE_TRANSPARENT_COLOR 'gvuc'
#define GV_TRANSPARENT_RED 'gvtr'
#define GV_TRANSPARENT_GREEN 'gvtg'
@@ -73,10 +72,9 @@ class GIFView : public BView {
BCheckBox* fUseTransparentCB;
BCheckBox* fUseDitheringCB;
BRadioButton* fUseTransparentIndexRB;
BRadioButton* fUseTransparentAutoRB;
BRadioButton* fUseTransparentColorRB;
BTextControl* fTransparentIndexTC;
BTextControl* fTransparentRedTC;
BTextControl* fTransparentGreenTC;
BTextControl* fTransparentBlueTC;
+41 -21
View File
@@ -23,13 +23,19 @@
extern bool debug;
Prefs::Prefs() {
interlaced = usetransparent = usetransparentindex = false;
usedithering = true;
transparentindex = transparentred = transparentgreen =
transparentblue = palettemode = 0;
palette_size_in_bits = 8;
// constructor
Prefs::Prefs()
: interlaced(false),
usetransparent(false),
usetransparentauto(false),
usedithering(false),
transparentred(0),
transparentgreen(0),
transparentblue(0),
palettemode(0),
palette_size_in_bits(8),
file(NULL)
{
BPath path;
find_directory(B_USER_SETTINGS_DIRECTORY, &path);
path.Append("GIFTranslator_settings");
@@ -45,7 +51,7 @@ Prefs::Prefs() {
db = false;
if (!GetBool("usetransparent", &usetransparent, &db)) return;
db = false;
if (!GetBool("usetransparentindex", &usetransparentindex, &db)) return;
if (!GetBool("usetransparentauto", &usetransparentauto, &db)) return;
db = true;
if (!GetBool("usedithering", &usedithering, &db)) return;
int di = 0;
@@ -53,8 +59,6 @@ Prefs::Prefs() {
di = 8;
if (!GetInt("palettesize", &palette_size_in_bits, &di)) return;
di = 0;
if (!GetInt("transparentindex", &transparentindex, &di)) return;
di = 0;
if (!GetInt("transparentred", &transparentred, &di)) return;
di = 0;
if (!GetInt("transparentgreen", &transparentgreen, &di)) return;
@@ -62,7 +66,16 @@ Prefs::Prefs() {
if (!GetInt("transparentblue", &transparentblue, &di)) return;
}
bool Prefs::GetInt(char *name, int *value, int *defaultvalue) {
// destructor
Prefs::~Prefs()
{
delete file;
}
// GetInt
bool
Prefs::GetInt(char *name, int *value, int *defaultvalue)
{
status_t err = file->ReadAttr(name, B_INT32_TYPE, 0, value, 4);
if (err == B_ENTRY_NOT_FOUND) {
*value = *defaultvalue;
@@ -77,7 +90,10 @@ bool Prefs::GetInt(char *name, int *value, int *defaultvalue) {
return true;
}
bool Prefs::GetBool(char *name, bool *value, bool *defaultvalue) {
// GetBool
bool
Prefs::GetBool(char *name, bool *value, bool *defaultvalue)
{
status_t err = file->ReadAttr(name, B_BOOL_TYPE, 0, value, 1);
if (err == B_ENTRY_NOT_FOUND) {
*value = *defaultvalue;
@@ -92,7 +108,10 @@ bool Prefs::GetBool(char *name, bool *value, bool *defaultvalue) {
return true;
}
bool Prefs::PutInt(char *name, int *value) {
// PutInt
bool
Prefs::PutInt(char *name, int *value)
{
status_t err = file->WriteAttr(name, B_INT32_TYPE, 0, value, 4);
if (err < 0) {
if (debug) printf("WriteAttr on %s died\n", name);
@@ -101,7 +120,10 @@ bool Prefs::PutInt(char *name, int *value) {
return true;
}
bool Prefs::PutBool(char *name, bool *value) {
// PutBool
bool
Prefs::PutBool(char *name, bool *value)
{
status_t err = file->WriteAttr(name, B_BOOL_TYPE, 0, value, 1);
if (err < 0) {
if (debug) printf("WriteAttr on %s died\n", name);
@@ -110,20 +132,18 @@ bool Prefs::PutBool(char *name, bool *value) {
return true;
}
void Prefs::Save() {
// Save
void
Prefs::Save()
{
if (!PutBool("interlaced", &interlaced)) return;
if (!PutBool("usetransparent", &usetransparent)) return;
if (!PutBool("usetransparentindex", &usetransparentindex)) return;
if (!PutBool("usetransparentauto", &usetransparentauto)) 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;
if (!PutInt("transparentblue", &transparentblue)) return;
}
Prefs::~Prefs() {
delete file;
}
@@ -25,9 +25,9 @@ class Prefs {
Prefs();
void Save();
~Prefs();
bool interlaced, usetransparent, usetransparentindex,
bool interlaced, usetransparent, usetransparentauto,
usedithering;
int transparentindex, transparentred, transparentgreen,
int transparentred, transparentgreen,
transparentblue, palettemode, palette_size_in_bits;
private:
bool GetInt(char *name, int *value, int *defaultvalue);
@@ -180,8 +180,8 @@ SavePalette::SavePalette(int mode)
fSize(0),
fSizeInBits(8),
fMode(mode),
fUseTransparent(false),
fTransparentIndex(0),
fTransparentMode(NO_TRANSPARENCY),
fTransparentIndex(-1),
fBackgroundIndex(0),
fFatalError(pal == NULL)
{
@@ -242,8 +242,8 @@ SavePalette::SavePalette(BBitmap *bitmap, int32 maxSizeInBits)
fSize(0),
fSizeInBits(0),
fMode(OPTIMAL_PALETTE),
fUseTransparent(false),
fTransparentIndex(0),
fTransparentMode(fTransparentMode),
fTransparentIndex(-1),
fBackgroundIndex(0),
fFatalError(pal == NULL)
{
@@ -366,49 +366,93 @@ SavePalette::~SavePalette()
//
// standard mapping services once a palette is loaded
uint8
SavePalette::IndexForColor(uint8 red, uint8 green, uint8 blue)
SavePalette::IndexForColor(uint8 red, uint8 green, uint8 blue, uint8 alpha)
{
if (fTransparentMode > NO_TRANSPARENCY && alpha < 128)
return fTransparentIndex;
uint8 index = 0;
if (fMode == GREYSCALE_PALETTE) {
index = (308 * red + 600 * green + 116 * blue) / 1024;
// avoid transparent index
if (fTransparentMode == AUTO_TRANSPARENCY && index == 1 && fTransparentIndex == 1)
index = 0;
} 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;
if (fTransparentMode == AUTO_TRANSPARENCY) {
for (int i = 0; i < fTransparentIndex && 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;
}
}
for (int i = fTransparentIndex + 1; 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;
}
}
} else {
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)
SavePalette::PrepareForAutoTransparency()
{
fTransparentIndex = max_c(fSize - 1, index);
fTransparentMode = AUTO_TRANSPARENCY;
// TODO: in the SavePalette::SavePalette(BBitmap*),
// we don't use more colors than necessary, however,
// here we take a slot away for transparency, even if
// we might still have used less colors than the user
// wanted as a maximum
// NOTE: the last index
switch (fMode) {
case WEB_SAFE_PALETTE:
fTransparentIndex = 216;
fSize = 217;
break;
case BEOS_SYSTEM_PALETTE:
fTransparentIndex = 0;
break;
case GREYSCALE_PALETTE:
fTransparentIndex = 1;
break;
case OPTIMAL_PALETTE:
fTransparentIndex = fSize - 1;
break;
}
}
// SetTransparentColor
void
SavePalette::SetTransparentColor(uint8 red, uint8 green, uint8 blue)
{
bool found = false;
fTransparentMode = COLOR_KEY_TRANSPARENCY;
bool found = false;
// try direct hit first
for (int i = 0; i < fSize; i++) {
if (pal[i].red == red &&
@@ -27,6 +27,12 @@ enum {
OPTIMAL_PALETTE
};
enum {
NO_TRANSPARENCY = 0,
AUTO_TRANSPARENCY,
COLOR_KEY_TRANSPARENCY
};
class SavePalette {
public:
SavePalette(int mode);
@@ -37,14 +43,14 @@ class SavePalette {
inline bool IsValid() const
{ return !fFatalError; }
uint8 IndexForColor(uint8 red, uint8 green, uint8 blue);
uint8 IndexForColor(uint8 red, uint8 green,
uint8 blue, uint8 alpha = 255);
inline uint8 IndexForColor(const rgb_color& color);
void SetUseTransparent(bool use);
inline bool UseTransparent() const
{ return fUseTransparent; }
{ return fTransparentMode > NO_TRANSPARENCY; }
void SetTransparentIndex(int index);
void PrepareForAutoTransparency();
inline int TransparentIndex() const
{ return fTransparentIndex; }
void SetTransparentColor(uint8 red,
@@ -65,7 +71,7 @@ class SavePalette {
int fSize;
int fSizeInBits;
int fMode;
bool fUseTransparent;
uint32 fTransparentMode;
int fTransparentIndex;
int fBackgroundIndex;
bool fFatalError;
@@ -75,7 +81,7 @@ class SavePalette {
inline uint8
SavePalette::IndexForColor(const rgb_color& color)
{
return IndexForColor(color.red, color.green, color.blue);
return IndexForColor(color.red, color.green, color.blue, color.alpha);
}