plug-ins: bmp import - overhaul

This commit is contained in:
Rupert Weber 2024-12-07 23:49:39 +00:00 committed by Alx Sa
parent b6be63eae3
commit a261fdb91b
5 changed files with 1284 additions and 768 deletions

File diff suppressed because it is too large Load diff

View file

@ -25,9 +25,7 @@
#define PLUG_IN_BINARY "file-bmp"
#define PLUG_IN_ROLE "gimp-file-bmp"
#define MAXCOLORS 256
#define BitSet(byte, bit) (((byte) & (bit)) == (bit))
#define MAXCOLORS 256
#define ReadOK(file,buffer,len) (fread(buffer, len, 1, file) != 0)
@ -36,9 +34,17 @@
#define BI_RLE8 1
#define BI_RLE4 2
#define BI_BITFIELDS 3
#define BI_ALPHABITFIELDS 4
#define BI_JPEG 4
#define BI_PNG 5
#define BI_ALPHABITFIELDS 6
#endif
/* The following two are OS/2 BMP compression methods.
* Their values (3 and 4) clash with MS values for
* BI_BITFIELDS and BI_JPEG. We make up our own distinct
* values and assign them as soon as we identify these
* methods. */
#define BI_OS2_HUFFMAN (100 + BI_BITFIELDS)
#define BI_OS2_RLE24 (100 + BI_JPEG)
typedef struct
{
@ -63,6 +69,15 @@ typedef struct
guint32 biClrUsed; /* 2E */
guint32 biClrImp; /* 32 */
guint32 masks[4]; /* 36 */
guint32 bV4CSType;
gdouble bV4Endpoints[9];
gdouble bV4GammaRed;
gdouble bV4GammaGreen;
gdouble bV4GammaBlue;
guint32 bV5Intent;
guint32 bV5ProfileData;
guint32 bV5ProfileSize;
guint32 bV5Reserved;
} BitmapHead;
typedef struct
@ -70,6 +85,7 @@ typedef struct
guint32 mask;
guint32 shiftin;
gfloat max_value;
gint nbits;
} BitmapChannel;

View file

@ -0,0 +1,209 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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 3 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, see <https://www.gnu.org/licenses/>.
*/
/* This program generates the header file "huffman.h".
* huffman.h will contain an array of Huffnode structs which make up two
* Huffman code trees for black and white pixels, respectively.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "generate-huffman.h"
#define ARR_SIZE(a) (sizeof a / sizeof a[0])
struct Node
{
int l;
int r;
int value;
int leaf;
int makeup;
};
static int nnodes = 0;
static struct Node nodebuffer[416];
static int blackroot = -1;
static int whiteroot = -1;
static void s_buildtree (void);
static void add_node (int *idx,
const char *bits,
int value,
int makeup);
static void find_empty_nodes (int idx,
int depth);
int
main (int argc, char *argv[])
{
int i;
struct Node *n = nodebuffer;
FILE *file;
if (argc == 2)
{
if (! strcmp (argv[1], "-"))
{
file = stdout;
}
else if (! (file = fopen (argv[1], "w")))
{
perror (argv[1]);
return 1;
}
}
else
{
fprintf (stderr, "Need filespec to save generated huffman header!\n");
return 1;
}
fprintf (file, "/* This file was auto-generated by\n * %s\n */\n\n", argv[0]);
s_buildtree ();
/* sanity checks */
find_empty_nodes (blackroot, 0);
find_empty_nodes (whiteroot, 0);
if (nnodes != 416)
{
fprintf (stderr, "*** have %d nodes, but should have 416.\n", nnodes);
return 1;
}
fprintf (file, "static const int blackroot = %d;\n", blackroot);
fprintf (file, "static const int whiteroot = %d;\n\n", whiteroot);
fprintf (file, "static const struct Huffnode nodebuffer[] = {\n ");
for (i = 0; i < ARR_SIZE (nodebuffer); i++)
{
if ((i + 1) % 2 == 0 && i < ARR_SIZE (nodebuffer) - 1)
{
fprintf (file, "{ %3d, %3d, %4d, %2d, %2d },\n ", n[i].l, n[i].r,
n[i].value, n[i].leaf, n[i].makeup);
}
else
{
fprintf (file, "{ %3d, %3d, %4d, %2d, %2d }, ", n[i].l, n[i].r,
n[i].value, n[i].leaf, n[i].makeup);
}
}
fprintf (file, "\n};\n");
return 0;
}
static void
s_buildtree (void)
{
int i;
memset (nodebuffer, 0, sizeof nodebuffer);
for (i = 0; i < ARR_SIZE (huff_term_black); i++)
add_node (&blackroot, huff_term_black[i].bits, huff_term_black[i].number, 0);
for (i = 0; i < ARR_SIZE (huff_makeup_black); i++)
add_node (&blackroot, huff_makeup_black[i].bits, huff_makeup_black[i].number, 1);
for (i = 0; i < ARR_SIZE (huff_term_white); i++)
add_node (&whiteroot, huff_term_white[i].bits, huff_term_white[i].number, 0);
for (i = 0; i < ARR_SIZE (huff_makeup_white); i++)
add_node (&whiteroot, huff_makeup_white[i].bits, huff_makeup_white[i].number, 1);
}
static void
add_node (int *idx, const char *bits, int value, int makeup)
{
if (*idx == -1)
{
if (nnodes >= ARR_SIZE (nodebuffer))
{
fprintf (stderr, "*** too many nodes (have %d, max is %d)\n", nnodes,
(int) ARR_SIZE (nodebuffer));
exit (1);
}
*idx = nnodes++;
nodebuffer[*idx].l = -1;
nodebuffer[*idx].r = -1;
}
if (! *bits)
{
/* we are on the final bit of the sequence */
nodebuffer[*idx].value = value;
nodebuffer[*idx].leaf = 1;
nodebuffer[*idx].makeup = makeup;
}
else
{
switch (*bits)
{
case '0':
add_node (&nodebuffer[*idx].l, bits + 1, value, makeup);
break;
case '1':
add_node (&nodebuffer[*idx].r, bits + 1, value, makeup);
break;
}
}
}
static void
find_empty_nodes (int idx, int depth)
{
static char str[30];
const struct Node *node;
if (depth >= (int) sizeof str)
{
fprintf (stderr, "*** panic!, str[] is too short\n");
exit (1);
}
str[depth] = 0;
node = &nodebuffer[idx];
if (! node->leaf)
{
if (! (node->l != -1 && node->r != -1))
{
if (node->r != -1 && ! strcmp ("0000000", str))
{
; /* ok, that's eol */
}
else
{
fprintf (stderr, "*** node %s not full. l=%d r=%d\n", str, node->l, node->r);
exit (1);
}
}
if (node->l != -1)
{
str[depth] = '0';
find_empty_nodes (node->l, depth + 1);
}
if (node->r != -1)
{
str[depth] = '1';
find_empty_nodes (node->r, depth + 1);
}
}
}

View file

@ -0,0 +1,96 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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 3 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, see <https://www.gnu.org/licenses/>.
*/
/* This header file is used by generate-huffman.c to auto-generate
* the actual "huffman.h".
*
* The bit sequences for terminating and make-up codes can be found in
* ITU-T Rec T.4:
* https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-T.4-200307-I!!PDF-E&type=items
*/
struct Huffcode
{
int number;
const char *bits;
};
/* clang-format off */
static struct Huffcode huff_term_white[] = {
{ 0, "00110101" }, { 1, "000111" }, { 2, "0111" }, { 3, "1000" },
{ 4, "1011" }, { 5, "1100" }, { 6, "1110" }, { 7, "1111" },
{ 8, "10011" }, { 9, "10100" }, { 10, "00111" }, { 11, "01000" },
{ 12, "001000" }, { 13, "000011" }, { 14, "110100" }, { 15, "110101" },
{ 16, "101010" }, { 17, "101011" }, { 18, "0100111" }, { 19, "0001100" },
{ 20, "0001000" }, { 21, "0010111" }, { 22, "0000011" }, { 23, "0000100" },
{ 24, "0101000" }, { 25, "0101011" }, { 26, "0010011" }, { 27, "0100100" },
{ 28, "0011000" }, { 29, "00000010" }, { 30, "00000011" }, { 31, "00011010" },
{ 32, "00011011" }, { 33, "00010010" }, { 34, "00010011" }, { 35, "00010100" },
{ 36, "00010101" }, { 37, "00010110" }, { 38, "00010111" }, { 39, "00101000" },
{ 40, "00101001" }, { 41, "00101010" }, { 42, "00101011" }, { 43, "00101100" },
{ 44, "00101101" }, { 45, "00000100" }, { 46, "00000101" }, { 47, "00001010" },
{ 48, "00001011" }, { 49, "01010010" }, { 50, "01010011" }, { 51, "01010100" },
{ 52, "01010101" }, { 53, "00100100" }, { 54, "00100101" }, { 55, "01011000" },
{ 56, "01011001" }, { 57, "01011010" }, { 58, "01011011" }, { 59, "01001010" },
{ 60, "01001011" }, { 61, "00110010" }, { 62, "00110011" }, { 63, "00110100" },
};
static struct Huffcode huff_term_black[] = {
{ 0, "0000110111" }, { 1, "010" }, { 2, "11" }, { 3, "10" },
{ 4, "011" }, { 5, "0011" }, { 6, "0010" }, { 7, "00011" },
{ 8, "000101" }, { 9, "000100" }, { 10, "0000100" }, { 11, "0000101" },
{ 12, "0000111" }, { 13, "00000100" }, { 14, "00000111" }, { 15, "000011000" },
{ 16, "0000010111" }, { 17, "0000011000" }, { 18, "0000001000" }, { 19, "00001100111" },
{ 20, "00001101000" }, { 21, "00001101100" }, { 22, "00000110111" }, { 23, "00000101000" },
{ 24, "00000010111" }, { 25, "00000011000" }, { 26, "000011001010" }, { 27, "000011001011" },
{ 28, "000011001100" }, { 29, "000011001101" }, { 30, "000001101000" }, { 31, "000001101001" },
{ 32, "000001101010" }, { 33, "000001101011" }, { 34, "000011010010" }, { 35, "000011010011" },
{ 36, "000011010100" }, { 37, "000011010101" }, { 38, "000011010110" }, { 39, "000011010111" },
{ 40, "000001101100" }, { 41, "000001101101" }, { 42, "000011011010" }, { 43, "000011011011" },
{ 44, "000001010100" }, { 45, "000001010101" }, { 46, "000001010110" }, { 47, "000001010111" },
{ 48, "000001100100" }, { 49, "000001100101" }, { 50, "000001010010" }, { 51, "000001010011" },
{ 52, "000000100100" }, { 53, "000000110111" }, { 54, "000000111000" }, { 55, "000000100111" },
{ 56, "000000101000" }, { 57, "000001011000" }, { 58, "000001011001" }, { 59, "000000101011" },
{ 60, "000000101100" }, { 61, "000001011010" }, { 62, "000001100110" }, { 63, "000001100111" },
};
static struct Huffcode huff_makeup_white[] = {
{ 64, "11011" }, { 128, "10010" }, { 192, "010111" }, { 256, "0110111" },
{ 320, "00110110" }, { 384, "00110111" }, { 448, "01100100" }, { 512, "01100101" },
{ 576, "01101000" }, { 640, "01100111" }, { 704, "011001100" }, { 768, "011001101" },
{ 832, "011010010" }, { 896, "011010011" }, { 960, "011010100" }, { 1024, "011010101" },
{ 1088, "011010110" }, { 1152, "011010111" }, { 1216, "011011000" }, { 1280, "011011001" },
{ 1344, "011011010" }, { 1408, "011011011" }, { 1472, "010011000" }, { 1536, "010011001" },
{ 1600, "010011010" }, { 1664, "011000" }, { 1728, "010011011" }, { 1792, "00000001000" },
{ 1856, "00000001100" }, { 1920, "00000001101" }, { 1984, "000000010010" }, { 2048, "000000010011" },
{ 2112, "000000010100" }, { 2176, "000000010101" }, { 2240, "000000010110" }, { 2304, "000000010111" },
{ 2368, "000000011100" }, { 2432, "000000011101" }, { 2496, "000000011110" }, { 2560, "000000011111" },
};
static struct Huffcode huff_makeup_black[] = {
{ 64, "0000001111" }, { 128, "000011001000" }, { 192, "000011001001" }, { 256, "000001011011" },
{ 320, "000000110011" }, { 384, "000000110100" }, { 448, "000000110101" }, { 512, "0000001101100" },
{ 576, "0000001101101" }, { 640, "0000001001010" }, { 704, "0000001001011" }, { 768, "0000001001100" },
{ 832, "0000001001101" }, { 896, "0000001110010" }, { 960, "0000001110011" }, { 1024, "0000001110100" },
{ 1088, "0000001110101" }, { 1152, "0000001110110" }, { 1216, "0000001110111" }, { 1280, "0000001010010" },
{ 1344, "0000001010011" }, { 1408, "0000001010100" }, { 1472, "0000001010101" }, { 1536, "0000001011010" },
{ 1600, "0000001011011" }, { 1664, "0000001100100" }, { 1728, "0000001100101" }, { 1792, "00000001000" },
{ 1856, "00000001100" }, { 1920, "00000001101" }, { 1984, "000000010010" }, { 2048, "000000010011" },
{ 2112, "000000010100" }, { 2176, "000000010101" }, { 2240, "000000010110" }, { 2304, "000000010111" },
{ 2368, "000000011100" }, { 2432, "000000011101" }, { 2496, "000000011110" }, { 2560, "000000011111" },
};

View file

@ -1,9 +1,19 @@
plugin_name = 'file-bmp'
gen_huffman = executable('generate-huffman',
'generate-huffman.c'
)
huffman = custom_target('huffman.h',
output: 'huffman.h',
command: [gen_huffman, '@OUTPUT@'],
)
plugin_sources = [
'bmp-load.c',
'bmp-export.c',
'bmp.c',
huffman,
]
if platform_windows