📄 gtkbitmap.cpp
字号:
/*____________________________________________________________________________
FreeAmp - The Free MP3 Player
Copyright (C) 1999 EMusic
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: GTKBitmap.cpp,v 1.15 2000/10/05 11:47:33 ijr Exp $
____________________________________________________________________________*/
#include "string"
#include "GTKBitmap.h"
#include "utility.h"
#include <gdk/gdk.h>
extern "C" {
#include <gdk/gdkx.h>
}
#include <sys/stat.h>
#include <unistd.h>
#ifdef USING_GDKPIXBUF
#include <gdk-pixbuf/gdk-pixbuf.h>
#endif
// This is basically bmp.c from xmms, although cleaned up and with a couple
// additions/fixes from imlib's bmp loader.
typedef struct tagRGBQUAD
{
guchar rgbBlue;
guchar rgbGreen;
guchar rgbRed;
guchar rgbReserved;
}
RGBQUAD;
#define BI_RGB 0
#define BI_RLE8 1
#define BI_RLE4 2
#define BI_BITFIELDS 3
GTKBitmap::GTKBitmap(string &oName)
:Bitmap(oName)
{
m_oBitmapName = oName;
shape_set = false;
m_Bitmap = NULL;
m_MaskBitmap = NULL;
gdk_threads_enter();
m_GC = gdk_gc_new(gdk_window_foreign_new(GDK_ROOT_WINDOW()));
gdk_threads_leave();
m_width = 0;
m_height = 0;
m_cache = false;
}
GTKBitmap::GTKBitmap(int iWidth, int iHeight, const string &oName)
:Bitmap(oName)
{
m_oBitmapName = oName;
shape_set = false;
gdk_threads_enter();
m_Bitmap = gdk_pixmap_new(NULL, iWidth, iHeight,
gdk_visual_get_best_depth());
m_MaskBitmap = gdk_pixmap_new(NULL, iWidth, iHeight, 1);
m_GC = gdk_gc_new(gdk_window_foreign_new(GDK_ROOT_WINDOW()));
gdk_threads_leave();
m_width = iWidth;
m_height = iHeight;
m_image = NULL;
m_cache = false;
}
GTKBitmap::~GTKBitmap(void)
{
gdk_threads_enter();
if (m_Bitmap) {
gdk_pixmap_unref(m_Bitmap);
}
m_Bitmap = NULL;
if (m_MaskBitmap)
gdk_pixmap_unref(m_MaskBitmap);
m_MaskBitmap = NULL;
if (m_GC)
gdk_gc_unref(m_GC);
m_GC = NULL;
if (m_image && m_cache)
gdk_image_destroy(m_image);
gdk_threads_leave();
}
Error GTKBitmap::ReadleShort(FILE *file, gushort *ret)
{
guchar b[2];
if (fread(b, sizeof(guchar), 2, file) != 2)
return kError_LoadBitmapFailed;
*ret = (b[1] << 8) | b[0];
return kError_NoErr;
}
Error GTKBitmap::ReadleLong(FILE *file, gulong *ret)
{
guchar b[4];
if (fread(b, sizeof(guchar), 4, file) != 4)
return kError_LoadBitmapFailed;
*ret = (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0];
return kError_NoErr;
}
Error GTKBitmap::LoadBitmapFromDisk(string &oFile)
{
struct stat statbuf;
string filename = oFile;
if (stat(filename.c_str(), &statbuf) == -1) {
filename = FindFile(filename);
if (stat(filename.c_str(), &statbuf) == -1)
return kError_LoadBitmapFailed;
}
m_image = NULL;
#ifdef USING_GDKPIXBUF
GdkPixbuf *pixbuf;
gdk_threads_enter();
pixbuf = gdk_pixbuf_new_from_file(filename.c_str());
if (pixbuf) {
GdkPixbuf *newbuf;
newbuf = gdk_pixbuf_add_alpha(pixbuf, m_bHasTransColor,
m_oTransColor.red,
m_oTransColor.green, m_oTransColor.blue);
gdk_pixbuf_render_pixmap_and_mask(newbuf, &m_Bitmap, &m_MaskBitmap,
255);
m_width = gdk_pixbuf_get_width(newbuf);
m_height = gdk_pixbuf_get_height(newbuf);
gdk_pixbuf_unref(newbuf);
gdk_pixbuf_unref(pixbuf);
gdk_threads_leave();
return kError_NoErr;
}
gdk_threads_leave();
cout << "Gdk-Pixbuf: Falling back to native loader for " << filename
<< ".\n";
#endif
FILE *file;
gchar type[2];
gulong size, offset, headSize, w, h, comp, imgsize, j, k, l;
gushort tmpShort, planes, bitcount, ncols, skip;
guchar tempchar, *data, *data_end, byte = 0, g, b, r, *buffer, *buffer_end;
register guchar *ptr, *buffer_ptr;
register gulong i;
register gushort x, y;
RGBQUAD rgbQuads[256];
gulong rmask = 0xff, gmask = 0xff, bmask = 0xff;
gulong rshift = 0, gshift = 0, bshift = 0;
size = statbuf.st_size;
file = fopen(filename.c_str(), "rb");
if (!file)
return kError_LoadBitmapFailed;
if (fread(type, 1, 2, file) != 2) {
fclose(file);
return kError_LoadBitmapFailed;
}
if (strncmp(type, "BM", 2)) {
fclose(file);
return kError_LoadBitmapFailed;
}
fseek(file, 8, SEEK_CUR);
ReadleLong(file, &offset);
ReadleLong(file, &headSize);
if (headSize == 12) {
ReadleShort(file, &tmpShort);
w = tmpShort;
ReadleShort(file, &tmpShort);
h = tmpShort;
ReadleShort(file, &planes);
ReadleShort(file, &bitcount);
imgsize = size - offset;
comp = BI_RGB;
}
else if (headSize == 40) {
ReadleLong(file, &w);
ReadleLong(file, &h);
ReadleShort(file, &planes);
ReadleShort(file, &bitcount);
ReadleLong(file, &comp);
ReadleLong(file, &imgsize);
imgsize = size - offset;
fseek(file, 16, SEEK_CUR);
}
else {
fclose(file);
return kError_LoadBitmapFailed;
}
if (bitcount < 16) {
ncols = (offset - headSize - 14);
if (headSize == 12) {
ncols /= 3;
for (i = 0; i < ncols; i++)
fread(&rgbQuads[i], 3, 1, file);
}
else {
ncols /= 4;
fread(rgbQuads, 4, ncols, file);
}
}
else if (bitcount == 16 || bitcount == 32) {
if (comp == BI_BITFIELDS) {
ReadleLong(file, &bmask);
ReadleLong(file, &gmask);
ReadleLong(file, &rmask);
for (int bit = bitcount - 1; bit >= 0; bit--) {
if (bmask & (1 << bit))
bshift = bit;
if (gmask & (1 << bit))
gshift = bit;
if (rmask & (1 << bit))
rshift = bit;
}
}
else if (bitcount == 16) {
rmask = 0x7C00;
gmask = 0x03E0;
bmask = 0x001F;
rshift = 10;
gshift = 5;
bshift = 0;
}
else if (bitcount == 32) {
rmask = 0x00FF0000;
gmask = 0x0000FF00;
bmask = 0x000000FF;
rshift = 16;
gshift = 8;
bshift = 0;
}
}
fseek(file, offset, SEEK_SET);
gdk_threads_enter();
buffer = (guchar *)g_malloc(imgsize);
if (!buffer) {
fclose(file);
gdk_threads_leave();
return kError_LoadBitmapFailed;
}
data = (guchar *)g_malloc0((w * 3 * h) + 3);
if (!data) {
fclose(file);
g_free(buffer);
gdk_threads_leave();
return kError_LoadBitmapFailed;
}
gdk_threads_leave();
fread(buffer, imgsize, 1, file);
fclose(file);
buffer_ptr = buffer;
buffer_end = buffer + imgsize;
data_end = data + (w * 3 * h);
ptr = data + ((h - 1) * w * 3);
if (bitcount == 4) {
if (comp == BI_RLE4) {
x = 0;
y = 0;
for (i = 0, g = 1; i < imgsize && g && buffer_ptr < buffer_end; i++) {
byte = *(buffer_ptr++);
if (byte) {
guchar t1, t2;
l = byte;
byte = *(buffer_ptr++);
t1 = byte & 0xF;
t2 = (byte >> 4) & 0xF;
for (j = 0; j < l; j++) {
k = (j & 1) ? t1 : t2;
if (x >= w)
break;
*ptr++ = rgbQuads[k].rgbRed;
*ptr++ = rgbQuads[k].rgbGreen;
*ptr++ = rgbQuads[k].rgbBlue;
x++;
if (ptr > data_end)
ptr = data_end;
}
}
else {
byte = *(buffer_ptr++);
switch (byte) {
case 0:
x = 0;
y++;
ptr = data + ((h - y - 1) * w * 3) + (x * 3);
if (ptr > data_end)
ptr = data_end;
break;
case 1:
g = 0;
break;
case 2:
x += *(buffer_ptr++);
y += *(buffer_ptr++);
ptr = data + ((h - y - 1) * w * 3) + (x * 3);
if (ptr > data_end)
ptr = data_end;
break;
default:
l = byte;
for (j = 0; j < l; j++) {
guchar t1 = '\0', t2 = '\0';
if ((j & 1) == 0) {
byte = *(buffer_ptr++);
t1 = byte & 0xF;
t2 = (byte >> 4) & 0xF;
}
k = (j & 1) ? t1 : t2;
if (x >= w) {
buffer_ptr += (l - j) / 2;
break;
}
*ptr++ = rgbQuads[k].rgbRed;
*ptr++ = rgbQuads[k].rgbGreen;
*ptr++ = rgbQuads[k].rgbBlue;
x++;
if (ptr > data_end)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -