diff --git a/src/add-ons/translators/giftranslator/GIFLoad.cpp b/src/add-ons/translators/giftranslator/GIFLoad.cpp new file mode 100644 index 0000000000..038613a196 --- /dev/null +++ b/src/add-ons/translators/giftranslator/GIFLoad.cpp @@ -0,0 +1,435 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// File: GIFLoad.cpp +// +// Date: December 1999 +// +// Author: Daniel Switkin +// +// Copyright 2003 (c) by Daniel Switkin. This file is made publically available +// under the BSD license, with the stipulations that this complete header must +// remain at the top of the file indefinitely, and credit must be given to the +// original author in any about box using this software. +// +//////////////////////////////////////////////////////////////////////////////// + +#include "GIFLoad.h" +#include +#include +#include +#include +#include + +extern bool debug; + +GIFLoad::GIFLoad(BPositionIO *input, BPositionIO *output) { + this->input = input; + this->output = output; + Init(); + + if (!ReadGIFHeader()) { + fatalerror = true; + return; + } + + if (debug) printf("GIFLoad::GIFLoad() - Image dimensions are %d x %d\n", width, height); + + unsigned char c; + if (input->Read(&c, 1) < 1) { + fatalerror = true; + return; + } + while (c != 0x3b) { + if (c == 0x2c) { + if ((!ReadGIFImageHeader()) || (!ReadGIFImageData())) { + if (debug) printf("GIFLoad::GIFLoad() - A fatal error occurred\n"); + fatalerror = true; + } else { + if (debug) printf("GIFLoad::GIFLoad() - Found a single image and leaving\n"); + } + if (scanline != NULL) free(scanline); + return; + } else if (c == 0x21) { + unsigned char d; + if (input->Read(&d, 1) < 1) { + fatalerror = true; + return; + } + if (d == 0xff) { + if (!ReadGIFLoopBlock()) { + fatalerror = true; + return; + } + } else if (d == 0xf9) { + if (!ReadGIFControlBlock()) { + fatalerror = true; + return; + } + } else if (d == 0xfe) { + if (!ReadGIFCommentBlock()) { + fatalerror = true; + return; + } + } else { + if (!ReadGIFUnknownBlock(d)) { + fatalerror = true; + return; + } + } + } else if (c != 0x00) { + if (!ReadGIFUnknownBlock(c)) { + fatalerror = true; + return; + } + } + if (input->Read(&c, 1) < 1) { + fatalerror = true; + return; + } + } + if (debug) printf("GIFLoad::GIFLoad() - Done\n"); +} + +void GIFLoad::Init() { + fatalerror = false; + scanline = NULL; + palette = NULL; + input->Seek(0, SEEK_SET); + head_memblock = NULL; +} + +bool GIFLoad::ReadGIFHeader() { + // Standard header + unsigned char header[13]; + if (input->Read(header, 13) < 13) return false; + width = header[6] + (header[7] << 8); + height = header[8] + (header[9] << 8); + + palette = new LoadPalette(); + // Global palette + if (header[10] & 0x80) { + palette->size_in_bits = (header[10] & 0x07) + 1; + if (debug) printf("GIFLoad::ReadGIFHeader() - Found %d bit global palette\n", palette->size_in_bits); + int s = 1 << palette->size_in_bits; + palette->size = s; + + unsigned char gp[256 * 3]; + if (input->Read(gp, s * 3) < s * 3) return false; + for (int x = 0; x < s; x++) { + palette->SetColor(x, gp[x * 3], gp[x * 3 + 1], gp[x * 3 + 2]); + } + palette->backgroundindex = header[11]; + } else { // Install BeOS system palette in case local palette isn't present + color_map *map = (color_map *)system_colors(); + for (int x = 0; x < 256; x++) { + palette->SetColor(x, map->color_list[x].red, map->color_list[x].green, + map->color_list[x].blue); + } + palette->size = 256; + palette->size_in_bits = 8; + } + return true; +} + +bool GIFLoad::ReadGIFLoopBlock() { + unsigned char length; + if (input->Read(&length, 1) < 1) return false; + input->Seek(length, SEEK_CUR); + + do { + if (input->Read(&length, 1) < 1) { + return false; + } + input->Seek(length, SEEK_CUR); + } while (length != 0); + + return true; +} + +bool GIFLoad::ReadGIFControlBlock() { + unsigned char data[6]; + if (input->Read(data, 6) < 6) return false; + if (data[1] & 0x01) { + palette->usetransparent = true; + palette->transparentindex = data[4]; + if (debug) printf("GIFLoad::ReadGIFControlBlock() - Transparency active, using palette index %d\n", data[4]); + } + return true; +} + +bool GIFLoad::ReadGIFCommentBlock() { + if (debug) printf("GIFLoad::ReadGIFCommentBlock() - Found:\n"); + unsigned char length; + char comment_data[256]; + do { + if (input->Read(&length, 1) < 1) return false; + if (input->Read(comment_data, length) < length) return false; + comment_data[length] = 0x00; + if (debug) printf("%s", comment_data); + } while (length != 0x00); + if (debug) printf("\n"); + return true; +} + +bool GIFLoad::ReadGIFUnknownBlock(unsigned char c) { + if (debug) printf("GIFLoad::ReadGIFUnknownBlock() - Found: %d\n", c); + unsigned char length; + do { + if (input->Read(&length, 1) < 1) return false; + input->Seek(length, SEEK_CUR); + } while (length != 0x00); + return true; +} + +bool GIFLoad::ReadGIFImageHeader() { + unsigned char data[9]; + if (input->Read(data, 9) < 9) return false; + + int local_width = data[4] + (data[5] << 8); + int local_height = data[6] + (data[7] << 8); + if (width != local_width || height != local_height) { + if (debug) printf("GIFLoad::ReadGIFImageHeader() - Local dimensions do not match global, setting to %d x %d\n", + local_width, local_height); + width = local_width; + height = local_height; + } + + scanline = (uint32 *)malloc(width * 4); + if (scanline == NULL) { + if (debug) printf("GIFLoad::ReadGIFImageHeader() - Could not allocate scanline\n"); + return false; + } + + BRect rect(0, 0, width - 1, height - 1); + TranslatorBitmap header; + header.magic = B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP); + header.bounds.left = B_HOST_TO_BENDIAN_FLOAT(rect.left); + header.bounds.top = B_HOST_TO_BENDIAN_FLOAT(rect.top); + header.bounds.right = B_HOST_TO_BENDIAN_FLOAT(rect.right); + header.bounds.bottom = B_HOST_TO_BENDIAN_FLOAT(rect.bottom); + header.rowBytes = B_HOST_TO_BENDIAN_INT32(width * 4); + header.colors = (color_space)B_HOST_TO_BENDIAN_INT32(B_RGBA32); + header.dataSize = B_HOST_TO_BENDIAN_INT32(width * 4 * height); + if (output->Write(&header, 32) < 32) return false; + + // Has local palette + if (data[8] & 0x80) { + palette->size_in_bits = (data[8] & 0x07) + 1; + int s = 1 << palette->size_in_bits; + palette->size = s; + if (debug) printf("GIFLoad::ReadGIFImageHeader() - Found %d bit local palette\n", + palette->size_in_bits); + + unsigned char lp[256 * 3]; + if (input->Read(lp, s * 3) < s * 3) return false; + for (int x = 0; x < s; x++) { + palette->SetColor(x, lp[x * 3], lp[x * 3 + 1], lp[x * 3 + 2]); + } + } + + if (data[8] & 0x40) { + interlaced = true; + if (debug) printf("GIFLoad::ReadGIFImageHeader() - Image is interlaced\n"); + } else { + interlaced = false; + if (debug) printf("GIFLoad::ReadGIFImageHeader() - Image is not interlaced\n"); + } + return true; +} + +bool GIFLoad::ReadGIFImageData() { + unsigned char new_entry[4096]; + + unsigned char cs; + input->Read(&cs, 1); + if (cs == palette->size_in_bits) { + if (!InitFrame(palette->size_in_bits)) return false; + } else if (cs > palette->size_in_bits) { + if (debug) printf("GIFLoad::ReadGIFImageData() - Code_size should be %d, not %d, allowing it\n", code_size, cs); + if (!InitFrame(cs)) return false; + } else if (cs < palette->size_in_bits) { + if (debug) printf("GIFLoad::ReadGIFImageData() - Code_size should be %d, not %d\n", code_size, cs); + return false; + } + + if (debug) printf("GIFLoad::ReadGIFImageData() - Starting LZW\n"); + + while ((new_code = NextCode()) != -1 && new_code != end_code) { + if (new_code == clear_code) { + ResetTable(); + new_code = NextCode(); + old_code[0] = new_code; + old_code_length = 1; + if (!OutputColor(old_code, 1)) goto bad_end; + if (new_code == -1 || new_code == end_code) { + if (debug) printf("GIFLoad::ReadGIFImageData() - Premature end_code or error\n"); + goto bad_end; + } + continue; + } + + // Explicitly check for lack of clear code at start of file + if (old_code_length == 0) { + old_code[0] = new_code; + old_code_length = 1; + if (!OutputColor(old_code, 1)) goto bad_end; + continue; + } + + if (table[new_code] != NULL) { // Does exist in table + if (!OutputColor(table[new_code], entry_size[new_code])) goto bad_end; + + //memcpy(new_entry, old_code, old_code_length); + for (int x = 0; x < old_code_length; x++) { + new_entry[x] = old_code[x]; + } + + //memcpy(new_entry + old_code_length, table[new_code], 1); + new_entry[old_code_length] = *table[new_code]; + } else { // Does not exist in table + //memcpy(new_entry, old_code, old_code_length); + for (int x = 0; x < old_code_length; x++) { + new_entry[x] = old_code[x]; + } + + //memcpy(new_entry + old_code_length, old_code, 1); + new_entry[old_code_length] = *old_code; + + if (!OutputColor(new_entry, old_code_length + 1)) goto bad_end; + } + table[next_code] = MemblockAllocate(old_code_length + 1); + + //memcpy(table[next_code], new_entry, old_code_length + 1); + for (int x = 0; x < old_code_length + 1; x++) { + table[next_code][x] = new_entry[x]; + } + + entry_size[next_code] = old_code_length + 1; + + //memcpy(old_code, table[new_code], entry_size[new_code]); + for (int x = 0; x < entry_size[new_code]; x++) { + old_code[x] = table[new_code][x]; + } + + old_code_length = entry_size[new_code]; + next_code++; + + if (next_code > max_code && BITS != 12) { + BITS++; + max_code = (1 << BITS) - 1; + } + } + + MemblockDeleteAll(); + if (new_code == -1) return false; + if (debug) printf("GIFLoad::ReadGIFImageData() - Done\n"); + return true; + +bad_end: + if (debug) printf("GIFLoad::ReadGIFImageData() - Reached a bad end\n"); + MemblockDeleteAll(); + return false; +} + +short GIFLoad::NextCode() { + while (bit_count < BITS) { + if (byte_count == 0) { + if (input->Read(&byte_count, 1) < 1) return -1; + if (byte_count == 0) return end_code; + if (input->Read(byte_buffer + (255 - byte_count), byte_count) < byte_count) return -1; + } + bit_buffer |= (unsigned int)byte_buffer[255 - byte_count] << bit_count; + byte_count--; + bit_count += 8; + } + + short s = bit_buffer & ((1 << BITS) - 1); + bit_buffer >>= BITS; + bit_count -= BITS; + return s; +} + +void GIFLoad::ResetTable() { + BITS = code_size + 1; + next_code = clear_code + 2; + max_code = (1 << BITS) - 1; + + MemblockDeleteAll(); + for (int x = 0; x < 4096; x++) { + table[x] = NULL; + if (x < (1 << code_size)) { + table[x] = MemblockAllocate(1); + table[x][0] = x; + entry_size[x] = 1; + } + } +} + +bool GIFLoad::InitFrame(int size) { + code_size = size; + if (code_size == 1) code_size++; + BITS = code_size + 1; + clear_code = 1 << code_size; + end_code = clear_code + 1; + next_code = clear_code + 2; + max_code = (1 << BITS) - 1; + pass = 0; + if (interlaced) row = gl_pass_starts_at[0]; + else row = 0; + + bit_count = 0; + bit_buffer = 0; + byte_count = 0; + old_code_length = 0; + new_code = 0; + scanline_position = 0; + + ResetTable(); + return true; +} + +// Do 4k mallocs, keep them in a linked list, do a first fit across them +// when a new request comes along +uchar *GIFLoad::MemblockAllocate(int size) { + if (head_memblock == NULL) { + head_memblock = new Memblock(); + uchar *value = head_memblock->data; + head_memblock->offset = size; + head_memblock->next = NULL; + return value; + } else { + Memblock *block = head_memblock; + Memblock *last = NULL; + while (block != NULL) { + if (4096 - block->offset > size) { + uchar *value = block->data + block->offset; + block->offset += size; + return value; + } + last = block; + block = block->next; + } + + block = new Memblock(); + uchar *value = block->data; + block->offset = size; + block->next = NULL; + last->next = block; + return value; + } +} + +// Delete the linked list +void GIFLoad::MemblockDeleteAll() { + Memblock *block = NULL; + while (head_memblock != NULL) { + block = head_memblock->next; + delete head_memblock; + head_memblock = block; + } +} + +GIFLoad::~GIFLoad() { + delete palette; +} + diff --git a/src/add-ons/translators/giftranslator/GIFLoad.h b/src/add-ons/translators/giftranslator/GIFLoad.h new file mode 100644 index 0000000000..bce12e5b04 --- /dev/null +++ b/src/add-ons/translators/giftranslator/GIFLoad.h @@ -0,0 +1,103 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// File: GIFLoad.h +// +// Date: December 1999 +// +// Author: Daniel Switkin +// +// Copyright 2003 (c) by Daniel Switkin. This file is made publically available +// under the BSD license, with the stipulations that this complete header must +// remain at the top of the file indefinitely, and credit must be given to the +// original author in any about box using this software. +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef GIFLOAD_H +#define GIFLOAD_H + +#include +#include "LoadPalette.h" + +class Memblock { + public: + uchar data[4096]; + int offset; + Memblock *next; +}; + +const int gl_pass_starts_at[] = {0, 4, 2, 1, 0}; +const int gl_increment_pass_by[] = {8, 8, 4, 2, 0}; + +class GIFLoad { + public: + GIFLoad(BPositionIO *input, BPositionIO *output); + ~GIFLoad(); + bool fatalerror; + + private: + bool ReadGIFHeader(); + bool ReadGIFLoopBlock(); + bool ReadGIFControlBlock(); + bool ReadGIFImageHeader(); + bool ReadGIFImageData(); + bool ReadGIFCommentBlock(); + bool ReadGIFUnknownBlock(unsigned char c); + + void Init(); + bool InitFrame(int size); + short NextCode(); + void ResetTable(); + + uchar *MemblockAllocate(int size); + void MemblockDeleteAll(); + + inline bool OutputColor(unsigned char *string, int size) { + int bpr = width << 2; + + for (int x = 0; x < size; x++) { + scanline[scanline_position] = palette->ColorForIndex(string[x]); + scanline_position++; + + if (scanline_position >= width) { + if (output->WriteAt(32 + (row * bpr), scanline, bpr) < bpr) return false; + scanline_position = 0; + if (interlaced) { + row += gl_increment_pass_by[pass]; + while (row >= height) { + pass++; + if (pass > 3) return true; + row = gl_pass_starts_at[pass]; + } + } else row++; + } + } + return true; + } + + BPositionIO *input, *output; + LoadPalette *palette; + bool interlaced; + int pass, row, width, height; + + unsigned char old_code[4096]; + int old_code_length; + short new_code; + int BITS, max_code, code_size; + short clear_code, end_code, next_code; + + unsigned char *table[4096]; + short entry_size[4096]; + Memblock *head_memblock; + + int bit_count; + unsigned int bit_buffer; + unsigned char byte_count; + unsigned char byte_buffer[255]; + + uint32 *scanline; + int scanline_position; +}; + +#endif + diff --git a/src/add-ons/translators/giftranslator/GIFSave.cpp b/src/add-ons/translators/giftranslator/GIFSave.cpp new file mode 100644 index 0000000000..4c4f1ade5e --- /dev/null +++ b/src/add-ons/translators/giftranslator/GIFSave.cpp @@ -0,0 +1,406 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// File: GIFSave.cpp +// +// Date: December 1999 +// +// Author: Daniel Switkin +// +// Copyright 2003 (c) by Daniel Switkin. This file is made publically available +// under the BSD license, with the stipulations that this complete header must +// remain at the top of the file indefinitely, and credit must be given to the +// original author in any about box using this software. +// +//////////////////////////////////////////////////////////////////////////////// + +#include "GIFSave.h" +#include +#include + +const int gs_pass_starts_at[] = {0, 4, 2, 1, 0}; +const int gs_increment_pass_by[] = {8, 8, 4, 2, 0}; +const int32 one_sixteenth = (int32)((1.0 / 16.0) * 32768); +const int32 three_sixteenth = (int32)((3.0 / 16.0) * 32768); +const int32 five_sixteenth = (int32)((5.0 / 16.0) * 32768); +const int32 seven_sixteenth = (int32)((7.0 / 16.0) * 32768); + +extern bool debug; + +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"); + fatalerror = true; + return; + } + + fatalerror = false; + prefs = new Prefs(); + if (prefs->palettemode == OPTIMAL_PALETTE) palette = new SavePalette(bitmap); + else palette = new SavePalette(prefs->palettemode); + if (palette->fatalerror) { + fatalerror = true; + return; + } + + width = bitmap->Bounds().IntegerWidth() + 1; + height = bitmap->Bounds().IntegerHeight() + 1; + if (debug) printf("GIFSave::GIFSave() - Image dimensions are %d by %d\n", width, height); + + if (prefs->usedithering) { + if (debug) printf("GIFSave::GIFSave() - Using dithering\n"); + red_error = new int32[width + 2]; + red_error = &red_error[1]; // Allow index of -1 too + green_error = new int32[width + 2]; + green_error = &green_error[1]; // Allow index of -1 too + blue_error = new int32[width + 2]; + blue_error = &blue_error[1]; // Allow index of -1 too + + red_side_error = green_side_error = blue_side_error = 0; + for (int32 x = -1; x < width + 1; x++) { + red_error[x] = 0; + green_error[x] = 0; + blue_error[x] = 0; + } + } else { + if (debug) printf("GIFSave::GIFSave() - Not using dithering\n"); + } + + if (debug) { + if (prefs->interlaced) printf("GIFSave::GIFSave() - Interlaced, "); + else printf("GIFSave::GIFSave() - Not interlaced, "); + switch (prefs->palettemode) { + case WEB_SAFE_PALETTE: + printf("web safe palette\n"); + break; + case BEOS_SYSTEM_PALETTE: + printf("BeOS system palette\n"); + break; + case GREYSCALE_PALETTE: + printf("greyscale palette\n"); + break; + case OPTIMAL_PALETTE: + default: + printf("optimal palette\n"); + break; + } + } + + palette->usetransparent = prefs->usetransparent; + if (prefs->usetransparent) { + if (prefs->usetransparentindex) { + palette->transparentindex = 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; + } + } + 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"); + } + + this->output = output; + this->bitmap = bitmap; + WriteGIFHeader(); + if (debug) printf("GIFSave::GIFSave() - Wrote gif header\n"); + + hash = new SFHash(1 << 16); + WriteGIFControlBlock(); + if (debug) printf("GIFSave::GIFSave() - Wrote gif control block\n"); + WriteGIFImageHeader(); + if (debug) printf("GIFSave::GIFSave() - Wrote gif image header\n"); + WriteGIFImageData(); + if (debug) printf("GIFSave::GIFSave() - Wrote gif image data\n"); + + if (prefs->usedithering) { + delete [] &red_error[-1]; + delete [] &green_error[-1]; + delete [] &blue_error[-1]; + } + delete hash; + + // Terminating character + char t = 0x3b; + output->Write(&t, 1); +} + +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; + 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); +} + +void GIFSave::WriteGIFControlBlock() { + unsigned char b[8] = {0x21, 0xf9, 0x04, 0, 0, 0, 0, 0x00}; + if (palette->usetransparent) { + b[3] = b[3] | 1; + b[6] = palette->transparentindex; + } + output->Write(b, 8); +} + +void GIFSave::WriteGIFImageHeader() { + unsigned char header[10]; + header[0] = 0x2c; + header[1] = header[2] = 0; + header[3] = header[4] = 0; + + header[5] = width & 0xff; + header[6] = (width & 0xff00) >> 8; + header[7] = height & 0xff; + header[8] = (height & 0xff00) >> 8; + + if (prefs->interlaced) header[9] = 0x40; + else header[9] = 0x00; + output->Write(header, 10); +} + +void GIFSave::WriteGIFImageData() { + InitFrame(); + code_value = (short *)malloc(HASHSIZE * 2); + prefix_code = (short *)malloc(HASHSIZE * 2); + append_char = (unsigned char *)malloc(HASHSIZE); + ResetHashtable(); + + output->Write(&code_size, 1); + OutputCode(clear_code, BITS); + string_code = NextPixel(0); + int area = height * width; + + for (int x = 1; x < area; x++) { + character = NextPixel(x); + int y = 0; + if ((y = CheckHashtable(string_code, character)) != -1) { + string_code = y; + } else { + AddToHashtable(string_code, character); + OutputCode(string_code, BITS); + + if (next_code > max_code) { + BITS++; + if (BITS > 12) { + OutputCode(clear_code, 12); + BITS = code_size + 1; + ResetHashtable(); + next_code = clear_code + 1; // this is different + } + max_code = (1 << BITS) - 1; + } + string_code = character; + next_code++; + } + } + OutputCode(string_code, BITS); + OutputCode(end_code, BITS); + OutputCode(0, BITS, true); + char t = 0x00; + output->Write(&t, 1); + free(code_value); + free(prefix_code); + free(append_char); +} + +void GIFSave::OutputCode(short code, int BITS, bool flush) { + if (!flush) { + bit_buffer |= (unsigned int) code << bit_count; + bit_count += BITS; + while (bit_count >= 8) { + byte_buffer[byte_count + 1] = (unsigned char)(bit_buffer & 0xff); + byte_count++; + bit_buffer >>= 8; + bit_count -= 8; + } + if (byte_count >= 255) { + byte_buffer[0] = 255; + output->Write(byte_buffer, 256); + if (byte_count == 256) { + byte_buffer[1] = byte_buffer[256]; + byte_count = 1; + } else byte_count = 0; + } + } else { + bit_buffer |= (unsigned int) code << bit_count; + bit_count += BITS; + while (bit_count > 0) { + byte_buffer[byte_count + 1] = (unsigned char)(bit_buffer & 0xff); + byte_count++; + bit_buffer >>= 8; + bit_count -= 8; + } + if (byte_count > 0) { + byte_buffer[0] = (unsigned char)byte_count; + output->Write(byte_buffer, byte_count + 1); + } + } +} + +void GIFSave::ResetHashtable() { + for (int q = 0; q < HASHSIZE; q++) { + code_value[q] = -1; + prefix_code[q] = 0; + append_char[q] = 0; + } +} + +int GIFSave::CheckHashtable(int s, unsigned char c) { + if (s == -1) return c; + int hashindex = HASH(s, c); + int nextindex; + while ((nextindex = code_value[hashindex]) != -1) { + if (prefix_code[nextindex] == s && append_char[nextindex] == c) + return nextindex; + hashindex = (hashindex + HASHSTEP) % HASHSIZE; + } + return -1; +} + +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; + prefix_code[next_code] = s; + append_char[next_code] = c; +} + +unsigned char GIFSave::NextPixel(int pixel) { + int bpr = bitmap->BytesPerRow(); + color_space cs = bitmap->ColorSpace(); + unsigned char r, g, b; + + if (cs == B_RGB32 || cs == B_RGBA32) { + b = gifbits[0]; + g = gifbits[1]; + r = gifbits[2]; + } else { + r = gifbits[1]; + g = gifbits[2]; + b = gifbits[3]; + } + gifbits += 4; + pos += 4; + + 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)); + } + + if (prefs->interlaced) { + if (pos >= bpr) { + pos = 0; + row += gs_increment_pass_by[pass]; + while (row >= height) { + pass++; + row = gs_pass_starts_at[pass]; + } + gifbits = (unsigned char *)bitmap->Bits() + (bpr * row); + } + } + + unsigned int key = (r << 16) + (g << 8) + b; + ColorCache *cc = (ColorCache *)hash->GetItem(key); + if (cc == NULL) { + cc = new ColorCache(); + cc->key = key; + 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 + // 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[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; + 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 cc->index; +} + +void GIFSave::InitFrame() { + code_size = palette->size_in_bits; + if (code_size == 1) code_size++; + BITS = code_size + 1; + clear_code = 1 << code_size; + end_code = clear_code + 1; + next_code = clear_code + 2; + max_code = (1 << BITS) - 1; + string_code = 0; + character = 0; + table_size = 1 << 12; + + bit_count = 0; + bit_buffer = 0; + byte_count = 0; + + pass = pos = 0; + row = gs_pass_starts_at[0]; + + gifbits = (unsigned char *)bitmap->Bits(); +} + +GIFSave::~GIFSave() { + delete palette; + delete prefs; +} + diff --git a/src/add-ons/translators/giftranslator/GIFSave.h b/src/add-ons/translators/giftranslator/GIFSave.h new file mode 100644 index 0000000000..882c714874 --- /dev/null +++ b/src/add-ons/translators/giftranslator/GIFSave.h @@ -0,0 +1,81 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// File: GIFSave.h +// +// Date: December 1999 +// +// Author: Daniel Switkin +// +// Copyright 2003 (c) by Daniel Switkin. This file is made publically available +// under the BSD license, with the stipulations that this complete header must +// remain at the top of the file indefinitely, and credit must be given to the +// original author in any about box using this software. +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef GIFSAVE_H +#define GIFSAVE_H + +#include +#include +#include "SavePalette.h" +#include "SFHash.h" +#include "Prefs.h" + +#define HASHSIZE 9973 +#define HASHSTEP 2039 + +#define HASH(index, lastbyte) (((lastbyte << 8) ^ index) % HASHSIZE) + +class GIFSave { + public: + GIFSave(BBitmap *bitmap, BPositionIO *output); + ~GIFSave(); + + bool fatalerror; + + private: + void WriteGIFHeader(); + void WriteGIFControlBlock(); + void WriteGIFImageHeader(); + void WriteGIFImageData(); + void OutputCode(short code, int BITS, bool flush=false); + + unsigned char NextPixel(int pixel); + void InitFrame(); + void ResetHashtable(); + int CheckHashtable(int s, unsigned char c); + void AddToHashtable(int s, unsigned char c); + + BPositionIO *output; + BBitmap *bitmap; + SavePalette *palette; + SFHash *hash; + Prefs *prefs; + + short *code_value, *prefix_code; + unsigned char *append_char; + int BITS, max_code; + char code_size; + short clear_code, end_code, next_code; + int string_code; + unsigned char character; + int table_size; + + int bit_count; + unsigned int bit_buffer; + int byte_count; + unsigned char byte_buffer[257]; + int pass, row, pos; + + unsigned char *gifbits; + + int width, height; + + // For dithering + int32 *red_error, *green_error, *blue_error; + int16 red_side_error, green_side_error, blue_side_error; +}; + +#endif + diff --git a/src/add-ons/translators/giftranslator/GIFTranslator.cpp b/src/add-ons/translators/giftranslator/GIFTranslator.cpp new file mode 100644 index 0000000000..160232353b --- /dev/null +++ b/src/add-ons/translators/giftranslator/GIFTranslator.cpp @@ -0,0 +1,214 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// File: GIFTranslator.cpp +// +// Date: December 1999 +// +// Author: Daniel Switkin +// +// Copyright 2003 (c) by Daniel Switkin. This file is made publically available +// under the BSD license, with the stipulations that this complete header must +// remain at the top of the file indefinitely, and credit must be given to the +// original author in any about box using this software. +// +//////////////////////////////////////////////////////////////////////////////// + +#include "GIFTranslator.h" +#include "GIFWindow.h" +#include "GIFView.h" +#include "GIFSave.h" +#include "GIFLoad.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef GIF_TYPE +#define GIF_TYPE 'GIF ' +#endif + +// This global will be externed in other files - set once here +// for the entire translator +bool debug = false; + +bool DetermineType(BPositionIO *source, bool *is_gif); +status_t GetBitmap(BPositionIO *in, BBitmap **out); + +/* Required data */ +char translatorName[] = "GIF Images"; +char translatorInfo[] = "GIF image translator v1.3"; +int32 translatorVersion = 0x130; + +translation_format inputFormats[] = { + { GIF_TYPE, B_TRANSLATOR_BITMAP, 0.8, 0.8, "image/gif", "GIF image" }, + { B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.3, 0.3, "image/x-be-bitmap", "Be Bitmap image" }, + { 0, 0, 0, 0, 0, 0 } +}; + +translation_format outputFormats[] = { + { GIF_TYPE, B_TRANSLATOR_BITMAP, 0.8, 0.8, "image/gif", "GIF image" }, + { B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.3, 0.3, "image/x-be-bitmap", "Be Bitmap image" }, + { 0, 0, 0, 0, 0, 0 } +}; + +/* Build a pretty view for DataTranslations */ +status_t MakeConfig(BMessage *ioExtension, BView **outView, BRect *outExtent) { + outExtent->Set(0, 0, 239, 239); + GIFView *gifview = new GIFView(*outExtent, "TranslatorView"); + *outView = gifview; + return B_OK; +} + +/* Look at first few bytes in stream to determine type - throw it back + if it is not a GIF or a BBitmap that we understand */ +bool DetermineType(BPositionIO *source, bool *is_gif) { + unsigned char header[7]; + *is_gif = true; + if (source->Read(header, 6) != 6) return false; + header[6] = 0x00; + + if (strcmp((char *)header, "GIF87a") != 0 && strcmp((char *)header, "GIF89a") != 0) { + *is_gif = false; + int32 magic = (header[0] << 24) + (header[1] << 16) + (header[2] << 8) + header[3]; + if (magic != B_TRANSLATOR_BITMAP) return false; + source->Seek(5 * 4 - 2, SEEK_CUR); + color_space cs; + if (source->Read(&cs, 4) != 4) return false; + cs = (color_space)B_BENDIAN_TO_HOST_INT32(cs); + if (cs != B_RGB32 && cs != B_RGBA32 && cs != B_RGB32_BIG && cs != B_RGBA32_BIG) return false; + } + + source->Seek(0, SEEK_SET); + return true; +} + +/* Dump data from stream into a BBitmap */ +status_t GetBitmap(BPositionIO *in, BBitmap **out) { + TranslatorBitmap header; + + status_t err = in->Read(&header, sizeof(header)); + if (err != sizeof(header)) return B_IO_ERROR; + + header.magic = B_BENDIAN_TO_HOST_INT32(header.magic); + header.bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left); + header.bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top); + header.bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right); + header.bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom); + header.rowBytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes); + header.colors = (color_space)B_BENDIAN_TO_HOST_INT32(header.colors); + header.dataSize = B_BENDIAN_TO_HOST_INT32(header.dataSize); + + BBitmap *bitmap = new BBitmap(header.bounds, header.colors); + *out = bitmap; + if (bitmap == NULL) return B_NO_MEMORY; + unsigned char *bits = (unsigned char *)bitmap->Bits(); + if (bits == NULL) { + delete bitmap; + return B_NO_MEMORY; + } + err = in->Read(bits, header.dataSize); + if (err == (status_t)header.dataSize) return B_OK; + else return B_IO_ERROR; +} + +/* Required Identify function - may need to read entire header, not sure */ +status_t Identify(BPositionIO *inSource, const translation_format *inFormat, + BMessage *ioExtension, translator_info *outInfo, uint32 outType) { + + const char *debug_text = getenv("GIF_TRANSLATOR_DEBUG"); + if ((debug_text != NULL) && (atoi(debug_text) != 0)) debug = true; + + if (outType == 0) outType = B_TRANSLATOR_BITMAP; + if (outType != GIF_TYPE && outType != B_TRANSLATOR_BITMAP) return B_NO_TRANSLATOR; + + bool is_gif; + if (!DetermineType(inSource, &is_gif)) return B_NO_TRANSLATOR; + if (!is_gif && inFormat != NULL && inFormat->type != B_TRANSLATOR_BITMAP) + return B_NO_TRANSLATOR; + + outInfo->group = B_TRANSLATOR_BITMAP; + if (is_gif) { + outInfo->type = GIF_TYPE; + outInfo->quality = 0.8; + outInfo->capability = 0.8; + strcpy(outInfo->name, "GIF image"); + strcpy(outInfo->MIME, "image/gif"); + } + else { + outInfo->type = B_TRANSLATOR_BITMAP; + outInfo->quality = 0.3; + outInfo->capability = 0.3; + strcpy(outInfo->name, "Be Bitmap image"); + strcpy(outInfo->MIME, "image/x-be-bitmap"); + } + return B_OK; +} + +/* Main required function - assumes that an incoming GIF must be translated + to a BBitmap, and vice versa - this could be improved */ +status_t Translate(BPositionIO *inSource, const translator_info *inInfo, + BMessage *ioExtension, uint32 outType, BPositionIO *outDestination) { + + const char *debug_text = getenv("GIF_TRANSLATOR_DEBUG"); + if ((debug_text != NULL) && (atoi(debug_text) != 0)) debug = true; + + if (outType == 0) outType = B_TRANSLATOR_BITMAP; + if (outType != GIF_TYPE && outType != B_TRANSLATOR_BITMAP) { + return B_NO_TRANSLATOR; + } + + bool is_gif; + if (!DetermineType(inSource, &is_gif)) return B_NO_TRANSLATOR; + if (!is_gif && inInfo->type != B_TRANSLATOR_BITMAP) return B_NO_TRANSLATOR; + + status_t err = B_OK; + bigtime_t now = system_time(); + // Going from BBitmap to GIF + if (!is_gif) { + BBitmap **b = (BBitmap **)malloc(4); + *b = NULL; + err = GetBitmap(inSource, b); + if (err != B_OK) return err; + GIFSave *gs = new GIFSave(*b, outDestination); + if (gs->fatalerror) { + delete gs; + if (*b != NULL) delete *b; + delete b; + return B_NO_MEMORY; + } + delete gs; + delete *b; + delete b; + } else { // GIF to BBitmap + GIFLoad *gl = new GIFLoad(inSource, outDestination); + if (gl->fatalerror) { + delete gl; + return B_NO_MEMORY; + } + delete gl; + } + + if (debug) { + now = system_time() - now; + printf("Translate() - Translation took %Ld microseconds\n", now); + } + return B_OK; +} + +GIFTranslator::GIFTranslator() : BApplication("application/x-vnd.Jules-GIFTranslator") { + BRect rect(100, 100, 339, 339); + gifwindow = new GIFWindow(rect, "GIF Settings"); + gifwindow->Show(); +} + +int main() { + GIFTranslator myapp; + myapp.Run(); + return 0; +} + diff --git a/src/add-ons/translators/giftranslator/GIFTranslator.h b/src/add-ons/translators/giftranslator/GIFTranslator.h new file mode 100644 index 0000000000..613f9c67c9 --- /dev/null +++ b/src/add-ons/translators/giftranslator/GIFTranslator.h @@ -0,0 +1,29 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// File: GIFTranslator.h +// +// Date: December 1999 +// +// Author: Daniel Switkin +// +// Copyright 2003 (c) by Daniel Switkin. This file is made publically available +// under the BSD license, with the stipulations that this complete header must +// remain at the top of the file indefinitely, and credit must be given to the +// original author in any about box using this software. +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef GIFTRANSLATOR_H +#define GIFTRANSLATOR_H + +#include +class GIFWindow; + +class GIFTranslator : public BApplication { + public: + GIFTranslator(); + GIFWindow *gifwindow; +}; + +#endif + diff --git a/src/add-ons/translators/giftranslator/GIFView.cpp b/src/add-ons/translators/giftranslator/GIFView.cpp new file mode 100644 index 0000000000..36cbc50ceb --- /dev/null +++ b/src/add-ons/translators/giftranslator/GIFView.cpp @@ -0,0 +1,326 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// File: GIFView.cpp +// +// Date: December 1999 +// +// Author: Daniel Switkin +// +// Copyright 2003 (c) by Daniel Switkin. This file is made publically available +// under the BSD license, with the stipulations that this complete header must +// remain at the top of the file indefinitely, and credit must be given to the +// original author in any about box using this software. +// +//////////////////////////////////////////////////////////////////////////////// + +#include "GIFView.h" +#include "SavePalette.h" +#include "Prefs.h" +#include +#include +#include + +extern int32 translatorVersion; +extern char translatorName[]; + +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; + be_bold_font->GetHeight(&fh); + BRect r(10, 15, 10 + be_bold_font->StringWidth(translatorName), 15 + fh.ascent + fh.descent); + + BStringView *title = new BStringView(r, "Title", translatorName); + title->SetFont(be_bold_font); + AddChild(title); + + 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.right = r.left + be_plain_font->StringWidth(version_string); + + BStringView *version = new BStringView(r, "Version", version_string); + version->SetFont(be_plain_font); + AddChild(version); + + const char *copyright_string = "© 2003 Daniel Switkin, software@switkin.com"; + r.top = r.bottom + 10; + r.bottom = r.top + fh.ascent + fh.descent; + r.right = r.left + be_plain_font->StringWidth(copyright_string); + + BStringView *copyright = new BStringView(r, "Copyright", copyright_string); + copyright->SetFont(be_plain_font); + AddChild(copyright); + + 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.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); + + r.top = palettemenufield->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", + new BMessage(GV_USE_DITHERING)); + AddChild(usedithering); + + r.top = usedithering->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", + new BMessage(GV_INTERLACED)); + AddChild(interlaced); + + r.top = interlaced->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", + new BMessage(GV_USE_TRANSPARENT)); + AddChild(usetransparent); + + r.top = usetransparent->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:", + new BMessage(GV_USE_TRANSPARENT_INDEX)); + AddChild(usetransparentindex); + + r.left = r.right + 1; + r.right = r.left + 30; + transparentindex = new BTextControl(r, "TransparentIndex", "", "0", + new BMessage(GV_TRANSPARENT_INDEX)); + AddChild(transparentindex); + transparentindex->SetDivider(0); + + r.top = usetransparentindex->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:", + new BMessage(GV_USE_TRANSPARENT_COLOR)); + AddChild(usetransparentcolor); + + r.left = r.right + 1; + r.right = r.left + 30; + transparentred = new BTextControl(r, "TransparentRed", "", "0", + new BMessage(GV_TRANSPARENT_RED)); + AddChild(transparentred); + transparentred->SetDivider(0); + + r.left = r.right + 5; + r.right = r.left + 30; + transparentgreen = new BTextControl(r, "TransparentGreen", "", "0", + new BMessage(GV_TRANSPARENT_GREEN)); + AddChild(transparentgreen); + transparentgreen->SetDivider(0); + + r.left = r.right + 5; + r.right = r.left + 30; + transparentblue = 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(); + + for (uint32 x = 0; x < 256; x++) { + if (x < '0' || x > '9') { + ti->DisallowChar(x); + tr->DisallowChar(x); + tg->DisallowChar(x); + tb->DisallowChar(x); + } + } + + RestorePrefs(); +} + +void GIFView::RestorePrefs() { + prefs = new Prefs(); + + switch (prefs->palettemode) { + case WEB_SAFE_PALETTE: + websafe->SetMarked(true); + break; + case BEOS_SYSTEM_PALETTE: + beossystem->SetMarked(true); + break; + case GREYSCALE_PALETTE: + greyscale->SetMarked(true); + usedithering->SetEnabled(false); + break; + case OPTIMAL_PALETTE: + optimal->SetMarked(true); + break; + default: + prefs->palettemode = WEB_SAFE_PALETTE; + websafe->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); + } else { + usetransparentindex->SetEnabled(false); + usetransparentcolor->SetEnabled(false); + transparentindex->SetEnabled(false); + transparentred->SetEnabled(false); + transparentgreen->SetEnabled(false); + transparentblue->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); +} + +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); +} + +void GIFView::MessageReceived(BMessage *message) { + switch (message->what) { + case GV_WEB_SAFE: + prefs->palettemode = WEB_SAFE_PALETTE; + usedithering->SetEnabled(true); + break; + case GV_BEOS_SYSTEM: + prefs->palettemode = BEOS_SYSTEM_PALETTE; + usedithering->SetEnabled(true); + break; + case GV_GREYSCALE: + prefs->palettemode = GREYSCALE_PALETTE; + usedithering->SetEnabled(false); + usedithering->SetValue(false); + prefs->usedithering = false; + break; + case GV_OPTIMAL: + prefs->palettemode = OPTIMAL_PALETTE; + usedithering->SetEnabled(true); + break; + case GV_INTERLACED: + prefs->interlaced = interlaced->Value(); + break; + case GV_USE_DITHERING: + prefs->usedithering = usedithering->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()); + } else { + usetransparentindex->SetEnabled(false); + usetransparentcolor->SetEnabled(false); + transparentindex->SetEnabled(false); + transparentred->SetEnabled(false); + transparentgreen->SetEnabled(false); + transparentblue->SetEnabled(false); + } + break; + case GV_USE_TRANSPARENT_INDEX: + prefs->usetransparentindex = true; + transparentindex->SetEnabled(true); + transparentred->SetEnabled(false); + transparentgreen->SetEnabled(false); + transparentblue->SetEnabled(false); + break; + case GV_TRANSPARENT_INDEX: + prefs->transparentindex = CheckInput(transparentindex); + break; + case GV_USE_TRANSPARENT_COLOR: + prefs->usetransparentindex = false; + transparentindex->SetEnabled(false); + transparentred->SetEnabled(true); + transparentgreen->SetEnabled(true); + transparentblue->SetEnabled(true); + break; + case GV_TRANSPARENT_RED: + prefs->transparentred = CheckInput(transparentred); + break; + case GV_TRANSPARENT_GREEN: + prefs->transparentgreen = CheckInput(transparentgreen); + break; + case GV_TRANSPARENT_BLUE: + prefs->transparentblue = CheckInput(transparentblue); + break; + default: + BView::MessageReceived(message); + break; + } + prefs->Save(); +} + +int GIFView::CheckInput(BTextControl *control) { + int value = atoi(control->Text()); + if (value < 0 || value > 255) { + value = (value < 0) ? 0 : 255; + char temp[4]; + sprintf(temp, "%d", value); + control->SetText(temp); + } + return value; +} + +GIFView::~GIFView() { + delete prefs; +} + diff --git a/src/add-ons/translators/giftranslator/GIFView.h b/src/add-ons/translators/giftranslator/GIFView.h new file mode 100644 index 0000000000..38cce8b158 --- /dev/null +++ b/src/add-ons/translators/giftranslator/GIFView.h @@ -0,0 +1,64 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// File: GIFView.h +// +// Date: December 1999 +// +// Author: Daniel Switkin +// +// Copyright 2003 (c) by Daniel Switkin. This file is made publically available +// under the BSD license, with the stipulations that this complete header must +// remain at the top of the file indefinitely, and credit must be given to the +// original author in any about box using this software. +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef GIFVIEW_H +#define GIFVIEW_H + +#include +class BMenuField; +class BPopUpMenu; +class BMenuItem; +class BCheckBox; +class BRadioButton; +class BTextControl; +class Prefs; + +#define GV_WEB_SAFE 'gvws' +#define GV_BEOS_SYSTEM 'gvbe' +#define GV_GREYSCALE 'gvgr' +#define GV_OPTIMAL 'gvop' +#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_COLOR 'gvuc' +#define GV_TRANSPARENT_RED 'gvtr' +#define GV_TRANSPARENT_GREEN 'gvtg' +#define GV_TRANSPARENT_BLUE 'gvtb' + +class GIFView : public BView { + public: + GIFView(BRect rect, const char *name); + ~GIFView(); + void MessageReceived(BMessage *message); + 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); +}; + +#endif + diff --git a/src/add-ons/translators/giftranslator/GIFWindow.cpp b/src/add-ons/translators/giftranslator/GIFWindow.cpp new file mode 100644 index 0000000000..3628f42efa --- /dev/null +++ b/src/add-ons/translators/giftranslator/GIFWindow.cpp @@ -0,0 +1,33 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// File: GIFWindow.cpp +// +// Date: December 1999 +// +// Author: Daniel Switkin +// +// Copyright 2003 (c) by Daniel Switkin. This file is made publically available +// under the BSD license, with the stipulations that this complete header must +// remain at the top of the file indefinitely, and credit must be given to the +// original author in any about box using this software. +// +//////////////////////////////////////////////////////////////////////////////// + +#include "GIFWindow.h" +#include "GIFView.h" +#include + +GIFWindow::GIFWindow(BRect rect, const char *name) : + BWindow(rect, name, B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE, + B_CURRENT_WORKSPACE) { + + BRect r(Bounds()); + gifview = new GIFView(r, "GIFView"); + AddChild(gifview); +} + +bool GIFWindow::QuitRequested() { + be_app->PostMessage(B_QUIT_REQUESTED); + return true; +} + diff --git a/src/add-ons/translators/giftranslator/GIFWindow.h b/src/add-ons/translators/giftranslator/GIFWindow.h new file mode 100644 index 0000000000..b05150dac0 --- /dev/null +++ b/src/add-ons/translators/giftranslator/GIFWindow.h @@ -0,0 +1,30 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// File: GIFWindow.h +// +// Date: December 1999 +// +// Author: Daniel Switkin +// +// Copyright 2003 (c) by Daniel Switkin. This file is made publically available +// under the BSD license, with the stipulations that this complete header must +// remain at the top of the file indefinitely, and credit must be given to the +// original author in any about box using this software. +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef GIFWINDOW_H +#define GIFWINDOW_H + +#include +class GIFView; + +class GIFWindow : public BWindow { + public: + GIFWindow(BRect rect, const char *name); + bool QuitRequested(); + GIFView *gifview; +}; + +#endif + diff --git a/src/add-ons/translators/giftranslator/Jamfile b/src/add-ons/translators/giftranslator/Jamfile new file mode 100644 index 0000000000..6e22617d84 --- /dev/null +++ b/src/add-ons/translators/giftranslator/Jamfile @@ -0,0 +1,18 @@ +SubDir OBOS_TOP src add-ons translators giftranslator ; + +Translator GIFTranslator : + # Main Source + GIFTranslator.cpp + GIFView.cpp + GIFWindow.cpp + Prefs.cpp + + # Real Work + GIFLoad.cpp + LoadPalette.cpp + GIFSave.cpp + SavePalette.cpp + SFHash.cpp + ; + +LinkSharedOSLibs GIFTranslator : be translation ; diff --git a/src/add-ons/translators/giftranslator/LoadPalette.cpp b/src/add-ons/translators/giftranslator/LoadPalette.cpp new file mode 100644 index 0000000000..549b053c5d --- /dev/null +++ b/src/add-ons/translators/giftranslator/LoadPalette.cpp @@ -0,0 +1,42 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// File: LoadPalette.cpp +// +// Date: December 1999 +// +// Author: Daniel Switkin +// +// Copyright 2003 (c) by Daniel Switkin. This file is made publically available +// under the BSD license, with the stipulations that this complete header must +// remain at the top of the file indefinitely, and credit must be given to the +// original author in any about box using this software. +// +//////////////////////////////////////////////////////////////////////////////// + +#include "LoadPalette.h" +#include +#include + +LoadPalette::LoadPalette() { + backgroundindex = 0; + usetransparent = false; + transparentindex = 0; + size = size_in_bits = 0; +} + +// Never index into pal directly - this function is safe +uint32 LoadPalette::ColorForIndex(int index) { + if (index >= 0 && index <= size) { + if (usetransparent && index == transparentindex) return B_TRANSPARENT_MAGIC_RGBA32; + else return data[index]; + } else { + return B_BENDIAN_TO_HOST_INT32(0x000000ff); + } +} + +void LoadPalette::SetColor(int index, uint8 red, uint8 green, uint8 blue) { + if (index < 0 || index > 255) return; + data[index] = (blue << 24) + (green << 16) + (red << 8) + 0xff; + data[index] = B_BENDIAN_TO_HOST_INT32(data[index]); +} + diff --git a/src/add-ons/translators/giftranslator/LoadPalette.h b/src/add-ons/translators/giftranslator/LoadPalette.h new file mode 100644 index 0000000000..d01d37482a --- /dev/null +++ b/src/add-ons/translators/giftranslator/LoadPalette.h @@ -0,0 +1,36 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// File: LoadPalette.h +// +// Date: December 1999 +// +// Author: Daniel Switkin +// +// Copyright 2003 (c) by Daniel Switkin. This file is made publically available +// under the BSD license, with the stipulations that this complete header must +// remain at the top of the file indefinitely, and credit must be given to the +// original author in any about box using this software. +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef LOAD_PALETTE_H +#define LOAD_PALETTE_H + +#include + +class LoadPalette { + public: + LoadPalette(); + uint32 ColorForIndex(int index); + void SetColor(int index, uint8 red, uint8 green, uint8 blue); + + int size, size_in_bits; + int backgroundindex, transparentindex; + bool usetransparent; + + private: + uint32 data[256]; +}; + +#endif + diff --git a/src/add-ons/translators/giftranslator/Prefs.cpp b/src/add-ons/translators/giftranslator/Prefs.cpp new file mode 100644 index 0000000000..3da553e391 --- /dev/null +++ b/src/add-ons/translators/giftranslator/Prefs.cpp @@ -0,0 +1,123 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// File: Prefs.cpp +// +// Date: December 1999 +// +// Author: Daniel Switkin +// +// Copyright 2003 (c) by Daniel Switkin. This file is made publically available +// under the BSD license, with the stipulations that this complete header must +// remain at the top of the file indefinitely, and credit must be given to the +// original author in any about box using this software. +// +//////////////////////////////////////////////////////////////////////////////// + +#include "Prefs.h" +#include +#include +#include +#include + +extern bool debug; + +Prefs::Prefs() { + interlaced = usetransparent = usetransparentindex = false; + usedithering = true; + transparentindex = transparentred = transparentgreen = + transparentblue = palettemode = 0; + + BPath path; + find_directory(B_USER_SETTINGS_DIRECTORY, &path); + path.Append("GIFTranslator_settings"); + file = new BFile(path.Path(), B_READ_WRITE | B_CREATE_FILE); + + if (file->InitCheck() != B_OK) { + if (debug) printf("Bad filename for attributes\n"); + return; + } + + bool db = false; + if (!GetBool("interlaced", &interlaced, &db)) return; + db = false; + if (!GetBool("usetransparent", &usetransparent, &db)) return; + db = false; + if (!GetBool("usetransparentindex", &usetransparentindex, &db)) return; + db = true; + if (!GetBool("usedithering", &usedithering, &db)) return; + int di = 0; + if (!GetInt("palettemode", &palettemode, &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; + di = 0; + if (!GetInt("transparentblue", &transparentblue, &di)) return; +} + +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; + if (file->WriteAttr(name, B_INT32_TYPE, 0, defaultvalue, 4) < 0) { + if (debug) printf("WriteAttr on %s died\n", name); + return false; + } + } else if (err < 0) { + if (debug) printf("Unknown error reading %s\n", name); + return false; + } + return true; +} + +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; + if (file->WriteAttr(name, B_BOOL_TYPE, 0, defaultvalue, 1) < 0) { + if (debug) printf("WriteAttr on %s died\n", name); + return false; + } + } else if (err < 0) { + if (debug) printf("Unknown error reading %s\n", name); + return false; + } + return true; +} + +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); + return false; + } + return true; +} + +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); + return false; + } + return true; +} + +void Prefs::Save() { + if (!PutBool("interlaced", &interlaced)) return; + if (!PutBool("usetransparent", &usetransparent)) return; + if (!PutBool("usetransparentindex", &usetransparentindex)) return; + if (!PutBool("usedithering", &usedithering)) return; + if (!PutInt("palettemode", &palettemode)) 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; +} + diff --git a/src/add-ons/translators/giftranslator/Prefs.h b/src/add-ons/translators/giftranslator/Prefs.h new file mode 100644 index 0000000000..dd3c046428 --- /dev/null +++ b/src/add-ons/translators/giftranslator/Prefs.h @@ -0,0 +1,40 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// File: Prefs.h +// +// Date: December 1999 +// +// Author: Daniel Switkin +// +// Copyright 2003 (c) by Daniel Switkin. This file is made publically available +// under the BSD license, with the stipulations that this complete header must +// remain at the top of the file indefinitely, and credit must be given to the +// original author in any about box using this software. +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef PREFS_H +#define PREFS_H + +class BNode; + +class Prefs { + public: + Prefs(); + void Save(); + ~Prefs(); + bool interlaced, usetransparent, usetransparentindex, + usedithering; + int transparentindex, transparentred, transparentgreen, + transparentblue, palettemode; + private: + bool GetInt(char *name, int *value, int *defaultvalue); + bool GetBool(char *name, bool *value, bool *defaultvalue); + bool PutInt(char *name, int *value); + bool PutBool(char *name, bool *value); + + BNode *file; +}; + +#endif + diff --git a/src/add-ons/translators/giftranslator/SFHash.cpp b/src/add-ons/translators/giftranslator/SFHash.cpp new file mode 100644 index 0000000000..b19ec457b2 --- /dev/null +++ b/src/add-ons/translators/giftranslator/SFHash.cpp @@ -0,0 +1,111 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// File: SFHash.cpp +// +// Date: December 1999 +// +// Author: Daniel Switkin +// +// Copyright 2003 (c) by Daniel Switkin. This file is made publically available +// under the BSD license, with the stipulations that this complete header must +// remain at the top of the file indefinitely, and credit must be given to the +// original author in any about box using this software. +// +//////////////////////////////////////////////////////////////////////////////// + +#include "SFHash.h" +#include +#include + +SFHash::SFHash(int size) { + fatalerror = false; + this->size = size; + iterate_pos = iterate_depth = 0; + main_array = (HashItem **)malloc(this->size * 4); + + if (main_array == NULL) { + fatalerror = true; + return; + } + for (int x = 0; x < this->size; x++) { + main_array[x] = NULL; + } +} + +SFHash::SFHash() { + SFHash(4096); +} + +void SFHash::AddItem(HashItem *item) { + item->next = NULL; + int pos = item->key % size; + + if (main_array[pos] == NULL) { + main_array[pos] = item; + } + else { + HashItem *temp = main_array[pos]; + while (temp->next != NULL) temp = temp->next; + temp->next = item; + } +} + +HashItem *SFHash::GetItem(unsigned int key) { + int pos = key % size; + HashItem *item = main_array[pos]; + + while (item != NULL) { + if (item->key == key) return item; + item = item->next; + } + return NULL; +} + +unsigned int SFHash::CountItems() { + unsigned int count = 0; + for (int x = 0; x < this->size; x++) { + HashItem *item = main_array[x]; + while (item != NULL) { + count++; + item = item->next; + } + } + return count; +} + +HashItem *SFHash::NextItem() { + if (iterate_pos >= size) { + Rewind(); + return NULL; + } + HashItem *item; + while ((item = main_array[iterate_pos]) == NULL) iterate_pos++; + for (int d = 0; d < iterate_depth; d++) { + item = item->next; + } + + if (item->next != NULL) iterate_depth++; + else { + iterate_pos++; + iterate_depth = 0; + } + return item; +} + +void SFHash::Rewind() { + iterate_pos = 0; + iterate_depth = 0; +} + +SFHash::~SFHash() { + for (int x = 0; x < size; x++) { + HashItem *item = main_array[x]; + while (item != NULL) { + HashItem *t = item->next; + delete item; + item = t; + } + } + free(main_array); +} + diff --git a/src/add-ons/translators/giftranslator/SFHash.h b/src/add-ons/translators/giftranslator/SFHash.h new file mode 100644 index 0000000000..e05f84cfbc --- /dev/null +++ b/src/add-ons/translators/giftranslator/SFHash.h @@ -0,0 +1,46 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// File: SFHash.h +// +// Date: December 1999 +// +// Author: Daniel Switkin +// +// Copyright 2003 (c) by Daniel Switkin. This file is made publically available +// under the BSD license, with the stipulations that this complete header must +// remain at the top of the file indefinitely, and credit must be given to the +// original author in any about box using this software. +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef SFHASH_H +#define SFHASH_H + +class HashItem { + friend class SFHash; + public: + unsigned int key; + private: + HashItem *next; +}; + +class SFHash { + public: + SFHash(); + SFHash(int size); + ~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; +}; + +#endif + diff --git a/src/add-ons/translators/giftranslator/SavePalette.cpp b/src/add-ons/translators/giftranslator/SavePalette.cpp new file mode 100644 index 0000000000..5125a6634f --- /dev/null +++ b/src/add-ons/translators/giftranslator/SavePalette.cpp @@ -0,0 +1,331 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// File: SavePalette.cpp +// +// Date: December 1999 +// +// Author: Daniel Switkin +// +// Copyright 2003 (c) by Daniel Switkin. This file is made publically available +// under the BSD license, with the stipulations that this complete header must +// remain at the top of the file indefinitely, and credit must be given to the +// original author in any about box using this software. +// +//////////////////////////////////////////////////////////////////////////////// + +#include "SavePalette.h" +#include +#include +#include +#include + +extern bool debug; + +const rgb_color wsp[256] = { + {0xff, 0xff, 0xff, 0xff}, {0xff, 0xff, 0xcc, 0xff}, + {0xff, 0xff, 0x99, 0xff}, {0xff, 0xff, 0x66, 0xff}, + {0xff, 0xff, 0x33, 0xff}, {0xff, 0xff, 0x00, 0xff}, + {0xff, 0xcc, 0xff, 0xff}, {0xff, 0xcc, 0xcc, 0xff}, + {0xff, 0xcc, 0x99, 0xff}, {0xff, 0xcc, 0x66, 0xff}, + {0xff, 0xcc, 0x33, 0xff}, {0xff, 0xcc, 0x00, 0xff}, + {0xff, 0x99, 0xff, 0xff}, {0xff, 0x99, 0xcc, 0xff}, + {0xff, 0x99, 0x99, 0xff}, {0xff, 0x99, 0x66, 0xff}, + {0xff, 0x99, 0x33, 0xff}, {0xff, 0x99, 0x00, 0xff}, + {0xff, 0x66, 0xff, 0xff}, {0xff, 0x66, 0xcc, 0xff}, + {0xff, 0x66, 0x99, 0xff}, {0xff, 0x66, 0x66, 0xff}, + {0xff, 0x66, 0x33, 0xff}, {0xff, 0x66, 0x00, 0xff}, + {0xff, 0x33, 0xff, 0xff}, {0xff, 0x33, 0xcc, 0xff}, + {0xff, 0x33, 0x99, 0xff}, {0xff, 0x33, 0x66, 0xff}, + {0xff, 0x33, 0x33, 0xff}, {0xff, 0x33, 0x00, 0xff}, + {0xff, 0x00, 0xff, 0xff}, {0xff, 0x00, 0xcc, 0xff}, + {0xff, 0x00, 0x99, 0xff}, {0xff, 0x00, 0x66, 0xff}, + {0xff, 0x00, 0x33, 0xff}, {0xff, 0x00, 0x00, 0xff}, + {0xcc, 0xff, 0xff, 0xff}, {0xcc, 0xff, 0xcc, 0xff}, + {0xcc, 0xff, 0x99, 0xff}, {0xcc, 0xff, 0x66, 0xff}, + {0xcc, 0xff, 0x33, 0xff}, {0xcc, 0xff, 0x00, 0xff}, + {0xcc, 0xcc, 0xff, 0xff}, {0xcc, 0xcc, 0xcc, 0xff}, + {0xcc, 0xcc, 0x99, 0xff}, {0xcc, 0xcc, 0x66, 0xff}, + {0xcc, 0xcc, 0x33, 0xff}, {0xcc, 0xcc, 0x00, 0xff}, + {0xcc, 0x99, 0xff, 0xff}, {0xcc, 0x99, 0xcc, 0xff}, + {0xcc, 0x99, 0x99, 0xff}, {0xcc, 0x99, 0x66, 0xff}, + {0xcc, 0x99, 0x33, 0xff}, {0xcc, 0x99, 0x00, 0xff}, + {0xcc, 0x66, 0xff, 0xff}, {0xcc, 0x66, 0xcc, 0xff}, + {0xcc, 0x66, 0x99, 0xff}, {0xcc, 0x66, 0x66, 0xff}, + {0xcc, 0x66, 0x33, 0xff}, {0xcc, 0x66, 0x00, 0xff}, + {0xcc, 0x33, 0xff, 0xff}, {0xcc, 0x33, 0xcc, 0xff}, + {0xcc, 0x33, 0x99, 0xff}, {0xcc, 0x33, 0x66, 0xff}, + {0xcc, 0x33, 0x33, 0xff}, {0xcc, 0x33, 0x00, 0xff}, + {0xcc, 0x00, 0xff, 0xff}, {0xcc, 0x00, 0xcc, 0xff}, + {0xcc, 0x00, 0x99, 0xff}, {0xcc, 0x00, 0x66, 0xff}, + {0xcc, 0x00, 0x33, 0xff}, {0xcc, 0x00, 0x00, 0xff}, + {0x99, 0xff, 0xff, 0xff}, {0x99, 0xff, 0xcc, 0xff}, + {0x99, 0xff, 0x99, 0xff}, {0x99, 0xff, 0x66, 0xff}, + {0x99, 0xff, 0x33, 0xff}, {0x99, 0xff, 0x00, 0xff}, + {0x99, 0xcc, 0xff, 0xff}, {0x99, 0xcc, 0xcc, 0xff}, + {0x99, 0xcc, 0x99, 0xff}, {0x99, 0xcc, 0x66, 0xff}, + {0x99, 0xcc, 0x33, 0xff}, {0x99, 0xcc, 0x00, 0xff}, + {0x99, 0x99, 0xff, 0xff}, {0x99, 0x99, 0xcc, 0xff}, + {0x99, 0x99, 0x99, 0xff}, {0x99, 0x99, 0x66, 0xff}, + {0x99, 0x99, 0x33, 0xff}, {0x99, 0x99, 0x00, 0xff}, + {0x99, 0x66, 0xff, 0xff}, {0x99, 0x66, 0xcc, 0xff}, + {0x99, 0x66, 0x99, 0xff}, {0x99, 0x66, 0x66, 0xff}, + {0x99, 0x66, 0x33, 0xff}, {0x99, 0x66, 0x00, 0xff}, + {0x99, 0x33, 0xff, 0xff}, {0x99, 0x33, 0xcc, 0xff}, + {0x99, 0x33, 0x99, 0xff}, {0x99, 0x33, 0x66, 0xff}, + {0x99, 0x33, 0x33, 0xff}, {0x99, 0x33, 0x00, 0xff}, + {0x99, 0x00, 0xff, 0xff}, {0x99, 0x00, 0xcc, 0xff}, + {0x99, 0x00, 0x99, 0xff}, {0x99, 0x00, 0x66, 0xff}, + {0x99, 0x00, 0x33, 0xff}, {0x99, 0x00, 0x00, 0xff}, + {0x66, 0xff, 0xff, 0xff}, {0x66, 0xff, 0xcc, 0xff}, + {0x66, 0xff, 0x99, 0xff}, {0x66, 0xff, 0x66, 0xff}, + {0x66, 0xff, 0x33, 0xff}, {0x66, 0xff, 0x00, 0xff}, + {0x66, 0xcc, 0xff, 0xff}, {0x66, 0xcc, 0xcc, 0xff}, + {0x66, 0xcc, 0x99, 0xff}, {0x66, 0xcc, 0x66, 0xff}, + {0x66, 0xcc, 0x33, 0xff}, {0x66, 0xcc, 0x00, 0xff}, + {0x66, 0x99, 0xff, 0xff}, {0x66, 0x99, 0xcc, 0xff}, + {0x66, 0x99, 0x99, 0xff}, {0x66, 0x99, 0x66, 0xff}, + {0x66, 0x99, 0x33, 0xff}, {0x66, 0x99, 0x00, 0xff}, + {0x66, 0x66, 0xff, 0xff}, {0x66, 0x66, 0xcc, 0xff}, + {0x66, 0x66, 0x99, 0xff}, {0x66, 0x66, 0x66, 0xff}, + {0x66, 0x66, 0x33, 0xff}, {0x66, 0x66, 0x00, 0xff}, + {0x66, 0x33, 0xff, 0xff}, {0x66, 0x33, 0xcc, 0xff}, + {0x66, 0x33, 0x99, 0xff}, {0x66, 0x33, 0x66, 0xff}, + {0x66, 0x33, 0x33, 0xff}, {0x66, 0x33, 0x00, 0xff}, + {0x66, 0x00, 0xff, 0xff}, {0x66, 0x00, 0xcc, 0xff}, + {0x66, 0x00, 0x99, 0xff}, {0x66, 0x00, 0x66, 0xff}, + {0x66, 0x00, 0x33, 0xff}, {0x66, 0x00, 0x00, 0xff}, + {0x33, 0xff, 0xff, 0xff}, {0x33, 0xff, 0xcc, 0xff}, + {0x33, 0xff, 0x99, 0xff}, {0x33, 0xff, 0x66, 0xff}, + {0x33, 0xff, 0x33, 0xff}, {0x33, 0xff, 0x00, 0xff}, + {0x33, 0xcc, 0xff, 0xff}, {0x33, 0xcc, 0xcc, 0xff}, + {0x33, 0xcc, 0x99, 0xff}, {0x33, 0xcc, 0x66, 0xff}, + {0x33, 0xcc, 0x33, 0xff}, {0x33, 0xcc, 0x00, 0xff}, + {0x33, 0x99, 0xff, 0xff}, {0x33, 0x99, 0xcc, 0xff}, + {0x33, 0x99, 0x99, 0xff}, {0x33, 0x99, 0x66, 0xff}, + {0x33, 0x99, 0x33, 0xff}, {0x33, 0x99, 0x00, 0xff}, + {0x33, 0x66, 0xff, 0xff}, {0x33, 0x66, 0xcc, 0xff}, + {0x33, 0x66, 0x99, 0xff}, {0x33, 0x66, 0x66, 0xff}, + {0x33, 0x66, 0x33, 0xff}, {0x33, 0x66, 0x00, 0xff}, + {0x33, 0x33, 0xff, 0xff}, {0x33, 0x33, 0xcc, 0xff}, + {0x33, 0x33, 0x99, 0xff}, {0x33, 0x33, 0x66, 0xff}, + {0x33, 0x33, 0x33, 0xff}, {0x33, 0x33, 0x00, 0xff}, + {0x33, 0x00, 0xff, 0xff}, {0x33, 0x00, 0xcc, 0xff}, + {0x33, 0x00, 0x99, 0xff}, {0x33, 0x00, 0x66, 0xff}, + {0x33, 0x00, 0x33, 0xff}, {0x33, 0x00, 0x00, 0xff}, + {0x00, 0xff, 0xff, 0xff}, {0x00, 0xff, 0xcc, 0xff}, + {0x00, 0xff, 0x99, 0xff}, {0x00, 0xff, 0x66, 0xff}, + {0x00, 0xff, 0x33, 0xff}, {0x00, 0xff, 0x00, 0xff}, + {0x00, 0xcc, 0xff, 0xff}, {0x00, 0xcc, 0xcc, 0xff}, + {0x00, 0xcc, 0x99, 0xff}, {0x00, 0xcc, 0x66, 0xff}, + {0x00, 0xcc, 0x33, 0xff}, {0x00, 0xcc, 0x00, 0xff}, + {0x00, 0x99, 0xff, 0xff}, {0x00, 0x99, 0xcc, 0xff}, + {0x00, 0x99, 0x99, 0xff}, {0x00, 0x99, 0x66, 0xff}, + {0x00, 0x99, 0x33, 0xff}, {0x00, 0x99, 0x00, 0xff}, + {0x00, 0x66, 0xff, 0xff}, {0x00, 0x66, 0xcc, 0xff}, + {0x00, 0x66, 0x99, 0xff}, {0x00, 0x66, 0x66, 0xff}, + {0x00, 0x66, 0x33, 0xff}, {0x00, 0x66, 0x00, 0xff}, + {0x00, 0x33, 0xff, 0xff}, {0x00, 0x33, 0xcc, 0xff}, + {0x00, 0x33, 0x99, 0xff}, {0x00, 0x33, 0x66, 0xff}, + {0x00, 0x33, 0x33, 0xff}, {0x00, 0x33, 0x00, 0xff}, + {0x00, 0x00, 0xff, 0xff}, {0x00, 0x00, 0xcc, 0xff}, + {0x00, 0x00, 0x99, 0xff}, {0x00, 0x00, 0x66, 0xff}, + {0x00, 0x00, 0x33, 0xff}, {0x00, 0x00, 0x00, 0xff}, + {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, + {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, + {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, + {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, + {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, + {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, + {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, + {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, + {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, + {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, + {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, + {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, + {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, + {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, + {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, + {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, + {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, + {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, + {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, + {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; + } + size = 256; + } +} + +SavePalette::SavePalette(BBitmap *bitmap) { + pal = new rgb_color[256]; + backgroundindex = 0; + usetransparent = false; + transparentindex = 0; + fatalerror = false; + mode = OPTIMAL_PALETTE; + + SFHash *hash = new SFHash(1 << 16); + if (hash == NULL || hash->fatalerror) { + if (debug) printf("Out of memory in SavePalette(BBitmap *)\n"); + if (hash != NULL) delete hash; + fatalerror = true; + return; + } + unsigned char r, g, b; + + color_space cs = bitmap->ColorSpace(); + if (cs != B_RGB32 && cs != B_RGBA32 && cs != B_RGB32_BIG && cs != B_RGBA32_BIG) { + if (debug) { + printf("Wrong color space given in SavePalette(BBitmap):\n"); + printf("%d %d %d %d or 0x%x\n", (cs & 0xff000000) >> 24, (cs & 0xff0000) >> 16, + (cs & 0xff00) >> 8, cs & 0xff, cs); + } + delete hash; + fatalerror = true; + return; + } + + BRect rect = bitmap->Bounds(); + int height = rect.IntegerHeight() + 1; + int width = rect.IntegerWidth() + 1; + unsigned char *bits = (unsigned char *)bitmap->Bits(); + + 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"); + delete hash; + fatalerror = true; + return; + } + hash->AddItem((HashItem *)ci); + } else { + ci->count++; + } + } + } + + 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; + + ColorItem **topcolors = (ColorItem **)malloc(size * 4); + if (topcolors == NULL) { + if (debug) printf("Out of memory in SavePalette(BBitmap *)\n"); + delete hash; + fatalerror = true; + return; + } + ColorItem *dummy = new ColorItem(0, 0); + for (int x = 0; x < size; x++) topcolors[x] = dummy; + + for (int x = 0; x < unique_colors; x++) { + 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]; + } + topcolors[y] = 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; + } + + delete dummy; + free(topcolors); + delete hash; +} + +/* Standard mapping services once a palette is loaded */ +unsigned char SavePalette::IndexForColor(unsigned char red, unsigned char green, + 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; +} + diff --git a/src/add-ons/translators/giftranslator/SavePalette.h b/src/add-ons/translators/giftranslator/SavePalette.h new file mode 100644 index 0000000000..d8200cfe49 --- /dev/null +++ b/src/add-ons/translators/giftranslator/SavePalette.h @@ -0,0 +1,60 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// File: SavePalette.h +// +// Date: December 1999 +// +// Author: Daniel Switkin +// +// Copyright 2003 (c) by Daniel Switkin. This file is made publically available +// under the BSD license, with the stipulations that this complete header must +// remain at the top of the file indefinitely, and credit must be given to the +// original author in any about box using this software. +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef SAVE_PALETTE_H +#define SAVE_PALETTE_H + +#include "SFHash.h" +#include +class BBitmap; + +enum { + WEB_SAFE_PALETTE = 0, + BEOS_SYSTEM_PALETTE, + GREYSCALE_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 { + public: + SavePalette(int predefined); + SavePalette(BBitmap *bitmap); + SavePalette(); + ~SavePalette(); + + unsigned char IndexForColor(unsigned char red, unsigned char green, + unsigned char blue); + unsigned char IndexForColor(rgb_color color); + + rgb_color *pal; + int size, size_in_bits, mode; + bool usetransparent; + int backgroundindex, transparentindex; + bool fatalerror; +}; + +#endif +