mirror of
https://github.com/rupertwh/bmplib.git
synced 2026-02-04 05:35:48 +00:00
huffman: small fixes
* write correct files/image sizes to header * eol/rtc funcs in huffman.c * align rtc on byte boundary * doc update * bump version to 1.6.2
This commit is contained in:
13
API-full.md
13
API-full.md
@@ -413,20 +413,29 @@ BMP for 3- or 4-color images, call `bmpwrite_allow_2bit()` before calling
|
||||
|
||||
Indexed images may optionally be written as RLE4 or RLE8 compressed BMPs.
|
||||
Images with 16 or fewer colors can be written as either RLE4 or RLE8
|
||||
(default is RLE4), images with more than 16 colors only as RLE8.
|
||||
(default is RLE4), images with more than 16 colors only as RLE8. Images with
|
||||
only 2 colors can also be written with 1-D Huffman encoding, but only
|
||||
after explicitly allowing it by calling `bmpwrite_allow_huffman()`.
|
||||
|
||||
To activate RLE compression, call
|
||||
|
||||
```
|
||||
BMPRESULT bmpwrite_set_rle(BMPHANDLE h, BMPRLETYPE type)
|
||||
BMPRESULT bmpwrite_allow_huffman(BMPHANDLE h)
|
||||
```
|
||||
|
||||
with `type` set to one of the following values:
|
||||
- `BMP_RLE_NONE` no RLE compression, same as not calling `bmpwrite_set_rle()`
|
||||
at all
|
||||
- `BMP_RLE_AUTO` choose RLE4 or RLE8 based on number of colors in palette
|
||||
- `BMP_RLE_AUTO` choose RLE4, RLE8, or 1-D Huffman based on number of colors
|
||||
in palette
|
||||
- `BMP_RLE_RLE8` use RLE8, regardless of number of colors in palette
|
||||
|
||||
In order to write 1-D Huffman encoded bitmpas, the provided palette must have
|
||||
2 colors, rle type must be set to `BMP_RLE_AUTO`, and `bmpwrite_allow_huffman
|
||||
()` must be called. Be aware that *very* few programs will be able to read
|
||||
Huffman encoded BMPs!
|
||||
|
||||
|
||||
### top-down / bottom-up
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
Download [bmplib on github](https://github.com/rupertwh/bmplib).
|
||||
|
||||
## Current status (v1.6.1):
|
||||
## Current status (v1.6.2):
|
||||
### Reading BMP files:
|
||||
- 16/24/32 bit RGB(A) with any bits/channel combination
|
||||
(BI_RGB, BI_BITFIELDS, BI_ALPHABITFIELDS).
|
||||
@@ -37,7 +37,7 @@ Download [bmplib on github](https://github.com/rupertwh/bmplib).
|
||||
- RGB(A) 16/24/32 bit.
|
||||
- 64-bit RGBA
|
||||
- any bit-depth combination for the RGBA channels.
|
||||
- Indexed 1/2/4/8 bit, optional RLE4 and RLE8 compression.
|
||||
- Indexed 1/2/4/8 bit, optional RLE4, RLE8, and 1-D Huffman compression.
|
||||
- write BI_RGB when possible, BI_BITFIELDS only when
|
||||
necessary.
|
||||
- optional line-by-line writing of BMPs.
|
||||
@@ -86,7 +86,7 @@ Includes:
|
||||
#include <bmplib.h>
|
||||
```
|
||||
|
||||
see API.md for the API documentation
|
||||
see API-quick-start.md and API-full.md for the API documentation
|
||||
|
||||
|
||||
### 64bit BMPs
|
||||
|
||||
41
bmp-write.c
41
bmp-write.c
@@ -244,7 +244,7 @@ API BMPRESULT bmpwrite_set_palette(BMPHANDLE h, int numcolors,
|
||||
if (!s_is_setting_compatible(wp, "indexed"))
|
||||
return BMP_RESULT_ERROR;
|
||||
|
||||
if (numcolors < 1 || numcolors > 256) {
|
||||
if (numcolors < 2 || numcolors > 256) {
|
||||
logerr(wp->log, "Invalid number of colors for palette (%d)",
|
||||
numcolors);
|
||||
return BMP_RESULT_ERROR;
|
||||
@@ -607,8 +607,7 @@ static void s_decide_outformat(BMPWRITE_R wp)
|
||||
wp->rle = 8;
|
||||
wp->ih->compression = BI_RLE8;
|
||||
wp->ih->bitcount = 8;
|
||||
} else if (wp->palette->numcolors > 2 ||
|
||||
!wp->allow_huffman) {
|
||||
} else if (wp->palette->numcolors > 2 || !wp->allow_huffman) {
|
||||
wp->rle = 4;
|
||||
wp->ih->compression = BI_RLE4;
|
||||
wp->ih->bitcount = 4;
|
||||
@@ -727,9 +726,6 @@ API BMPRESULT bmpwrite_save_image(BMPHANDLE h, const unsigned char *image)
|
||||
wp->saveimage_done = TRUE;
|
||||
wp->bytes_written_before_bitdata = wp->bytes_written;
|
||||
|
||||
if (wp->ih->compression == BI_OS2_HUFFMAN)
|
||||
huff_encode(wp, -1, 0); /* leading eol */
|
||||
|
||||
linesize = (size_t) wp->width * wp->source_bytes_per_pixel;
|
||||
for (y = 0; y < wp->height; y++) {
|
||||
real_y = (wp->outorientation == BMP_ORIENT_TOPDOWN) ? y : wp->height - y - 1;
|
||||
@@ -762,14 +758,11 @@ API BMPRESULT bmpwrite_save_image(BMPHANDLE h, const unsigned char *image)
|
||||
}
|
||||
}
|
||||
else {
|
||||
huff_encode(wp, -1, 0);
|
||||
huff_encode(wp, -1, 0);
|
||||
huff_encode(wp, -1, 0);
|
||||
huff_encode(wp, -1, 0);
|
||||
huff_encode(wp, -1, 0);
|
||||
huff_flush(wp);
|
||||
if (!(huff_encode_rtc(wp) && huff_flush(wp))) {
|
||||
logsyserr(wp->log, "Writing RTC end-of-file marker");
|
||||
return BMP_RESULT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
s_try_saving_image_size(wp);
|
||||
}
|
||||
|
||||
@@ -799,8 +792,6 @@ API BMPRESULT bmpwrite_save_line(BMPHANDLE h, const unsigned char *line)
|
||||
goto abort;
|
||||
wp->bytes_written_before_bitdata = wp->bytes_written;
|
||||
wp->line_by_line = TRUE;
|
||||
if (wp->ih->compression == BI_OS2_HUFFMAN)
|
||||
huff_encode(wp, -1, 0); /* leading eol */
|
||||
}
|
||||
|
||||
switch (wp->rle) {
|
||||
@@ -830,12 +821,10 @@ API BMPRESULT bmpwrite_save_line(BMPHANDLE h, const unsigned char *line)
|
||||
goto abort;
|
||||
}
|
||||
} else {
|
||||
huff_encode(wp, -1, 0);
|
||||
huff_encode(wp, -1, 0);
|
||||
huff_encode(wp, -1, 0);
|
||||
huff_encode(wp, -1, 0);
|
||||
huff_encode(wp, -1, 0);
|
||||
huff_flush(wp);
|
||||
if (!(huff_encode_rtc(wp) && huff_flush(wp))) {
|
||||
logsyserr(wp->log, "Writing RTC end-of-file marker");
|
||||
goto abort;
|
||||
}
|
||||
}
|
||||
s_try_saving_image_size(wp);
|
||||
}
|
||||
@@ -1233,23 +1222,21 @@ abort:
|
||||
|
||||
static int s_save_line_huff(BMPWRITE_R wp, const unsigned char *line)
|
||||
{
|
||||
int x, len, total = 0;
|
||||
int x = 0, len;
|
||||
int black = FALSE;
|
||||
|
||||
x = 0;
|
||||
if (!huff_encode_eol(wp)) /* each line starts with eol */
|
||||
goto abort;
|
||||
|
||||
while (x < wp->width) {
|
||||
len = 0;
|
||||
while ((len < wp->width - x) && ((!!line[x + len]) == black))
|
||||
len++;
|
||||
if (!huff_encode(wp, len, black))
|
||||
goto abort;
|
||||
total += len;
|
||||
black = !black;
|
||||
x += len;
|
||||
}
|
||||
if (!huff_encode(wp, -1, 0)) /* eol */
|
||||
goto abort;
|
||||
|
||||
return TRUE;
|
||||
abort:
|
||||
logsyserr(wp->log, "Writing 1-D Huffman data to BMP file");
|
||||
|
||||
65
huffman.c
65
huffman.c
@@ -36,7 +36,7 @@
|
||||
|
||||
|
||||
static int s_findnode(uint32_t bits, int nbits, int black, int *found);
|
||||
|
||||
static int s_zerofill(BMPWRITE_R wp);
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
@@ -116,6 +116,11 @@ void huff_fillbuf(BMPREAD_R rp)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* s_push()
|
||||
****************************************************************************/
|
||||
|
||||
static int s_push(BMPWRITE_R wp, int bits, int nbits)
|
||||
{
|
||||
if (nbits > 32 - wp->hufbuf_len) {
|
||||
@@ -130,6 +135,10 @@ static int s_push(BMPWRITE_R wp, int bits, int nbits)
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* huff_encode()
|
||||
****************************************************************************/
|
||||
|
||||
int huff_encode(BMPWRITE_R wp, int val, int black)
|
||||
{
|
||||
const struct Huffcode *makeup, *term;
|
||||
@@ -159,6 +168,59 @@ int huff_encode(BMPWRITE_R wp, int val, int black)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* huff_encode_eol()
|
||||
****************************************************************************/
|
||||
|
||||
int huff_encode_eol(BMPWRITE_R wp)
|
||||
{
|
||||
return huff_encode(wp, -1, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* huff_encode_rtc()
|
||||
****************************************************************************/
|
||||
|
||||
int huff_encode_rtc(BMPWRITE_R wp)
|
||||
{
|
||||
if (!s_zerofill(wp))
|
||||
return FALSE;
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
if (!huff_encode_eol(wp))
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* s_zerofill()
|
||||
*
|
||||
* add fill 0s up to next byte boundary
|
||||
****************************************************************************/
|
||||
|
||||
static int s_zerofill(BMPWRITE_R wp)
|
||||
{
|
||||
int n = 8 - wp->hufbuf_len % 8;
|
||||
|
||||
if (n < 8)
|
||||
return s_push(wp, 0, n);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* huff_flush()
|
||||
****************************************************************************/
|
||||
|
||||
int huff_flush(BMPWRITE_R wp)
|
||||
{
|
||||
int byte;
|
||||
@@ -169,6 +231,7 @@ int huff_flush(BMPWRITE_R wp)
|
||||
logsyserr(wp->log, "writing Huffman bitmap");
|
||||
return FALSE;
|
||||
}
|
||||
wp->bytes_written++;
|
||||
wp->hufbuf_len -= 8;
|
||||
wp->hufbuf &= (1UL << wp->hufbuf_len) - 1;
|
||||
}
|
||||
|
||||
@@ -22,4 +22,6 @@ int huff_decode(BMPREAD_R rp, int black);
|
||||
void huff_fillbuf(BMPREAD_R rp);
|
||||
|
||||
int huff_encode(BMPWRITE_R wp, int val, int black);
|
||||
int huff_encode_eol(BMPWRITE_R wp);
|
||||
int huff_encode_rtc(BMPWRITE_R wp);
|
||||
int huff_flush(BMPWRITE_R wp);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
project('bmplib', 'c', default_options: ['c_std=c11'], version: '1.6.1')
|
||||
project('bmplib', 'c', default_options: ['c_std=c11'], version: '1.6.2')
|
||||
|
||||
cc = meson.get_compiler('c')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user