mirror of
https://github.com/rupertwh/bmplib.git
synced 2026-04-11 00:32:47 +00:00
Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
91066fc509 | ||
|
|
de7004a158 | ||
|
|
7523138fbb | ||
|
|
592605e06f | ||
|
|
eeae2205c5 | ||
|
|
2d7763de7f | ||
|
|
7513352a7b | ||
|
|
ea7b93ce64 | ||
|
|
1b3c8a1081 | ||
|
|
1ede644b71 | ||
|
|
1b9c8af659 | ||
|
|
a4800cb684 | ||
|
|
ed07c4f618 | ||
|
|
9297d88483 | ||
|
|
c0c2513c7d | ||
|
|
352a231632 | ||
|
|
72f8085c41 | ||
|
|
69f7e8baf3 | ||
|
|
7b105681f4 | ||
|
|
516944d992 | ||
|
|
4aa6c34663 | ||
|
|
bec2e3ac00 | ||
|
|
4cd1988d47 | ||
|
|
3bebc4c182 | ||
|
|
f19502f8e9 | ||
|
|
d000a25250 | ||
|
|
b723c6f6ef | ||
|
|
e8cd85b938 | ||
|
|
30495d92cf | ||
|
|
7f125a3d81 |
@@ -8,6 +8,7 @@
|
||||
BasedOnStyle: WebKit
|
||||
|
||||
SortIncludes: false
|
||||
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignArrayOfStructures: Right
|
||||
AlignConsecutiveAssignments:
|
||||
@@ -16,34 +17,47 @@ AlignConsecutiveAssignments:
|
||||
AcrossComments: true
|
||||
AlignCompound: true
|
||||
AlignFunctionPointers: false
|
||||
PadOperators: true
|
||||
AlignConsecutiveDeclarations: Consecutive
|
||||
AlignConsecutiveMacros: Consecutive
|
||||
AlignEscapedNewlines: Left
|
||||
PadOperators: false
|
||||
AlignConsecutiveBitFields: AcrossComments
|
||||
AlignConsecutiveDeclarations: AcrossComments
|
||||
AlignConsecutiveMacros: AcrossComments
|
||||
AlignConsecutiveShortCaseStatements:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: true
|
||||
AcrossComments: true
|
||||
AlignCaseColons: true
|
||||
AlignEscapedNewlines: LeftWithLastLine
|
||||
AlignOperands: Align
|
||||
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortEnumsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
BreakAfterReturnType: Automatic
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
|
||||
BitFieldColonSpacing: After
|
||||
|
||||
BreakAfterReturnType: Automatic
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Linux
|
||||
BreakBeforeTernaryOperators: false
|
||||
BreakStringLiterals: false
|
||||
IndentWidth: 8
|
||||
PointerAlignment: Right
|
||||
UseTab: ForIndentation
|
||||
|
||||
SpaceBeforeParens: ControlStatementsExceptControlMacros
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterCStyleCast: false
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
ColumnLimit: 80
|
||||
PenaltyBreakAssignment: 60
|
||||
PenaltyBreakBeforeFirstCallParameter: 100
|
||||
PenaltyBreakOpenParenthesis: 40
|
||||
PenaltyExcessCharacter: 1
|
||||
# Strings are more often longer by usage, so let's give these slightly
|
||||
# more space to breath.
|
||||
PenaltyBreakString: 60
|
||||
PenaltyReturnTypeOnItsOwnLine: 90
|
||||
|
||||
145
API-full.md
145
API-full.md
@@ -1,11 +1,11 @@
|
||||
# Rupert's bmplib -- Full API Description (v1.7.0)
|
||||
# Rupert's bmplib -- Full API Description (v1.7.5)
|
||||
|
||||
Refer to the *Quick Start Guide* (API-quick-start.md) for a quick intro to bmplib which describes only the minimal set of functions needed to read/write BMP files.
|
||||
|
||||
|
||||
## 1. Functions for reading BMP files
|
||||
|
||||
### Get a handle
|
||||
|
||||
```
|
||||
BMPHANDLE bmpread_new(FILE *file)
|
||||
```
|
||||
@@ -16,14 +16,14 @@ handle.
|
||||
|
||||
The handle cannot be reused to read multiple files.
|
||||
|
||||
|
||||
|
||||
### Read the file header
|
||||
|
||||
```
|
||||
BMPRESULT bmpread_load_info(BMPHANDLE h)
|
||||
```
|
||||
|
||||
bmplib reads the file header and checks validity. Possible return values are:
|
||||
|
||||
- `BMP_RESULT_OK`: All is good, you can proceed to read the file.
|
||||
- `BMP_INSANE`: The file is valid, but huge. The default limit is 500MB
|
||||
(relevant is the required buffer size to hold the complete image, not the
|
||||
@@ -42,8 +42,8 @@ bmplib reads the file header and checks validity. Possible return values are:
|
||||
Calling `bmpread_load_info()` is optional when you use `bmpread_dimensions()`
|
||||
(see below).
|
||||
|
||||
|
||||
### Get image dimensions
|
||||
|
||||
```
|
||||
BMPRESULT bmpread_dimensions(BMPHANDLE h,
|
||||
int *width,
|
||||
@@ -77,30 +77,32 @@ BMPORIENT bmpread_orientation(BMPHANDLE h)
|
||||
|
||||
int bmpread_resolution_xdpi(BMPHANDLE h)
|
||||
int bmpread_resolution_ydpi(BMPHANDLE h)
|
||||
|
||||
```
|
||||
|
||||
#### top-down / bottom-up
|
||||
`*orientation` is one of:
|
||||
- `BMP_ORIENT_BOTTOMUP`
|
||||
- `BMP_ORIENT_TOPDOWN`
|
||||
|
||||
`bmpread_orientation()` or the `orientation` value returned by
|
||||
`bmpread_dimensions()` **is only relevant if you load the BMP file
|
||||
line-by-line**. In line-by-line mode (using `bmpread_load_line()`), the
|
||||
image data is always delivered in the order it is in the BMP file. The
|
||||
`orientation` value will tell you if it's top-down or bottom-up. On the
|
||||
other hand, when the whole image is loaded at once (using `bmpread_load_image
|
||||
()`), bmplib will **always** return the image top-down, regardless of how
|
||||
the BMP file is oriented. The `orientation` value will still indicate the
|
||||
orientation of the original BMP.
|
||||
`*orientation` is one of:
|
||||
|
||||
- `BMP_ORIENT_BOTTOMUP`
|
||||
- `BMP_ORIENT_TOPDOWN`
|
||||
|
||||
`bmpread_orientation()` or the `orientation` value returned by
|
||||
`bmpread_dimensions()` **is only relevant if you load the BMP file
|
||||
line-by-line**. In line-by-line mode (using `bmpread_load_line()`), the
|
||||
image data is always delivered in the order it is in the BMP file. The
|
||||
`orientation` value will tell you if it's top-down or bottom-up. On the
|
||||
other hand, when the whole image is loaded at once (using `bmpread_load_image
|
||||
()`), bmplib will **always** return the image top-down, regardless of how
|
||||
the BMP file is oriented. The `orientation` value will still indicate the
|
||||
orientation of the original BMP.
|
||||
|
||||
#### Required size for buffer to receive image
|
||||
|
||||
```
|
||||
size_t bmpread_buffersize(BMPHANDLE h)
|
||||
```
|
||||
Returns the buffer size you have to allocate for the whole image.
|
||||
|
||||
Returns the buffer size you have to allocate for the whole image.
|
||||
|
||||
### Indexed BMPs
|
||||
|
||||
@@ -141,7 +143,6 @@ bmpread_load_palette(h, &palette); /* bmplib will allocate the palette
|
||||
/* or: */
|
||||
palette = malloc(4 * numcolors);
|
||||
bmpread_load_palette(h, &palette); /* bmplib will use the provided buffer */
|
||||
|
||||
```
|
||||
|
||||
Note: Once you have called `bmpread_load_palette()`, both `bmpread_load_image
|
||||
@@ -175,6 +176,7 @@ void bmpread_set_undefined(BMPHANDLE h, BMPUNDEFINED mode)
|
||||
```
|
||||
|
||||
`mode` can be one of:
|
||||
|
||||
- `BMP_UNDEFINED_LEAVE`
|
||||
- `BMP_UNDEFINED_TO_ALPHA` (default)
|
||||
|
||||
@@ -182,7 +184,6 @@ Note: If you use `bmpread_load_palette()` to switch to loading the index data
|
||||
instead of RGB data, this setting will have no effect and undefined pixels
|
||||
will always be left alone! (see above)
|
||||
|
||||
|
||||
### Optional settings for 64bit BMPs
|
||||
|
||||
```
|
||||
@@ -207,7 +208,6 @@ Options for `bmpread_set_64bit()` are:
|
||||
as they are in the BMP file, without any conversion or attempt at
|
||||
interpretation.
|
||||
|
||||
|
||||
### Setting a number format
|
||||
|
||||
By default, bmplib will always return the image data as 8-,16-, or 32-bit integer values. You can instead set the number format to floating point or fixed using:
|
||||
@@ -218,8 +218,6 @@ BMPRESULT bmp_set_number_format(BMPHANDLE h, BMPFORMAT format)
|
||||
|
||||
(see below, *3. General functions for both reading/writing BMPs*)
|
||||
|
||||
|
||||
|
||||
### Huge files: bmpread_set_insanity_limit()
|
||||
|
||||
bmplib will refuse to load images beyond a certain size (default 500MB) and
|
||||
@@ -232,8 +230,8 @@ void
|
||||
bmpread_set_insanity_limit(BMPHANDLE h, size_t limit)
|
||||
```
|
||||
|
||||
|
||||
### Load the image
|
||||
|
||||
#### bmpread_load_image()
|
||||
|
||||
```
|
||||
@@ -259,7 +257,6 @@ bmpread_load_image(h, &buffer); /* bmplib will allocate the buffer */
|
||||
/* or: */
|
||||
buffer = malloc(bmpread_buffersize(h));
|
||||
bmpread_load_image(h, &buffer); /* bmplib will use the provided buffer */
|
||||
|
||||
```
|
||||
|
||||
The image data is written to the buffer according to the returned dimensions
|
||||
@@ -273,6 +270,7 @@ the file may have been damaged or simply contains invalid image data. Image
|
||||
data is loaded anyway as far as possible and may be partially usable.
|
||||
|
||||
#### bmpread_load_line()
|
||||
|
||||
```
|
||||
BMPRESULT bmpread_load_line(BMPHANDLE h, unsigned char **pbuffer)
|
||||
```
|
||||
@@ -303,7 +301,6 @@ returned in whichever order they are stored in the BMP. Use the value
|
||||
returned by `bmpread_orientation()` to determine if it is top-down or
|
||||
bottom-up. Almost all BMPs will be bottom-up. (see above)
|
||||
|
||||
|
||||
### Invalid pixels
|
||||
|
||||
Invalid pixels may occur in indexed BMPs, both RLE and non-RLE. Invalid pixels
|
||||
@@ -316,7 +313,6 @@ In both cases, `bmpread_load_image()` and `bmpread_load_line()` will return
|
||||
BMP_RESULT_INVALID, unless the image is also truncated, then
|
||||
BMP_RESULT_TRUNCATED is returned.
|
||||
|
||||
|
||||
### Query info about the BMP file
|
||||
|
||||
Note: these functions return information about the original BMP file being
|
||||
@@ -333,7 +329,6 @@ const char* bmpread_info_compression_name(BMPHANDLE h)
|
||||
BMPRESULT bmpread_info_channel_bits(BMPHANDLE h, int *r, int *g, int *b, int *a)
|
||||
```
|
||||
|
||||
|
||||
### Release the handle
|
||||
|
||||
```
|
||||
@@ -347,17 +342,16 @@ affected**, so you can call bmp_free() immediately after `bmpread_load_image
|
||||
Note: Any error message strings returned by `bmp_errmsg()` are invalidated by
|
||||
`bmp_free()` and must not be used anymore!
|
||||
|
||||
|
||||
|
||||
|
||||
## 2. Functions for writing BMP files
|
||||
|
||||
### Get a handle
|
||||
|
||||
```
|
||||
BMPHANDLE bmpwrite_new(FILE *file)
|
||||
```
|
||||
|
||||
### Set image dimensions
|
||||
|
||||
```
|
||||
BMPRESULT bmpwrite_set_dimensions(BMPHANDLE h,
|
||||
unsigned width,
|
||||
@@ -366,7 +360,6 @@ BMPRESULT bmpwrite_set_dimensions(BMPHANDLE h,
|
||||
unsigned bitsperchannel)
|
||||
|
||||
BMPRESULT bmpwrite_set_resolution(BMPHANDLE h, int xdpi, int ydpi)
|
||||
|
||||
```
|
||||
|
||||
Note: the dimensions set with `bmpwrite_set_dimensions()` describe the source
|
||||
@@ -374,7 +367,6 @@ data that you pass to bmplib, *not* the output BMP format. Use
|
||||
`bmpwrite_set_output_bits()`, `bmpwrite_set_palette()`, and
|
||||
`bmpwrite_set_64bit()` to modify the format written to the BMP file.
|
||||
|
||||
|
||||
### Set the output format
|
||||
|
||||
Optional: set the bit-depth for each output channel. bmplib will otherwise
|
||||
@@ -415,6 +407,7 @@ BMP for 3- or 4-color images, call `bmpwrite_allow_2bit()` before calling
|
||||
```
|
||||
BMPRESULT bmpwrite_set_rle(BMPHANDLE h, BMPRLETYPE type)
|
||||
BMPRESULT bmpwrite_allow_huffman(BMPHANDLE h)
|
||||
BMPRESULT bmpwrite_set_huffman_img_fg_idx(BMPHANDLE h, int idx)
|
||||
```
|
||||
|
||||
Indexed images may optionally be written run-lenght-encoded (RLE) bitmaps.
|
||||
@@ -427,16 +420,30 @@ only after explicitly allowing it by calling `bmpwrite_allow_huffman()`
|
||||
|
||||
To activate RLE compression, call `bmpwrite_set_rle()` 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, 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!
|
||||
|
||||
#### 1-D Huffman encoding
|
||||
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!
|
||||
|
||||
In order to get the best compression result, you should also call
|
||||
`bmpwrite_set_huffman_img_fg_idx()` to specify which color index (0 or 1) in
|
||||
the image corresponds to the foreground color. Huffman compression is
|
||||
optimized for scanned text, meaning short runs of foreground color and long
|
||||
(er) runs of background color. This will not change the appearance of the
|
||||
image, but setting it correctly will result in better compression.
|
||||
|
||||
|
||||
#### RLE24
|
||||
|
||||
@@ -449,7 +456,6 @@ In order to save an image as RLE24, the data must be provided as 8 bits per
|
||||
channel RGB (no alpha channel). Call `bmpwrite_set_rle()` with type set to
|
||||
`BMP_RLE_AUTO` and also call `bmpwrite_allow_rle24()` (in any order).
|
||||
|
||||
|
||||
### top-down / bottom-up
|
||||
|
||||
By default, bmplib will write BMP files bottom-up, which is how BMP files are
|
||||
@@ -463,8 +469,9 @@ BMPRESULT bmpwrite_set_orientation(BMPHANDLE h, BMPORIENT orientation)
|
||||
```
|
||||
|
||||
with `orientation` set to one of the following values:
|
||||
- `BMPORIENT_BOTTOMUP`
|
||||
- `BMPORIENT_TOPDOWN`
|
||||
|
||||
- `BMPORIENT_BOTTOMUP`
|
||||
- `BMPORIENT_TOPDOWN`
|
||||
|
||||
Note: When writing the whole image at once using `bmpwrite_save_image()`, the
|
||||
image buffer you provide must **always** be in top-down orientation,
|
||||
@@ -474,9 +481,6 @@ When writing the image line-by-line using `bmpwrite_save_line()`, you must
|
||||
provide the image lines in the order according to the orientation you have
|
||||
chosen for the BMP file.
|
||||
|
||||
|
||||
|
||||
|
||||
### 64-bit RGBA BMPs
|
||||
|
||||
By default, bmplib will not write 64-bit BMPs because they are rather exotic and hardly any
|
||||
@@ -492,9 +496,6 @@ In order to make use of the extended range available in 64-bit BMPs (-4.0 to +3.
|
||||
|
||||
Note: 64-bit BMPs store pixel values in *linear light*. Unlike when *reading* 64-bit BMPs, bmplib will not make any gamma/linear conversion while writing BMPs. You have to provide the proper linear values in the image buffer.
|
||||
|
||||
|
||||
|
||||
|
||||
### Write the image
|
||||
|
||||
```
|
||||
@@ -517,11 +518,6 @@ Important: When writing the whole image at once using `bmpwrite_save_image
|
||||
line-by-line, the image data must be provided according to the orientation
|
||||
set with `bmpwrite_set_orientation()` (see above).
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 3. General functions for both reading/writing BMPs
|
||||
|
||||
### bmp_free()
|
||||
@@ -536,7 +532,6 @@ affected, so you can call bmp_free() immediately after bmpread_load_image
|
||||
by `bmp_errmsg()` are invalidated by `bmp_free()` and cannot be used
|
||||
anymore.
|
||||
|
||||
|
||||
### bmp_errmsg()
|
||||
|
||||
```
|
||||
@@ -547,7 +542,6 @@ Returns a zero-terminated character string containing the last error
|
||||
description(s). The returned string is safe to use until any other
|
||||
bmplib-function is called with the same handle.
|
||||
|
||||
|
||||
### bmp_set_number_format()
|
||||
|
||||
```
|
||||
@@ -562,7 +556,6 @@ sets the number format of the image buffer received from / passed to bmplib. `fo
|
||||
|
||||
For indexed images, `BMP_FORMAT_INT` is the only valid format.
|
||||
|
||||
|
||||
### bmp_version()
|
||||
|
||||
```
|
||||
@@ -571,7 +564,40 @@ const char* bmp_version(void)
|
||||
|
||||
Returns a zero-terminated character string containing the version of bmplib.
|
||||
|
||||
### bmp_set_huffman_t4black_value()
|
||||
|
||||
```
|
||||
BMPRESULT bmp_set_huffman_t4black_value(BMPHANDLE h, int blackidx)
|
||||
```
|
||||
|
||||
(not to be confused with `bmpwrite_set_huffman_img_fg_idx()`, which serves an
|
||||
entirely different purpose, see above.)
|
||||
|
||||
ITU-T T.4 defines 'black' and 'white' pixel sequences (referring to fore- and
|
||||
background, respectively), but it doesn't prescribe which of those is
|
||||
represented by 0 or 1. That would have to be defined by a BMP specification,
|
||||
but documentation on Huffman BMPs is close to non-existent.
|
||||
|
||||
Current consensus seems to be that 'black' is 1, i.e. indexing the second
|
||||
color in the palette, and 'white' is 0, i.e. indexing the first color. This
|
||||
is the default for bmplib.
|
||||
|
||||
In case that's wrong (in fact it's not even clear if there is a right and a
|
||||
wrong), `bmp_set_huffman_t4black_value()` can be used to set the pixel value
|
||||
of 'black' to either 0 or 1 (and white to the respective opposite).
|
||||
|
||||
Can be used both for reading and writing BMPs.
|
||||
|
||||
Changing this value will invert the image colors!
|
||||
|
||||
Reasons to use this function:
|
||||
|
||||
- You know that bmplib's default of 'black'=1 is wrong, and you want to set it
|
||||
to 0. (In that case, please also drop a note on github.)
|
||||
- You don't care either way, but you want to be sure to get consistent
|
||||
behaviour, in case bmplib's default is ever changed in light of new
|
||||
information/documentation.
|
||||
- You need to interface with other software that you know assumes 'black'=0.
|
||||
|
||||
|
||||
## 4. Data types and constants
|
||||
@@ -608,10 +634,10 @@ else {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
#### `BMPINFOVER`
|
||||
|
||||
Returned by `bmpread_info_header_version()`. Possible values are:
|
||||
|
||||
- `BMPINFO_CORE_OS21` BITMAPCOREHEADER aka OS21XBITMAPHEADER (12 bytes)
|
||||
- `BMPINFO_OS22` OS22XBITMAPHEADER (16/40/64 bytes)
|
||||
- `BMPINFO_V3` BITMAPINFOHEADER (40 bytes)
|
||||
@@ -627,6 +653,7 @@ from `BMPINFO_CORE_OS21` to `BMPINFO_FUTURE`.
|
||||
#### `BMPRLETYPE`
|
||||
|
||||
Used in `bmpwrite_set_rle()`. Possible values are:
|
||||
|
||||
- `BMP_RLE_NONE` No RLE
|
||||
- `BMP_RLE_AUTO` RLE4 or RLE8, chosen based on number of colors in palette
|
||||
- `BMP_RLE_RLE8` Use RLE8 for any number of colors in palette
|
||||
@@ -636,6 +663,7 @@ Can safely be cast from/to int.
|
||||
#### `BMPUNDEFINED`
|
||||
|
||||
Used in `bmpread_set_undefined()`. Possible values are:
|
||||
|
||||
- `BMP_UNDEFINED_TO_ALPHA` (default)
|
||||
- `BMP_UNDEFINED_TO_ZERO`
|
||||
|
||||
@@ -644,6 +672,7 @@ Can safely be cast from/to int.
|
||||
#### `BMPCONV64`
|
||||
|
||||
Used in `bmpread_set_64bit_conv()`. Possible values are:
|
||||
|
||||
- `BMP_CONV64_SRGB` (default)
|
||||
- `BMP_CONV64_LINEAR`
|
||||
- `BMP_CONV64_NONE`
|
||||
@@ -653,12 +682,11 @@ Can safely be cast from/to int.
|
||||
#### `BMPFORMAT`
|
||||
|
||||
Used in `bmp_set_number_format()`. Possible values are:
|
||||
|
||||
- `BMP_FORMAT_INT` (default)
|
||||
- `BMP_FORMAT_FLOAT` 32-bit floating point
|
||||
- `BMP_FORMAT_S2_13` s2.13 fixed point
|
||||
|
||||
|
||||
|
||||
## 5. Sample code
|
||||
|
||||
### Reading BMPs
|
||||
@@ -713,7 +741,6 @@ Used in `bmp_set_number_format()`. Possible values are:
|
||||
*/
|
||||
```
|
||||
|
||||
|
||||
### Writing BMPs
|
||||
|
||||
```
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
Download [bmplib on github](https://github.com/rupertwh/bmplib).
|
||||
|
||||
## Current status (v1.7.0):
|
||||
## Current status (v1.7.5):
|
||||
### Reading BMP files:
|
||||
- 16/24/32 bit RGB(A) with any bits/channel combination
|
||||
(BI_RGB, BI_BITFIELDS, BI_ALPHABITFIELDS).
|
||||
|
||||
208
bmp-common.c
208
bmp-common.c
@@ -23,6 +23,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define BMPLIB_LIB
|
||||
|
||||
@@ -35,13 +36,6 @@
|
||||
#include "bmp-write.h"
|
||||
|
||||
|
||||
struct Bmphandle {
|
||||
struct {
|
||||
uint32_t magic;
|
||||
LOG log;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
/********************************************************
|
||||
@@ -61,10 +55,10 @@ API const char* bmp_version(void)
|
||||
|
||||
API const char* bmp_errmsg(BMPHANDLE h)
|
||||
{
|
||||
if (!(h && (h->magic == HMAGIC_READ || h->magic == HMAGIC_WRITE)))
|
||||
if (!(h && (h->common.magic == HMAGIC_READ || h->common.magic == HMAGIC_WRITE)))
|
||||
return "BMPHANDLE is NULL or invalid";
|
||||
|
||||
return logmsg(h->log);
|
||||
return logmsg(h->common.log);
|
||||
}
|
||||
|
||||
|
||||
@@ -78,17 +72,17 @@ API BMPRESULT bmp_set_number_format(BMPHANDLE h, enum BmpFormat format)
|
||||
if (!h)
|
||||
return BMP_RESULT_ERROR;
|
||||
|
||||
switch (h->magic) {
|
||||
switch (h->common.magic) {
|
||||
case HMAGIC_READ:
|
||||
return br_set_number_format((BMPREAD)(void*)h, format);
|
||||
return br_set_number_format(&h->read, format);
|
||||
|
||||
case HMAGIC_WRITE:
|
||||
return bw_set_number_format((BMPWRITE)(void*)h, format);
|
||||
return bw_set_number_format(&h->write, format);
|
||||
|
||||
default:
|
||||
#ifdef DEBUG
|
||||
printf("bmp_set_number_format() called with invalid handle (0x%04x)\n",
|
||||
(unsigned int) h->magic);
|
||||
(unsigned int) h->common.magic);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@@ -97,6 +91,25 @@ API BMPRESULT bmp_set_number_format(BMPHANDLE h, enum BmpFormat format)
|
||||
|
||||
|
||||
|
||||
/********************************************************
|
||||
* bmp_set_huffman_t4black_value
|
||||
*******************************************************/
|
||||
|
||||
API BMPRESULT bmp_set_huffman_t4black_value(BMPHANDLE h, int blackidx)
|
||||
{
|
||||
if (!h)
|
||||
return BMP_RESULT_ERROR;
|
||||
|
||||
if (!(h->common.magic == HMAGIC_READ || h->common.magic == HMAGIC_WRITE))
|
||||
return BMP_RESULT_ERROR;
|
||||
|
||||
h->common.huffman_black_is_zero = !blackidx;
|
||||
|
||||
return BMP_RESULT_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************************************
|
||||
* bmp_free
|
||||
*******************************************************/
|
||||
@@ -106,18 +119,18 @@ API void bmp_free(BMPHANDLE h)
|
||||
if (!h)
|
||||
return;
|
||||
|
||||
switch (h->magic) {
|
||||
switch (h->common.magic) {
|
||||
case HMAGIC_READ:
|
||||
br_free((BMPREAD)(void*)h);
|
||||
br_free(&h->read);
|
||||
break;
|
||||
case HMAGIC_WRITE:
|
||||
bw_free((BMPWRITE)(void*)h);
|
||||
bw_free(&h->write);
|
||||
break;
|
||||
|
||||
default:
|
||||
#ifdef DEBUG
|
||||
printf("bmp_free() called with invalid handle (0x%04x)\n",
|
||||
(unsigned int) h->magic);
|
||||
(unsigned int) h->common.magic);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@@ -126,30 +139,28 @@ API void bmp_free(BMPHANDLE h)
|
||||
|
||||
|
||||
/********************************************************
|
||||
* cm_check_is_read_handle
|
||||
* cm_read_handle
|
||||
*******************************************************/
|
||||
|
||||
int cm_check_is_read_handle(BMPHANDLE h)
|
||||
BMPREAD cm_read_handle(BMPHANDLE h)
|
||||
{
|
||||
BMPREAD rp = (BMPREAD)(void*)h;
|
||||
if (h && h->common.magic == HMAGIC_READ)
|
||||
return &h->read;
|
||||
|
||||
if (rp && rp->magic == HMAGIC_READ)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************
|
||||
* bm_check_is_write_handle
|
||||
* cm_write_handle
|
||||
*******************************************************/
|
||||
|
||||
int cm_check_is_write_handle(BMPHANDLE h)
|
||||
BMPWRITE cm_write_handle(BMPHANDLE h)
|
||||
{
|
||||
BMPWRITE wp = (BMPWRITE)(void*)h;
|
||||
if (h && h->common.magic == HMAGIC_WRITE)
|
||||
return &h->write;
|
||||
|
||||
if (wp && wp->magic == HMAGIC_WRITE)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -157,7 +168,7 @@ int cm_check_is_write_handle(BMPHANDLE h)
|
||||
* cm_gobble_up
|
||||
*******************************************************/
|
||||
|
||||
int cm_gobble_up(BMPREAD_R rp, int count)
|
||||
bool cm_gobble_up(BMPREAD_R rp, int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -165,15 +176,15 @@ int cm_gobble_up(BMPREAD_R rp, int count)
|
||||
if (EOF == getc(rp->file)) {
|
||||
if (feof(rp->file)) {
|
||||
rp->lasterr = BMP_ERR_TRUNCATED;
|
||||
logerr(rp->log, "unexpected end of file");
|
||||
logerr(rp->c.log, "unexpected end of file");
|
||||
} else {
|
||||
rp->lasterr = BMP_ERR_FILEIO;
|
||||
logsyserr(rp->log, "error reading from file");
|
||||
logsyserr(rp->c.log, "error reading from file");
|
||||
}
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -220,18 +231,19 @@ const char* cm_format_name(enum BmpFormat format)
|
||||
|
||||
|
||||
|
||||
int cm_all_lessoreq_int(int limit, int n, ...)
|
||||
bool cm_all_lessoreq_int(int limit, int n, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int i, ret = TRUE;
|
||||
int i;
|
||||
bool ret = true;
|
||||
|
||||
if (n < 1)
|
||||
return TRUE;
|
||||
return true;
|
||||
|
||||
va_start(ap, n);
|
||||
for (i = 0; i < n; i++) {
|
||||
if (va_arg(ap, int) > limit) {
|
||||
ret = FALSE;
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -241,19 +253,20 @@ int cm_all_lessoreq_int(int limit, int n, ...)
|
||||
}
|
||||
|
||||
|
||||
int cm_all_equal_int(int n, ...)
|
||||
bool cm_all_equal_int(int n, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int first, i, ret = TRUE;
|
||||
int first, i;
|
||||
bool ret = true;
|
||||
|
||||
if (n < 2)
|
||||
return TRUE;
|
||||
return true;
|
||||
|
||||
va_start(ap, n);
|
||||
first = va_arg(ap, int);
|
||||
for (i = 1; i < n; i++) {
|
||||
if (va_arg(ap, int) != first) {
|
||||
ret = FALSE;
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -263,18 +276,19 @@ int cm_all_equal_int(int n, ...)
|
||||
}
|
||||
|
||||
|
||||
int cm_all_positive_int(int n, ...)
|
||||
bool cm_all_positive_int(int n, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int i, ret = TRUE;
|
||||
int i;
|
||||
bool ret = true;
|
||||
|
||||
if (n < 1)
|
||||
return TRUE;
|
||||
return true;
|
||||
|
||||
va_start(ap, n);
|
||||
for (i = 0; i < n; i++) {
|
||||
if (va_arg(ap, int) < 0) {
|
||||
ret = FALSE;
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -284,18 +298,19 @@ int cm_all_positive_int(int n, ...)
|
||||
}
|
||||
|
||||
|
||||
int cm_is_one_of(int n, int candidate, ...)
|
||||
bool cm_is_one_of(int n, int candidate, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int i, ret = FALSE;
|
||||
int i;
|
||||
bool ret = false;
|
||||
|
||||
if (n < 1)
|
||||
return TRUE;
|
||||
return true;
|
||||
|
||||
va_start(ap, candidate);
|
||||
for (i = 0; i < n; i++) {
|
||||
if (va_arg(ap, int) == candidate) {
|
||||
ret = TRUE;
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -323,91 +338,106 @@ int cm_align2padding(unsigned long long a)
|
||||
* from little-endian files
|
||||
*********************************************************/
|
||||
|
||||
int write_u16_le(FILE *file, uint16_t val)
|
||||
bool write_u16_le(FILE *file, uint16_t val)
|
||||
{
|
||||
return (EOF != fputc(val & 0xff, file) &&
|
||||
EOF != fputc((val >> 8) & 0xff, file));
|
||||
}
|
||||
|
||||
|
||||
int write_u32_le(FILE *file, uint32_t val)
|
||||
bool write_u32_le(FILE *file, uint32_t val)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (EOF == fputc((val >> (i*8)) & 0xff, file))
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int read_u16_le(FILE *file, uint16_t *val)
|
||||
bool read_u16_le(FILE *file, uint16_t *val)
|
||||
{
|
||||
unsigned char buf[2];
|
||||
|
||||
if (2 != fread(buf, 1, 2, file))
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
*val = (buf[1] << 8) | buf[0];
|
||||
*val = ((unsigned)buf[1] << 8) | (unsigned)buf[0];
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int read_u32_le(FILE *file, uint32_t *val)
|
||||
bool read_u32_le(FILE *file, uint32_t *val)
|
||||
{
|
||||
unsigned char buf[4];
|
||||
|
||||
if (4 != fread(buf, 1, 4, file))
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
*val = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
|
||||
*val = ((uint32_t)buf[3] << 24) | ((uint32_t)buf[2] << 16) |
|
||||
((uint32_t)buf[1] << 8) | (uint32_t)buf[0];
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int write_s16_le(FILE *file, int16_t val)
|
||||
bool write_s16_le(FILE *file, int16_t val)
|
||||
{
|
||||
return (EOF != fputc(val & 0xff, file) &&
|
||||
EOF != fputc((val >> 8) & 0xff, file));
|
||||
return write_u16_le(file, (uint16_t)val);
|
||||
}
|
||||
|
||||
|
||||
int read_s16_le(FILE *file, int16_t *val)
|
||||
bool write_s32_le(FILE *file, int32_t val)
|
||||
{
|
||||
unsigned char buf[2];
|
||||
|
||||
if (2 != fread(buf, 1, 2, file))
|
||||
return 0;
|
||||
|
||||
*val = (((int16_t)(signed char)buf[1]) << 8) | (int16_t) buf[0];
|
||||
|
||||
return 1;
|
||||
return write_u32_le(file, (uint32_t)val);
|
||||
}
|
||||
|
||||
|
||||
int read_s32_le(FILE *file, int32_t *val)
|
||||
bool read_s16_le(FILE *file, int16_t *val)
|
||||
{
|
||||
unsigned char buf[4];
|
||||
uint16_t u16;
|
||||
|
||||
if (4 != fread(buf, 1, 4, file))
|
||||
return 0;
|
||||
if (!read_u16_le(file, &u16))
|
||||
return false;
|
||||
|
||||
*val = (((int32_t)(signed char)buf[3]) << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
|
||||
*val = (int16_t)u16;
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int write_s32_le(FILE *file, int32_t val)
|
||||
bool read_s32_le(FILE *file, int32_t *val)
|
||||
{
|
||||
int i;
|
||||
uint32_t u32;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (EOF == fputc((val >> (i*8)) & 0xff, file))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
if (!read_u32_le(file, &u32))
|
||||
return false;
|
||||
|
||||
*val = (int32_t)u32;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint32_t u32_from_le(const unsigned char *buf)
|
||||
{
|
||||
return (uint32_t)buf[3] << 24 | (uint32_t)buf[2] << 16 |
|
||||
(uint32_t)buf[1] << 8 | (uint32_t)buf[0];
|
||||
}
|
||||
|
||||
int32_t s32_from_le(const unsigned char *buf)
|
||||
{
|
||||
return (int32_t)u32_from_le(buf);
|
||||
}
|
||||
|
||||
uint16_t u16_from_le(const unsigned char *buf)
|
||||
{
|
||||
return (uint16_t)buf[1] << 8 | (uint16_t)buf[0];
|
||||
}
|
||||
|
||||
int16_t s16_from_le(const unsigned char *buf)
|
||||
{
|
||||
return (int16_t)u16_from_le(buf);
|
||||
}
|
||||
|
||||
281
bmp-common.h
281
bmp-common.h
@@ -18,12 +18,6 @@
|
||||
* If not, see <https://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#undef TRUE
|
||||
#define TRUE (1)
|
||||
|
||||
#undef FALSE
|
||||
#define FALSE (0)
|
||||
|
||||
#undef MAX
|
||||
#undef MIN
|
||||
#define MAX(a,b) ((a)>(b)?(a):(b))
|
||||
@@ -32,15 +26,12 @@
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define ATTR_CONST __attribute__((const))
|
||||
#define API __attribute__ ((visibility ("default")))
|
||||
#else
|
||||
#define ATTR_CONST
|
||||
#define API
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#define API
|
||||
#else
|
||||
#define API __attribute__ ((visibility ("default")))
|
||||
#endif
|
||||
|
||||
union Pixel {
|
||||
unsigned int value[4];
|
||||
@@ -91,82 +82,80 @@ struct Colormask {
|
||||
} maxval;
|
||||
};
|
||||
|
||||
typedef struct Bmpread *BMPREAD;
|
||||
typedef struct Bmpwrite *BMPWRITE;
|
||||
typedef struct Bmpread * restrict BMPREAD_R;
|
||||
typedef struct Bmpwrite * restrict BMPWRITE_R;
|
||||
|
||||
struct Palette {
|
||||
int numcolors;
|
||||
union Pixel color[1];
|
||||
};
|
||||
|
||||
|
||||
struct Bmpcommon {
|
||||
uint32_t magic;
|
||||
LOG log;
|
||||
bool huffman_black_is_zero; /* defaults to false */
|
||||
};
|
||||
|
||||
|
||||
struct Bmpread {
|
||||
struct {
|
||||
uint32_t magic;
|
||||
LOG log;
|
||||
};
|
||||
struct Bmpcommon c;
|
||||
FILE *file;
|
||||
size_t bytes_read; /* number of bytes we have read from the file */
|
||||
struct Bmpfile *fh;
|
||||
struct Bmpinfo *ih;
|
||||
unsigned int insanity_limit;
|
||||
int width;
|
||||
unsigned height;
|
||||
int height;
|
||||
enum BmpOrient orientation;
|
||||
int has_alpha; /* original BMP has alpha channel */
|
||||
bool has_alpha; /* original BMP has alpha channel */
|
||||
enum BmpUndefined undefined_mode;
|
||||
int we_allocated_buffer;
|
||||
int line_by_line;
|
||||
bool we_allocated_buffer;
|
||||
bool line_by_line;
|
||||
struct Palette *palette;
|
||||
struct Colormask cmask;
|
||||
/* result image dimensions */
|
||||
enum Bmpconv64 conv64;
|
||||
int conv64_explicit;
|
||||
bool conv64_explicit;
|
||||
int result_channels;
|
||||
int result_indexed;
|
||||
bool result_indexed;
|
||||
int result_bits_per_pixel;
|
||||
int result_bytes_per_pixel;
|
||||
int result_bitsperchannel;
|
||||
enum BmpFormat result_format;
|
||||
int result_format_explicit;
|
||||
bool result_format_explicit;
|
||||
size_t result_size;
|
||||
/* state */
|
||||
unsigned long lasterr;
|
||||
int getinfo_called;
|
||||
bool getinfo_called;
|
||||
int getinfo_return;
|
||||
int jpeg;
|
||||
int png;
|
||||
int dimensions_queried;
|
||||
int dim_queried_width;
|
||||
int dim_queried_height;
|
||||
int dim_queried_channels;
|
||||
int dim_queried_bitsperchannel;
|
||||
int image_loaded;
|
||||
int rle;
|
||||
int rle_eol;
|
||||
int rle_eof;
|
||||
bool jpeg;
|
||||
bool png;
|
||||
bool dimensions_queried;
|
||||
bool dim_queried_width;
|
||||
bool dim_queried_height;
|
||||
bool dim_queried_channels;
|
||||
bool dim_queried_bitsperchannel;
|
||||
bool image_loaded;
|
||||
bool rle;
|
||||
bool rle_eol;
|
||||
bool rle_eof;
|
||||
int lbl_x; /* remember where we are in the image */
|
||||
int lbl_y; /* for line by line reading */
|
||||
int lbl_file_y; /* RLE files may be ahead of the image y */
|
||||
uint32_t hufbuf;
|
||||
int hufbuf_len;
|
||||
int truncated;
|
||||
int invalid_index;
|
||||
int invalid_delta;
|
||||
int invalid_overrun;
|
||||
int file_err;
|
||||
int file_eof;
|
||||
int panic;
|
||||
bool truncated;
|
||||
bool invalid_index;
|
||||
bool invalid_delta;
|
||||
bool invalid_overrun;
|
||||
bool file_err;
|
||||
bool file_eof;
|
||||
bool panic;
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct Bmpwrite {
|
||||
struct {
|
||||
uint32_t magic;
|
||||
LOG log;
|
||||
};
|
||||
struct Bmpcommon c;
|
||||
FILE *file;
|
||||
struct Bmpfile *fh;
|
||||
struct Bmpinfo *ih;
|
||||
@@ -176,41 +165,56 @@ struct Bmpwrite {
|
||||
int source_channels;
|
||||
int source_bitsperchannel;
|
||||
int source_bytes_per_pixel;
|
||||
int source_format;
|
||||
enum BmpFormat source_format;
|
||||
struct Palette *palette;
|
||||
int palette_size; /* sizeof palette in bytes */
|
||||
unsigned char *iccprofile;
|
||||
int iccprofile_size;
|
||||
/* output */
|
||||
size_t bytes_written;
|
||||
size_t bytes_written_before_bitdata;
|
||||
int has_alpha;
|
||||
bool has_alpha;
|
||||
enum BmpOrient outorientation;
|
||||
bool huffman_fg_idx;
|
||||
struct Colormask cmask;
|
||||
int rle_requested;
|
||||
int rle;
|
||||
int allow_2bit; /* Windows CE, but many will not read it */
|
||||
int allow_huffman;
|
||||
int allow_rle24;
|
||||
int out64bit;
|
||||
enum BmpRLEtype rle_requested;
|
||||
int rle; /* 1, 4, or 8 */
|
||||
bool allow_2bit; /* Windows CE, but many will not read it */
|
||||
bool allow_huffman;
|
||||
bool allow_rle24;
|
||||
bool out64bit;
|
||||
int outbytes_per_pixel;
|
||||
int padding;
|
||||
int *group;
|
||||
int group_count;
|
||||
/* state */
|
||||
int outbits_set;
|
||||
int dimensions_set;
|
||||
int saveimage_done;
|
||||
int line_by_line;
|
||||
bool outbits_set;
|
||||
bool dimensions_set;
|
||||
bool saveimage_done;
|
||||
bool line_by_line;
|
||||
int lbl_y;
|
||||
uint32_t hufbuf;
|
||||
int hufbuf_len;
|
||||
};
|
||||
|
||||
|
||||
union Bmphandle {
|
||||
struct Bmpcommon common;
|
||||
struct Bmpread read;
|
||||
struct Bmpwrite write;
|
||||
};
|
||||
|
||||
int cm_all_lessoreq_int(int limit, int n, ...);
|
||||
int cm_all_equal_int(int n, ...);
|
||||
int cm_all_positive_int(int n, ...);
|
||||
int cm_is_one_of(int n, int candidate, ...);
|
||||
|
||||
typedef struct Bmpread *BMPREAD;
|
||||
typedef struct Bmpwrite *BMPWRITE;
|
||||
typedef struct Bmpread *restrict BMPREAD_R;
|
||||
typedef struct Bmpwrite *restrict BMPWRITE_R;
|
||||
|
||||
|
||||
bool cm_all_lessoreq_int(int limit, int n, ...);
|
||||
bool cm_all_equal_int(int n, ...);
|
||||
bool cm_all_positive_int(int n, ...);
|
||||
bool cm_is_one_of(int n, int candidate, ...);
|
||||
|
||||
#define cm_align4size(a) ((((a) + 3) >> 2) << 2)
|
||||
#define cm_align2size(a) ((((a) + 1) >> 1) << 1)
|
||||
@@ -218,23 +222,27 @@ int cm_align4padding(unsigned long long a);
|
||||
int cm_align2padding(unsigned long long a);
|
||||
int cm_count_bits(unsigned long v);
|
||||
|
||||
int cm_gobble_up(BMPREAD_R rp, int count);
|
||||
int cm_check_is_read_handle(BMPHANDLE h);
|
||||
int cm_check_is_write_handle(BMPHANDLE h);
|
||||
bool cm_gobble_up(BMPREAD_R rp, int count);
|
||||
BMPREAD cm_read_handle(BMPHANDLE h);
|
||||
BMPWRITE cm_write_handle(BMPHANDLE h);
|
||||
|
||||
const char* cm_conv64_name(enum Bmpconv64 conv);
|
||||
const char* cm_format_name(enum BmpFormat format);
|
||||
|
||||
int write_u16_le(FILE *file, uint16_t val);
|
||||
int write_u32_le(FILE *file, uint32_t val);
|
||||
int read_u16_le(FILE *file, uint16_t *val);
|
||||
int read_u32_le(FILE *file, uint32_t *val);
|
||||
bool write_u16_le(FILE *file, uint16_t val);
|
||||
bool write_u32_le(FILE *file, uint32_t val);
|
||||
bool read_u16_le(FILE *file, uint16_t *val);
|
||||
bool read_u32_le(FILE *file, uint32_t *val);
|
||||
|
||||
int write_s16_le(FILE *file, int16_t val);
|
||||
int write_s32_le(FILE *file, int32_t val);
|
||||
int read_s16_le(FILE *file, int16_t *val);
|
||||
int read_s32_le(FILE *file, int32_t *val);
|
||||
bool write_s16_le(FILE *file, int16_t val);
|
||||
bool write_s32_le(FILE *file, int32_t val);
|
||||
bool read_s16_le(FILE *file, int16_t *val);
|
||||
bool read_s32_le(FILE *file, int32_t *val);
|
||||
|
||||
uint32_t u32_from_le(const unsigned char *buf);
|
||||
int32_t s32_from_le(const unsigned char *buf);
|
||||
uint16_t u16_from_le(const unsigned char *buf);
|
||||
int16_t s16_from_le(const unsigned char *buf);
|
||||
|
||||
|
||||
#define HMAGIC_READ 0x44414552UL
|
||||
@@ -248,75 +256,73 @@ int read_s32_le(FILE *file, int32_t *val);
|
||||
#define BMPFILE_PT 0x5450
|
||||
|
||||
|
||||
#define BMPFHSIZE 14
|
||||
#define BMPIHSIZE_V3 40
|
||||
#define BMPIHSIZE_V4 108
|
||||
#define BMPIHSIZE_OS22 64
|
||||
|
||||
typedef uint16_t WORD;
|
||||
typedef uint32_t DWORD;
|
||||
typedef int32_t LONG;
|
||||
typedef uint8_t BYTE;
|
||||
#define BMPFHSIZE 14
|
||||
#define BMPIHSIZE_V3 40
|
||||
#define BMPIHSIZE_V4 108
|
||||
#define BMPIHSIZE_OS22 64
|
||||
#define BMPIHSIZE_V5 124
|
||||
|
||||
struct Bmpfile {
|
||||
WORD type; /* "BM" */
|
||||
DWORD size; /* bytes in file */
|
||||
WORD reserved1;
|
||||
WORD reserved2;
|
||||
DWORD offbits;
|
||||
uint16_t type; /* "BM" */
|
||||
uint32_t size; /* bytes in file */
|
||||
uint16_t reserved1;
|
||||
uint16_t reserved2;
|
||||
uint32_t offbits;
|
||||
};
|
||||
|
||||
struct Bmpinfo {
|
||||
/* BITMAPINFOHEADER (40 bytes) */
|
||||
DWORD size; /* sizof struct */
|
||||
LONG width;
|
||||
LONG height;
|
||||
WORD planes;
|
||||
WORD bitcount;
|
||||
DWORD compression;
|
||||
DWORD sizeimage; /* 0 ok for uncompressed */
|
||||
LONG xpelspermeter;
|
||||
LONG ypelspermeter;
|
||||
DWORD clrused;
|
||||
DWORD clrimportant;
|
||||
uint32_t size; /* sizof struct */
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
uint16_t planes;
|
||||
uint16_t bitcount;
|
||||
uint32_t compression;
|
||||
uint32_t sizeimage; /* 0 ok for uncompressed */
|
||||
int32_t xpelspermeter;
|
||||
int32_t ypelspermeter;
|
||||
uint32_t clrused;
|
||||
uint32_t clrimportant;
|
||||
/* BITMAPV4INFOHEADER (108 bytes) */
|
||||
DWORD redmask;
|
||||
DWORD greenmask;
|
||||
DWORD bluemask;
|
||||
DWORD alphamask;
|
||||
DWORD cstype;
|
||||
LONG redX;
|
||||
LONG redY;
|
||||
LONG redZ;
|
||||
LONG greenX;
|
||||
LONG greenY;
|
||||
LONG greenZ;
|
||||
LONG blueX;
|
||||
LONG blueY;
|
||||
LONG blueZ;
|
||||
DWORD gammared;
|
||||
DWORD gammagreen;
|
||||
DWORD gammablue;
|
||||
uint32_t redmask;
|
||||
uint32_t greenmask;
|
||||
uint32_t bluemask;
|
||||
uint32_t alphamask;
|
||||
uint32_t cstype;
|
||||
int32_t redX;
|
||||
int32_t redY;
|
||||
int32_t redZ;
|
||||
int32_t greenX;
|
||||
int32_t greenY;
|
||||
int32_t greenZ;
|
||||
int32_t blueX;
|
||||
int32_t blueY;
|
||||
int32_t blueZ;
|
||||
uint32_t gammared;
|
||||
uint32_t gammagreen;
|
||||
uint32_t gammablue;
|
||||
/* BITMAPV5INFOHEADER (124 bytes) */
|
||||
DWORD intent;
|
||||
DWORD profiledata;
|
||||
DWORD profilesize;
|
||||
DWORD reserved;
|
||||
uint32_t intent;
|
||||
uint32_t profiledata;
|
||||
uint32_t profilesize;
|
||||
uint32_t reserved;
|
||||
|
||||
/* OS22XBITMAPHEADER */
|
||||
WORD resolution; /* = 0 */
|
||||
WORD orientation; /* = 0 */
|
||||
WORD halftone_alg;
|
||||
DWORD halftone_parm1;
|
||||
DWORD halftone_parm2;
|
||||
DWORD color_encoding; /* = 0 (RGB) */
|
||||
DWORD app_id;
|
||||
uint16_t resolution; /* = 0 */
|
||||
uint16_t orientation; /* = 0 */
|
||||
uint16_t halftone_alg;
|
||||
uint32_t halftone_parm1;
|
||||
uint32_t halftone_parm2;
|
||||
uint32_t color_encoding; /* = 0 (RGB) */
|
||||
uint32_t app_id;
|
||||
|
||||
/* internal only, not from file: */
|
||||
enum BmpInfoVer version;
|
||||
/* internal only, not from file: */
|
||||
enum BmpInfoVer version;
|
||||
};
|
||||
|
||||
#define IH_PROFILEDATA_OFFSET (14L + 112L)
|
||||
|
||||
#define MAX_ICCPROFILE_SIZE (1UL << 20)
|
||||
|
||||
|
||||
#define BI_RGB 0
|
||||
@@ -336,3 +342,16 @@ struct Bmpinfo {
|
||||
/* we set our own unique values: */
|
||||
#define BI_OS2_HUFFMAN 1001
|
||||
#define BI_OS2_RLE24 1002
|
||||
|
||||
|
||||
#define LCS_CALIBRATED_RGB 0
|
||||
#define LCS_sRGB 0x73524742 /* 'sRGB' */
|
||||
#define LCS_WINDOWS_COLOR_SPACE 0x57696e20 /* 'Win ' */
|
||||
#define PROFILE_LINKED 0x4c494e4b /* 'LINK' */
|
||||
#define PROFILE_EMBEDDED 0x4d424544 /* 'MBED' */
|
||||
|
||||
|
||||
#define LCS_GM_ABS_COLORIMETRIC 8
|
||||
#define LCS_GM_BUSINESS 1
|
||||
#define LCS_GM_GRAPHICS 2
|
||||
#define LCS_GM_IMAGES 3
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#define BMPLIB_LIB
|
||||
@@ -32,7 +34,6 @@
|
||||
#include "bmp-common.h"
|
||||
#include "huffman.h"
|
||||
#include "bmp-read.h"
|
||||
#include "reversebits.h"
|
||||
|
||||
|
||||
/*
|
||||
@@ -61,13 +62,13 @@
|
||||
static inline unsigned long s_scaleint(unsigned long val, int frombits, int tobits) ATTR_CONST;
|
||||
static void s_set_file_error(BMPREAD_R rp);
|
||||
static void s_log_error_from_state(BMPREAD_R rp);
|
||||
static int s_cont_error(BMPREAD_R rp);
|
||||
static int s_stopping_error(BMPREAD_R rp);
|
||||
static bool s_cont_error(BMPREAD_R rp);
|
||||
static bool s_stopping_error(BMPREAD_R rp);
|
||||
static inline int s_read_one_byte(BMPREAD_R rp);
|
||||
static inline void s_int_to_result_format(BMPREAD_R rp, int frombits, unsigned char *restrict px);
|
||||
|
||||
static BMPRESULT s_load_image_or_line(BMPREAD_R rp, unsigned char **restrict buffer, int line_by_line);
|
||||
static int s_read_rgb_line(BMPREAD_R rp, unsigned char *restrict line);
|
||||
static BMPRESULT s_load_image_or_line(BMPREAD_R rp, unsigned char **restrict buffer, bool line_by_line);
|
||||
static void s_read_rgb_line(BMPREAD_R rp, unsigned char *restrict line);
|
||||
static void s_read_indexed_line(BMPREAD_R rp, unsigned char *restrict line);
|
||||
static void s_read_rle_line(BMPREAD_R rp, unsigned char *restrict line,
|
||||
int *restrict x, int *restrict yoff);
|
||||
@@ -85,11 +86,10 @@ API BMPRESULT bmpread_load_image(BMPHANDLE h, unsigned char **restrict buffer)
|
||||
{
|
||||
BMPREAD rp;
|
||||
|
||||
if (!(h && cm_check_is_read_handle(h)))
|
||||
if (!(rp = cm_read_handle(h)))
|
||||
return BMP_RESULT_ERROR;
|
||||
rp = (BMPREAD)(void*)h;
|
||||
|
||||
return s_load_image_or_line(rp, buffer, FALSE);
|
||||
return s_load_image_or_line(rp, buffer, false);
|
||||
}
|
||||
|
||||
|
||||
@@ -102,14 +102,13 @@ API BMPRESULT bmpread_load_line(BMPHANDLE h, unsigned char **restrict buffer)
|
||||
{
|
||||
BMPREAD rp;
|
||||
|
||||
if (!(h && cm_check_is_read_handle(h)))
|
||||
if (!(rp = cm_read_handle(h)))
|
||||
return BMP_RESULT_ERROR;
|
||||
rp = (BMPREAD)(void*)h;
|
||||
|
||||
logreset(rp->log); /* otherwise we might accumulate thousands */
|
||||
logreset(rp->c.log); /* otherwise we might accumulate thousands */
|
||||
/* of log entries with large corrupt images */
|
||||
|
||||
return s_load_image_or_line(rp, buffer, TRUE);
|
||||
return s_load_image_or_line(rp, buffer, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -121,37 +120,37 @@ API BMPRESULT bmpread_load_line(BMPHANDLE h, unsigned char **restrict buffer)
|
||||
static void s_read_whole_image(BMPREAD_R rp, unsigned char *restrict image);
|
||||
static void s_read_one_line(BMPREAD_R rp, unsigned char *restrict image);
|
||||
|
||||
static BMPRESULT s_load_image_or_line(BMPREAD_R rp, unsigned char **restrict buffer, int line_by_line)
|
||||
static BMPRESULT s_load_image_or_line(BMPREAD_R rp, unsigned char **restrict buffer, bool line_by_line)
|
||||
{
|
||||
size_t buffer_size;
|
||||
|
||||
if (!(rp->getinfo_called && (rp->getinfo_return == BMP_RESULT_OK))) {
|
||||
if (rp->getinfo_return == BMP_RESULT_INSANE) {
|
||||
logerr(rp->log, "trying to load insanley large image");
|
||||
logerr(rp->c.log, "trying to load insanley large image");
|
||||
return BMP_RESULT_INSANE;
|
||||
}
|
||||
logerr(rp->log, "getinfo had failed, cannot load image");
|
||||
logerr(rp->c.log, "getinfo had failed, cannot load image");
|
||||
return BMP_RESULT_ERROR;
|
||||
}
|
||||
|
||||
if (rp->image_loaded) {
|
||||
logerr(rp->log, "Cannot load image more than once!");
|
||||
logerr(rp->c.log, "Cannot load image more than once!");
|
||||
return BMP_RESULT_ERROR;
|
||||
}
|
||||
|
||||
if (rp->line_by_line && !line_by_line) {
|
||||
logerr(rp->log, "Image is being loaded line-by-line. "
|
||||
logerr(rp->c.log, "Image is being loaded line-by-line. "
|
||||
"Cannot switch to full image.");
|
||||
return BMP_RESULT_ERROR;
|
||||
}
|
||||
|
||||
if (!rp->dimensions_queried) {
|
||||
logerr(rp->log, "must query dimensions before loading image");
|
||||
logerr(rp->c.log, "must query dimensions before loading image");
|
||||
return BMP_RESULT_ERROR;
|
||||
}
|
||||
|
||||
if (!buffer) {
|
||||
logerr(rp->log, "buffer pointer is NULL");
|
||||
logerr(rp->c.log, "buffer pointer is NULL");
|
||||
return BMP_RESULT_ERROR;
|
||||
}
|
||||
|
||||
@@ -161,35 +160,35 @@ static BMPRESULT s_load_image_or_line(BMPREAD_R rp, unsigned char **restrict buf
|
||||
buffer_size = rp->result_size;
|
||||
if (!*buffer) { /* no buffer supplied, we will allocate one */
|
||||
if (!(*buffer = malloc(buffer_size))) {
|
||||
logsyserr(rp->log, "allocating result buffer");
|
||||
logsyserr(rp->c.log, "allocating result buffer");
|
||||
return BMP_RESULT_ERROR;
|
||||
}
|
||||
rp->we_allocated_buffer = TRUE;
|
||||
rp->we_allocated_buffer = true;
|
||||
} else {
|
||||
rp->we_allocated_buffer = FALSE;
|
||||
rp->we_allocated_buffer = false;
|
||||
}
|
||||
|
||||
if (rp->we_allocated_buffer || (rp->rle && (rp->undefined_mode == BMP_UNDEFINED_TO_ALPHA)))
|
||||
memset(*buffer, 0, buffer_size);
|
||||
|
||||
if (!line_by_line)
|
||||
rp->image_loaded = TRUE; /* point of no return */
|
||||
rp->image_loaded = true; /* point of no return */
|
||||
|
||||
if (!rp->line_by_line) { /* either whole image or first line */
|
||||
if (rp->bytes_read > rp->fh->offbits) {
|
||||
logerr(rp->log, "Corrupt file");
|
||||
logerr(rp->c.log, "Corrupt file");
|
||||
goto abort;
|
||||
}
|
||||
/* skip to actual bitmap data: */
|
||||
if (!cm_gobble_up(rp, rp->fh->offbits - rp->bytes_read)) {
|
||||
logerr(rp->log, "while seeking start of bitmap data");
|
||||
logerr(rp->c.log, "while seeking start of bitmap data");
|
||||
goto abort;
|
||||
}
|
||||
rp->bytes_read += rp->fh->offbits - rp->bytes_read;
|
||||
}
|
||||
|
||||
if (line_by_line) {
|
||||
rp->line_by_line = TRUE; /* don't set this earlier, or we won't */
|
||||
rp->line_by_line = true; /* don't set this earlier, or we won't */
|
||||
/* be able to identify first line */
|
||||
s_read_one_line(rp, *buffer);
|
||||
} else {
|
||||
@@ -198,8 +197,8 @@ static BMPRESULT s_load_image_or_line(BMPREAD_R rp, unsigned char **restrict buf
|
||||
|
||||
s_log_error_from_state(rp);
|
||||
if (s_stopping_error(rp)) {
|
||||
rp->truncated = TRUE;
|
||||
rp->image_loaded = TRUE;
|
||||
rp->truncated = true;
|
||||
rp->image_loaded = true;
|
||||
return BMP_RESULT_TRUNCATED;
|
||||
} else if (s_cont_error(rp))
|
||||
return BMP_RESULT_INVALID;
|
||||
@@ -211,7 +210,7 @@ abort:
|
||||
free(*buffer);
|
||||
*buffer = NULL;
|
||||
}
|
||||
rp->image_loaded = TRUE;
|
||||
rp->image_loaded = true;
|
||||
return BMP_RESULT_ERROR;
|
||||
}
|
||||
|
||||
@@ -228,7 +227,7 @@ static void s_read_whole_image(BMPREAD_R rp, unsigned char *restrict image)
|
||||
|
||||
linesize = (size_t) rp->width * rp->result_bytes_per_pixel;
|
||||
|
||||
for (y = 0; y < (int) rp->height; y += yoff) {
|
||||
for (y = 0; y < rp->height; y += yoff) {
|
||||
real_y = (rp->orientation == BMP_ORIENT_TOPDOWN) ? y : rp->height-1-y;
|
||||
s_read_one_line(rp, image + real_y * linesize);
|
||||
if (rp->rle_eof || s_stopping_error(rp))
|
||||
@@ -265,8 +264,8 @@ static void s_read_one_line(BMPREAD_R rp, unsigned char *restrict line)
|
||||
}
|
||||
|
||||
if (!(rp->rle_eof || s_stopping_error(rp))) {
|
||||
if (yoff > (int) rp->height - rp->lbl_file_y) {
|
||||
rp->invalid_delta = TRUE;
|
||||
if (yoff > rp->height - rp->lbl_file_y) {
|
||||
rp->invalid_delta = true;
|
||||
}
|
||||
rp->lbl_file_y += yoff;
|
||||
|
||||
@@ -279,8 +278,8 @@ static void s_read_one_line(BMPREAD_R rp, unsigned char *restrict line)
|
||||
}
|
||||
|
||||
rp->lbl_y++;
|
||||
if (rp->lbl_y >= (int) rp->height) {
|
||||
rp->image_loaded = TRUE;
|
||||
if (rp->lbl_y >= rp->height) {
|
||||
rp->image_loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,7 +289,7 @@ static void s_read_one_line(BMPREAD_R rp, unsigned char *restrict line)
|
||||
* s_read_rgb_line
|
||||
*******************************************************/
|
||||
|
||||
static inline int s_read_rgb_pixel(BMPREAD_R rp, union Pixel *restrict px);
|
||||
static inline bool s_read_rgb_pixel(BMPREAD_R rp, union Pixel *restrict px);
|
||||
static inline double s_s2_13_to_float(uint16_t s2_13);
|
||||
static inline double s_int_to_float(unsigned long ul, int bits);
|
||||
static inline void s_convert64(uint16_t *val64);
|
||||
@@ -298,7 +297,7 @@ static inline void s_convert64srgb(uint16_t *val64);
|
||||
static inline double s_srgb_gamma_float(double d);
|
||||
static inline uint16_t s_srgb_gamma_s2_13(uint16_t s2_13);
|
||||
|
||||
static int s_read_rgb_line(BMPREAD_R rp, unsigned char *restrict line)
|
||||
static void s_read_rgb_line(BMPREAD_R rp, unsigned char *restrict line)
|
||||
{
|
||||
int i, x, padding;
|
||||
union Pixel px;
|
||||
@@ -311,7 +310,7 @@ static int s_read_rgb_line(BMPREAD_R rp, unsigned char *restrict line)
|
||||
for (x = 0; x < rp->width; x++) {
|
||||
|
||||
if (!s_read_rgb_pixel(rp, &px)) {
|
||||
return FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
offs = x * rp->result_channels;
|
||||
@@ -331,9 +330,9 @@ static int s_read_rgb_line(BMPREAD_R rp, unsigned char *restrict line)
|
||||
((uint32_t*)line)[offs + i] = pxval;
|
||||
break;
|
||||
default:
|
||||
logerr(rp->log, "Waaaaaaaaaaaaaah!");
|
||||
rp->panic = TRUE;
|
||||
return FALSE;
|
||||
logerr(rp->c.log, "Waaaaaaaaaaaaaah!");
|
||||
rp->panic = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (rp->ih->bitcount == 64) {
|
||||
@@ -384,18 +383,17 @@ static int s_read_rgb_line(BMPREAD_R rp, unsigned char *restrict line)
|
||||
break;
|
||||
|
||||
default:
|
||||
logerr(rp->log, "Unknown format");
|
||||
rp->panic = TRUE;
|
||||
return FALSE;
|
||||
logerr(rp->c.log, "Unknown format");
|
||||
rp->panic = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
padding = cm_align4padding(((uint64_t)rp->width * rp->ih->bitcount + 7) / 8);
|
||||
if (!cm_gobble_up(rp, padding)) {
|
||||
s_set_file_error(rp);
|
||||
return FALSE;
|
||||
return;
|
||||
}
|
||||
rp->bytes_read += padding;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
@@ -413,41 +411,33 @@ static inline double s_int_to_float(unsigned long ul, int bits)
|
||||
|
||||
static inline void s_convert64(uint16_t *val64)
|
||||
{
|
||||
int i;
|
||||
int32_t s;
|
||||
double d;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
s = val64[i];
|
||||
s = s << 16 >> 16; /* propagate sign bit */
|
||||
s *= 0xffff;
|
||||
s >>= 13;
|
||||
s = MAX(0, s);
|
||||
s = MIN(s, 0xffff);
|
||||
val64[i] = s;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
d = (double) (int16_t) val64[i];
|
||||
d /= 8192.0;
|
||||
d = MAX(0.0, d);
|
||||
d = MIN(d, 1.0);
|
||||
val64[i] = (uint16_t) (d * 0xffff + 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline void s_convert64srgb(uint16_t *val64)
|
||||
{
|
||||
int i;
|
||||
int32_t s;
|
||||
double v;
|
||||
double d;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
s = val64[i];
|
||||
s = s << 16 >> 16; /* propagate sign bit */
|
||||
if (i < 3) {
|
||||
v = (double) s / (1<<13);
|
||||
v = s_srgb_gamma_float(v);
|
||||
s = (int32_t) (v * (double) 0xffff);
|
||||
} else { /* don't apply gamma to alpha channel */
|
||||
s *= 0xffff;
|
||||
s >>= 13;
|
||||
}
|
||||
s = MAX(0, s);
|
||||
s = MIN(s, 0xffff);
|
||||
val64[i] = s;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
d = (double) (int16_t) val64[i];
|
||||
d /= 8192.0;
|
||||
d = MAX(0.0, d);
|
||||
d = MIN(d, 1.0);
|
||||
|
||||
/* apply gamma to RGB channels, but not to alpha channel */
|
||||
if (i < 3)
|
||||
d = s_srgb_gamma_float(d);
|
||||
|
||||
val64[i] = (uint16_t) (d * 0xffff + 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -478,7 +468,7 @@ static inline uint16_t s_srgb_gamma_s2_13(uint16_t s2_13)
|
||||
* s_read_rgb_pixel
|
||||
*******************************************************/
|
||||
|
||||
static inline int s_read_rgb_pixel(BMPREAD_R rp, union Pixel *restrict px)
|
||||
static inline bool s_read_rgb_pixel(BMPREAD_R rp, union Pixel *restrict px)
|
||||
{
|
||||
unsigned long long v;
|
||||
int i, byte;
|
||||
@@ -487,7 +477,7 @@ static inline int s_read_rgb_pixel(BMPREAD_R rp, union Pixel *restrict px)
|
||||
for (i = 0; i < rp->ih->bitcount; i+=8 ) {
|
||||
if (EOF == (byte = s_read_one_byte(rp))) {
|
||||
s_set_file_error(rp);
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
v |= ((unsigned long long)byte) << i;
|
||||
}
|
||||
@@ -498,9 +488,9 @@ static inline int s_read_rgb_pixel(BMPREAD_R rp, union Pixel *restrict px)
|
||||
if (rp->has_alpha)
|
||||
px->alpha = (unsigned int) ((v & rp->cmask.mask.alpha) >> rp->cmask.shift.alpha);
|
||||
else
|
||||
px->alpha = (1<<rp->result_bitsperchannel) - 1;
|
||||
px->alpha = (1ULL<<rp->result_bitsperchannel) - 1;
|
||||
|
||||
return TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -509,33 +499,62 @@ static inline int s_read_rgb_pixel(BMPREAD_R rp, union Pixel *restrict px)
|
||||
* s_read_indexed_line
|
||||
* - 1/2/4/8 bits non-RLE indexed
|
||||
*******************************************************/
|
||||
static inline int s_read_n_bytes(BMPREAD_R rp, int n, unsigned long *restrict buff);
|
||||
static inline unsigned long s_bits_from_buffer(unsigned long buf, int size,
|
||||
int nbits, int used_bits);
|
||||
struct Buffer32 {
|
||||
uint32_t buffer;
|
||||
int n;
|
||||
};
|
||||
|
||||
static inline bool s_buffer32_fill(BMPREAD_R rp, struct Buffer32 *restrict buf)
|
||||
{
|
||||
int byte;
|
||||
|
||||
memset(buf, 0, sizeof *buf);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (EOF == (byte = s_read_one_byte(rp))) {
|
||||
s_set_file_error(rp);
|
||||
return false;
|
||||
}
|
||||
buf->buffer <<= 8;
|
||||
buf->buffer |= byte;
|
||||
}
|
||||
buf->n = 32;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static inline uint32_t s_buffer32_bits(struct Buffer32 *restrict buf, int nbits)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
assert(nbits < 32);
|
||||
|
||||
result = buf->buffer >> (32 - nbits);
|
||||
buf->buffer = (buf->buffer << nbits) & 0xffffffffUL;
|
||||
buf->n -= nbits;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void s_read_indexed_line(BMPREAD_R rp, unsigned char *restrict line)
|
||||
{
|
||||
int bits_used, buffer_size, x = 0, v;
|
||||
int done = FALSE;
|
||||
unsigned long buffer;
|
||||
size_t offs;
|
||||
int x = 0, v;
|
||||
bool done = false;
|
||||
struct Buffer32 buffer;
|
||||
size_t offs;
|
||||
|
||||
/* setting the buffer size to the alignment takes care of padding bytes */
|
||||
buffer_size = 32;
|
||||
/* the buffer size of 32 bits takes care of padding bytes */
|
||||
|
||||
while (!done && s_read_n_bytes(rp, buffer_size / 8, &buffer)) {
|
||||
while (!done && s_buffer32_fill(rp, &buffer)) {
|
||||
|
||||
bits_used = 0;
|
||||
while (bits_used < buffer_size) {
|
||||
while (buffer.n >= rp->ih->bitcount) {
|
||||
|
||||
/* mask out the relevant bits for current pixel */
|
||||
v = (int) s_bits_from_buffer(buffer, buffer_size,
|
||||
rp->ih->bitcount, bits_used);
|
||||
bits_used += rp->ih->bitcount;
|
||||
v = (int) s_buffer32_bits(&buffer, rp->ih->bitcount);
|
||||
|
||||
if (v >= rp->palette->numcolors) {
|
||||
v = rp->palette->numcolors - 1;
|
||||
rp->invalid_index = TRUE;
|
||||
rp->invalid_index = true;
|
||||
}
|
||||
|
||||
offs = (size_t) x * rp->result_bytes_per_pixel;
|
||||
@@ -547,8 +566,9 @@ static void s_read_indexed_line(BMPREAD_R rp, unsigned char *restrict line)
|
||||
line[offs+2] = rp->palette->color[v].blue;
|
||||
s_int_to_result_format(rp, 8, line + offs);
|
||||
}
|
||||
|
||||
if (++x == rp->width) {
|
||||
done = TRUE;
|
||||
done = true;
|
||||
break; /* discarding rest of buffer == padding */
|
||||
}
|
||||
}
|
||||
@@ -557,51 +577,6 @@ static void s_read_indexed_line(BMPREAD_R rp, unsigned char *restrict line)
|
||||
|
||||
|
||||
|
||||
/********************************************************
|
||||
* s_read_n_bytes
|
||||
*******************************************************/
|
||||
|
||||
static inline int s_read_n_bytes(BMPREAD_R rp, int n, unsigned long *restrict buff)
|
||||
{
|
||||
int byte;
|
||||
|
||||
*buff = 0;
|
||||
while (n--) {
|
||||
if (EOF == (byte = s_read_one_byte(rp))) {
|
||||
s_set_file_error(rp);
|
||||
return FALSE;
|
||||
}
|
||||
*buff <<= 8;
|
||||
*buff |= byte;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************************************
|
||||
* s_bits_from_buffer
|
||||
*******************************************************/
|
||||
|
||||
static inline unsigned long s_bits_from_buffer(unsigned long buf, int size,
|
||||
int nbits, int used_bits)
|
||||
{
|
||||
unsigned long mask;
|
||||
int shift;
|
||||
|
||||
shift = size - (nbits + used_bits);
|
||||
|
||||
mask = (1U << nbits) - 1;
|
||||
mask <<= shift;
|
||||
|
||||
buf &= mask;
|
||||
buf >>= shift;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************************************
|
||||
* s_read_rle_line
|
||||
* - 4/8/24 bit RLE
|
||||
@@ -610,14 +585,15 @@ static inline unsigned long s_bits_from_buffer(unsigned long buf, int size,
|
||||
static void s_read_rle_line(BMPREAD_R rp, unsigned char *restrict line,
|
||||
int *restrict x, int *restrict yoff)
|
||||
{
|
||||
int repeat = FALSE, left_in_run = 0;
|
||||
int left_in_run = 0;
|
||||
bool repeat = false, padding = false, odd = false;
|
||||
int right, up;
|
||||
int padding = FALSE, odd = FALSE, v, r = 0, g = 0, b = 0;
|
||||
int v, r = 0, g = 0, b = 0;
|
||||
size_t offs;
|
||||
int bits = rp->ih->bitcount;
|
||||
|
||||
if (!(bits == 4 || bits == 8 || bits == 24)) {
|
||||
rp->panic = TRUE;
|
||||
rp->panic = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -665,7 +641,7 @@ static void s_read_rle_line(BMPREAD_R rp, unsigned char *restrict line,
|
||||
}
|
||||
if (v >= rp->palette->numcolors) {
|
||||
v = rp->palette->numcolors - 1;
|
||||
rp->invalid_index = TRUE;
|
||||
rp->invalid_index = true;
|
||||
}
|
||||
if (rp->result_indexed) {
|
||||
line[offs] = v;
|
||||
@@ -680,9 +656,9 @@ static void s_read_rle_line(BMPREAD_R rp, unsigned char *restrict line,
|
||||
|
||||
*x += 1;
|
||||
if (*x >= rp->width) {
|
||||
rp->rle_eol = FALSE; /* EOL detected by width, not by RLE-code */
|
||||
rp->rle_eol = false; /* EOL detected by width, not by RLE-code */
|
||||
if (left_in_run) {
|
||||
rp->invalid_overrun = TRUE;
|
||||
rp->invalid_overrun = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -703,10 +679,10 @@ static void s_read_rle_line(BMPREAD_R rp, unsigned char *restrict line,
|
||||
s_set_file_error(rp);
|
||||
break;
|
||||
}
|
||||
padding = FALSE;
|
||||
odd = FALSE;
|
||||
padding = false;
|
||||
odd = false;
|
||||
left_in_run = v;
|
||||
repeat = TRUE;
|
||||
repeat = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -719,21 +695,21 @@ static void s_read_rle_line(BMPREAD_R rp, unsigned char *restrict line,
|
||||
/* start literal run */
|
||||
if (v > 2) {
|
||||
left_in_run = v;
|
||||
repeat = FALSE;
|
||||
repeat = false;
|
||||
|
||||
switch (bits) {
|
||||
case 8:
|
||||
case 24:
|
||||
padding = v & 0x01 ? TRUE : FALSE;
|
||||
padding = v & 0x01 ? true : false;
|
||||
break;
|
||||
case 4:
|
||||
if ((v+1)%4 >= 2)
|
||||
padding = TRUE;
|
||||
padding = true;
|
||||
else
|
||||
padding = FALSE;
|
||||
padding = false;
|
||||
break;
|
||||
}
|
||||
odd = FALSE;
|
||||
odd = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -741,7 +717,7 @@ static void s_read_rle_line(BMPREAD_R rp, unsigned char *restrict line,
|
||||
if (v == 0) {
|
||||
if (*x != 0 || rp->rle_eol) {
|
||||
*x = rp->width;
|
||||
rp->rle_eol = TRUE;
|
||||
rp->rle_eol = true;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
@@ -749,7 +725,7 @@ static void s_read_rle_line(BMPREAD_R rp, unsigned char *restrict line,
|
||||
|
||||
/* end of bitmap */
|
||||
if (v == 1) {
|
||||
rp->rle_eof = TRUE;
|
||||
rp->rle_eof = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -760,7 +736,7 @@ static void s_read_rle_line(BMPREAD_R rp, unsigned char *restrict line,
|
||||
break;
|
||||
}
|
||||
if (right >= rp->width - *x) {
|
||||
rp->invalid_delta = TRUE;
|
||||
rp->invalid_delta = true;
|
||||
break;
|
||||
}
|
||||
*x += right;
|
||||
@@ -771,8 +747,8 @@ static void s_read_rle_line(BMPREAD_R rp, unsigned char *restrict line,
|
||||
continue;
|
||||
}
|
||||
|
||||
logerr(rp->log, "Should never get here! (x=%d, byte=%d)", (int) *x, (int) v);
|
||||
rp->panic = TRUE;
|
||||
logerr(rp->c.log, "Should never get here! (x=%d, byte=%d)", (int) *x, (int) v);
|
||||
rp->panic = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -781,14 +757,14 @@ static void s_read_rle_line(BMPREAD_R rp, unsigned char *restrict line,
|
||||
/********************************************************
|
||||
* s_read_huffman_line
|
||||
*******************************************************/
|
||||
static int s_huff_skip_eol(BMPREAD_R rp);
|
||||
static int s_huff_find_eol(BMPREAD_R rp);
|
||||
static bool s_huff_skip_eol(BMPREAD_R rp);
|
||||
static bool s_huff_find_eol(BMPREAD_R rp);
|
||||
|
||||
static void s_read_huffman_line(BMPREAD_R rp, unsigned char *restrict line)
|
||||
{
|
||||
size_t offs;
|
||||
int x = 0, runlen;
|
||||
int black = 0;
|
||||
bool black = false;
|
||||
|
||||
while (x < rp->width) {
|
||||
huff_fillbuf(rp);
|
||||
@@ -796,9 +772,9 @@ static void s_read_huffman_line(BMPREAD_R rp, unsigned char *restrict line)
|
||||
if (rp->hufbuf_len == 0)
|
||||
break;
|
||||
|
||||
if ((rp->hufbuf & 0x00ff) == 0) {
|
||||
if ((rp->hufbuf & 0xff000000UL) == 0) {
|
||||
if (!s_huff_skip_eol(rp)) {
|
||||
rp->truncated = TRUE;
|
||||
rp->truncated = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -812,7 +788,7 @@ static void s_read_huffman_line(BMPREAD_R rp, unsigned char *restrict line)
|
||||
/* code was invalid, look for next eol */
|
||||
rp->lasterr |= BMP_ERR_PIXEL;
|
||||
if (!s_huff_find_eol(rp))
|
||||
rp->truncated = TRUE;
|
||||
rp->truncated = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -824,11 +800,11 @@ static void s_read_huffman_line(BMPREAD_R rp, unsigned char *restrict line)
|
||||
for (int i = 0; i < runlen; i++, x++) {
|
||||
offs = (size_t) x * rp->result_bytes_per_pixel;
|
||||
if (rp->result_indexed) {
|
||||
line[offs] = black;
|
||||
line[offs] = black ^ rp->c.huffman_black_is_zero;
|
||||
} else {
|
||||
line[offs] = rp->palette->color[black].red;
|
||||
line[offs+1] = rp->palette->color[black].green;
|
||||
line[offs+2] = rp->palette->color[black].blue;
|
||||
line[offs] = rp->palette->color[black ^ rp->c.huffman_black_is_zero].red;
|
||||
line[offs+1] = rp->palette->color[black ^ rp->c.huffman_black_is_zero].green;
|
||||
line[offs+2] = rp->palette->color[black ^ rp->c.huffman_black_is_zero].blue;
|
||||
s_int_to_result_format(rp, 8, line + offs);
|
||||
}
|
||||
}
|
||||
@@ -837,7 +813,7 @@ static void s_read_huffman_line(BMPREAD_R rp, unsigned char *restrict line)
|
||||
}
|
||||
|
||||
|
||||
static int s_huff_skip_eol(BMPREAD_R rp)
|
||||
static bool s_huff_skip_eol(BMPREAD_R rp)
|
||||
{
|
||||
huff_fillbuf(rp);
|
||||
while (rp->hufbuf_len > 0) {
|
||||
@@ -846,38 +822,38 @@ static int s_huff_skip_eol(BMPREAD_R rp)
|
||||
huff_fillbuf(rp);
|
||||
continue;
|
||||
}
|
||||
while ((rp->hufbuf & 0x0001) == 0) {
|
||||
rp->hufbuf >>= 1;
|
||||
while ((rp->hufbuf & 0x80000000UL) == 0) {
|
||||
rp->hufbuf <<= 1;
|
||||
rp->hufbuf_len--;
|
||||
}
|
||||
rp->hufbuf >>= 1;
|
||||
rp->hufbuf <<= 1;
|
||||
rp->hufbuf_len--;
|
||||
return TRUE;
|
||||
return true;
|
||||
}
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int s_huff_find_eol(BMPREAD_R rp)
|
||||
static bool s_huff_find_eol(BMPREAD_R rp)
|
||||
{
|
||||
/* look for the next full 12-bit eol sequence,
|
||||
* discard anything else
|
||||
*/
|
||||
huff_fillbuf (rp);
|
||||
while (rp->hufbuf_len > 11)
|
||||
{
|
||||
if ((rp->hufbuf & 0x07ff) == 0) {
|
||||
rp->hufbuf >>= 11;
|
||||
rp->hufbuf_len -= 11;
|
||||
return s_huff_skip_eol (rp);
|
||||
}
|
||||
rp->hufbuf >>= 1;
|
||||
rp->hufbuf_len -= 1;
|
||||
if (rp->hufbuf_len < 12)
|
||||
huff_fillbuf (rp);
|
||||
}
|
||||
return FALSE;
|
||||
/* look for the next full 12-bit eol sequence,
|
||||
* discard anything else
|
||||
*/
|
||||
huff_fillbuf (rp);
|
||||
while (rp->hufbuf_len > 11)
|
||||
{
|
||||
if ((rp->hufbuf & 0xffe00000UL) == 0) {
|
||||
rp->hufbuf <<= 11;
|
||||
rp->hufbuf_len -= 11;
|
||||
return s_huff_skip_eol (rp);
|
||||
}
|
||||
rp->hufbuf <<= 1;
|
||||
rp->hufbuf_len -= 1;
|
||||
if (rp->hufbuf_len < 12)
|
||||
huff_fillbuf (rp);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -931,7 +907,7 @@ static inline void s_int_to_result_format(BMPREAD_R rp, int frombits, unsigned c
|
||||
break;
|
||||
default:
|
||||
#ifdef DEBUG
|
||||
logerr(rp->log, "Unexpected result format %d", rp->result_format);
|
||||
logerr(rp->c.log, "Unexpected result format %d", rp->result_format);
|
||||
exit(1);
|
||||
#endif
|
||||
break;
|
||||
@@ -948,9 +924,9 @@ static inline void s_int_to_result_format(BMPREAD_R rp, int frombits, unsigned c
|
||||
static void s_set_file_error(BMPREAD_R rp)
|
||||
{
|
||||
if (feof(rp->file))
|
||||
rp->file_eof = TRUE;
|
||||
rp->file_eof = true;
|
||||
else
|
||||
rp->file_err = TRUE;
|
||||
rp->file_err = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -962,19 +938,19 @@ static void s_set_file_error(BMPREAD_R rp)
|
||||
static void s_log_error_from_state(BMPREAD_R rp)
|
||||
{
|
||||
if (rp->panic)
|
||||
logerr(rp->log, "An internal error occured.");
|
||||
logerr(rp->c.log, "An internal error occured.");
|
||||
if (rp->file_eof)
|
||||
logerr(rp->log, "Unexpected end of file.");
|
||||
logerr(rp->c.log, "Unexpected end of file.");
|
||||
if (rp->file_err)
|
||||
logsyserr(rp->log, "While reading file");
|
||||
logsyserr(rp->c.log, "While reading file");
|
||||
if (rp->invalid_index)
|
||||
logerr(rp->log, "File contained invalid color index.");
|
||||
logerr(rp->c.log, "File contained invalid color index.");
|
||||
if (rp->invalid_delta)
|
||||
logerr(rp->log, "Invalid delta pointing outside image area.");
|
||||
logerr(rp->c.log, "Invalid delta pointing outside image area.");
|
||||
if (rp->invalid_overrun)
|
||||
logerr(rp->log, "RLE data overrunning image area.");
|
||||
logerr(rp->c.log, "RLE data overrunning image area.");
|
||||
if (rp->truncated)
|
||||
logerr(rp->log, "Image was truncated.");
|
||||
logerr(rp->c.log, "Image was truncated.");
|
||||
}
|
||||
|
||||
|
||||
@@ -983,13 +959,12 @@ static void s_log_error_from_state(BMPREAD_R rp)
|
||||
* s_cont_error
|
||||
*******************************************************/
|
||||
|
||||
static int s_cont_error(BMPREAD_R rp)
|
||||
static bool s_cont_error(BMPREAD_R rp)
|
||||
{
|
||||
if (rp->invalid_index ||
|
||||
rp->invalid_overrun) {
|
||||
return TRUE;
|
||||
if (rp->invalid_index || rp->invalid_overrun) {
|
||||
return true;
|
||||
}
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -998,16 +973,16 @@ static int s_cont_error(BMPREAD_R rp)
|
||||
* s_stopping_error
|
||||
*******************************************************/
|
||||
|
||||
static int s_stopping_error(BMPREAD_R rp)
|
||||
static bool s_stopping_error(BMPREAD_R rp)
|
||||
{
|
||||
if (rp->truncated ||
|
||||
if (rp->truncated ||
|
||||
rp->invalid_delta ||
|
||||
rp->file_err ||
|
||||
rp->file_eof ||
|
||||
rp->file_err ||
|
||||
rp->file_eof ||
|
||||
rp->panic) {
|
||||
return TRUE;
|
||||
return true;
|
||||
}
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define BMPLIB_LIB
|
||||
|
||||
@@ -50,9 +51,8 @@ API int bmpread_num_palette_colors(BMPHANDLE h)
|
||||
{
|
||||
BMPREAD rp;
|
||||
|
||||
if (!(h && cm_check_is_read_handle(h)))
|
||||
if (!(rp = cm_read_handle(h)))
|
||||
return 0;
|
||||
rp = (BMPREAD)(void*)h;
|
||||
|
||||
if (rp->palette)
|
||||
return rp->palette->numcolors;
|
||||
@@ -74,29 +74,27 @@ API BMPRESULT bmpread_load_palette(BMPHANDLE h, unsigned char **palette)
|
||||
int i,c;
|
||||
size_t memsize;
|
||||
|
||||
|
||||
if (!(h && cm_check_is_read_handle(h)))
|
||||
return 0;
|
||||
rp = (BMPREAD)(void*)h;
|
||||
if (!(rp = cm_read_handle(h)))
|
||||
return BMP_RESULT_ERROR;
|
||||
|
||||
if (!rp->getinfo_called) {
|
||||
logerr(rp->log, "Must call bmpread_load_info() before loading palette");
|
||||
logerr(rp->c.log, "Must call bmpread_load_info() before loading palette");
|
||||
return BMP_RESULT_ERROR;
|
||||
}
|
||||
if (!rp->palette) {
|
||||
logerr(rp->log, "Image has no palette");
|
||||
logerr(rp->c.log, "Image has no palette");
|
||||
return BMP_RESULT_ERROR;
|
||||
}
|
||||
|
||||
if (!palette) {
|
||||
logerr(rp->log, "palette is NULL");
|
||||
logerr(rp->c.log, "palette is NULL");
|
||||
return BMP_RESULT_ERROR;
|
||||
}
|
||||
|
||||
memsize = rp->palette->numcolors * 4;
|
||||
if (!*palette) {
|
||||
if (!(*palette = malloc(memsize))) {
|
||||
logsyserr(rp->log, "allocating palette");
|
||||
logsyserr(rp->c.log, "allocating palette");
|
||||
return BMP_RESULT_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -104,9 +102,9 @@ API BMPRESULT bmpread_load_palette(BMPHANDLE h, unsigned char **palette)
|
||||
|
||||
/* irreversible. image will be returned as indexed pixels */
|
||||
if (!rp->result_indexed) {
|
||||
rp->result_indexed = TRUE;
|
||||
rp->dimensions_queried = FALSE;
|
||||
rp->dim_queried_channels = FALSE;
|
||||
rp->result_indexed = true;
|
||||
rp->dimensions_queried = false;
|
||||
rp->dim_queried_channels = false;
|
||||
rp->result_channels = 1;
|
||||
if (!br_set_resultbits(rp))
|
||||
return BMP_RESULT_ERROR;
|
||||
|
||||
798
bmp-read.c
798
bmp-read.c
File diff suppressed because it is too large
Load Diff
@@ -19,5 +19,5 @@
|
||||
*/
|
||||
|
||||
void br_free(BMPREAD rp);
|
||||
int br_set_resultbits(BMPREAD_R rp);
|
||||
bool br_set_resultbits(BMPREAD_R rp);
|
||||
BMPRESULT br_set_number_format(BMPREAD_R rp, enum BmpFormat format);
|
||||
|
||||
605
bmp-write.c
605
bmp-write.c
File diff suppressed because it is too large
Load Diff
120
bmplib.h
120
bmplib.h
@@ -22,27 +22,27 @@
|
||||
#ifndef BMPLIB_H
|
||||
#define BMPLIB_H
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define DEPR(m) __attribute__ ((deprecated(m)))
|
||||
#define DEPR(m) __attribute__ ((deprecated(m)))
|
||||
#else
|
||||
#define DEPR(m)
|
||||
#define DEPR(m)
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef BMPLIB_LIB
|
||||
#define APIDECL __declspec(dllexport)
|
||||
#else
|
||||
#define APIDECL __declspec(dllimport)
|
||||
#endif
|
||||
#if defined (WIN32) || defined (_WIN32)
|
||||
#ifdef BMPLIB_LIB
|
||||
#define APIDECL __declspec(dllexport)
|
||||
#else
|
||||
#define APIDECL __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define APIDECL
|
||||
#define APIDECL
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct Bmphandle *BMPHANDLE;
|
||||
typedef union Bmphandle *BMPHANDLE;
|
||||
|
||||
|
||||
/*
|
||||
@@ -86,13 +86,13 @@ typedef struct Bmphandle *BMPHANDLE;
|
||||
* sufficiently high limit.
|
||||
*/
|
||||
enum Bmpresult {
|
||||
BMP_RESULT_OK = 0,
|
||||
BMP_RESULT_INVALID,
|
||||
BMP_RESULT_TRUNCATED,
|
||||
BMP_RESULT_INSANE,
|
||||
BMP_RESULT_PNG,
|
||||
BMP_RESULT_JPEG,
|
||||
BMP_RESULT_ERROR,
|
||||
BMP_RESULT_OK = 0,
|
||||
BMP_RESULT_INVALID,
|
||||
BMP_RESULT_TRUNCATED,
|
||||
BMP_RESULT_INSANE,
|
||||
BMP_RESULT_PNG,
|
||||
BMP_RESULT_JPEG,
|
||||
BMP_RESULT_ERROR,
|
||||
};
|
||||
typedef enum Bmpresult BMPRESULT;
|
||||
|
||||
@@ -112,11 +112,11 @@ typedef enum Bmpresult BMPRESULT;
|
||||
* - bmp_set_number_format(BMP_FORMAT_S2_13).
|
||||
*/
|
||||
enum Bmpconv64 {
|
||||
BMP_CONV64_SRGB = 0, /* default */
|
||||
BMP_CONV64_LINEAR = 1,
|
||||
BMP_CONV64_16BIT_SRGB DEPR("use BMP_CONV64_SRGB instead") = 0,
|
||||
BMP_CONV64_16BIT DEPR("use BMP_CONV64_LINEAR instead") = 1,
|
||||
BMP_CONV64_NONE
|
||||
BMP_CONV64_SRGB = 0, /* default */
|
||||
BMP_CONV64_LINEAR = 1,
|
||||
BMP_CONV64_16BIT_SRGB DEPR("use BMP_CONV64_SRGB instead") = 0,
|
||||
BMP_CONV64_16BIT DEPR("use BMP_CONV64_LINEAR instead") = 1,
|
||||
BMP_CONV64_NONE
|
||||
};
|
||||
typedef enum Bmpconv64 BMPCONV64;
|
||||
|
||||
@@ -124,22 +124,20 @@ typedef enum Bmpconv64 BMPCONV64;
|
||||
/*
|
||||
* BMP info header versions
|
||||
*
|
||||
* There doesn't seem to be consensus on whether the
|
||||
* BITMAPINFOHEADER is version 1 (with the two Adobe
|
||||
* extensions being v2 and v3) or version 3 (with the
|
||||
* older BITMAPCIREHEADER and OS22XBITMAPHEADER being
|
||||
* v1 and v2).
|
||||
* I am going with BITMAPINFOHEADER = v3
|
||||
* There doesn't seem to be consensus on whether the BITMAPINFOHEADER is
|
||||
* version 1 (with the two Adobe extensions being v2 and v3) or version 3
|
||||
* (with the older BITMAPCOREHEADER and OS22XBITMAPHEADER being v1 and v2).
|
||||
* I am going with BITMAPINFOHEADER = v3.
|
||||
*/
|
||||
enum BmpInfoVer {
|
||||
BMPINFO_CORE_OS21 = 1, /* 12 bytes */
|
||||
BMPINFO_OS22, /* 16 / 40(!) / 64 bytes */
|
||||
BMPINFO_V3, /* 40 bytes */
|
||||
BMPINFO_V3_ADOBE1, /* 52 bytes, unofficial */
|
||||
BMPINFO_V3_ADOBE2, /* 56 bytes, unofficial */
|
||||
BMPINFO_V4, /* 108 bytes */
|
||||
BMPINFO_V5, /* 124 bytes */
|
||||
BMPINFO_FUTURE /* future versions, larger than 124 bytes */
|
||||
BMPINFO_CORE_OS21 = 1, /* 12 bytes */
|
||||
BMPINFO_OS22, /* 16 / 40(!) / 64 bytes */
|
||||
BMPINFO_V3, /* 40 bytes */
|
||||
BMPINFO_V3_ADOBE1, /* 52 bytes, unofficial */
|
||||
BMPINFO_V3_ADOBE2, /* 56 bytes, unofficial */
|
||||
BMPINFO_V4, /* 108 bytes */
|
||||
BMPINFO_V5, /* 124 bytes */
|
||||
BMPINFO_FUTURE /* future versions, larger than 124 bytes */
|
||||
};
|
||||
typedef enum BmpInfoVer BMPINFOVER;
|
||||
|
||||
@@ -156,9 +154,9 @@ typedef enum BmpInfoVer BMPINFOVER;
|
||||
* table size.
|
||||
*/
|
||||
enum BmpRLEtype {
|
||||
BMP_RLE_NONE,
|
||||
BMP_RLE_AUTO,
|
||||
BMP_RLE_RLE8
|
||||
BMP_RLE_NONE,
|
||||
BMP_RLE_AUTO,
|
||||
BMP_RLE_RLE8
|
||||
};
|
||||
typedef enum BmpRLEtype BMPRLETYPE;
|
||||
|
||||
@@ -175,9 +173,9 @@ typedef enum BmpRLEtype BMPRLETYPE;
|
||||
*
|
||||
*/
|
||||
enum BmpUndefined {
|
||||
BMP_UNDEFINED_LEAVE,
|
||||
BMP_UNDEFINED_TO_ZERO DEPR("use BMP_UNDEFINED_LEAVE instead") = 0,
|
||||
BMP_UNDEFINED_TO_ALPHA /* default */
|
||||
BMP_UNDEFINED_LEAVE,
|
||||
BMP_UNDEFINED_TO_ZERO DEPR("use BMP_UNDEFINED_LEAVE instead") = 0,
|
||||
BMP_UNDEFINED_TO_ALPHA /* default */
|
||||
};
|
||||
typedef enum BmpUndefined BMPUNDEFINED;
|
||||
|
||||
@@ -191,16 +189,16 @@ typedef enum BmpUndefined BMPUNDEFINED;
|
||||
* still gives the orientation of the BMP file.
|
||||
*/
|
||||
enum BmpOrient {
|
||||
BMP_ORIENT_BOTTOMUP,
|
||||
BMP_ORIENT_TOPDOWN
|
||||
BMP_ORIENT_BOTTOMUP,
|
||||
BMP_ORIENT_TOPDOWN
|
||||
};
|
||||
typedef enum BmpOrient BMPORIENT;
|
||||
|
||||
|
||||
enum BmpFormat {
|
||||
BMP_FORMAT_INT,
|
||||
BMP_FORMAT_FLOAT,
|
||||
BMP_FORMAT_S2_13
|
||||
BMP_FORMAT_INT,
|
||||
BMP_FORMAT_FLOAT,
|
||||
BMP_FORMAT_S2_13
|
||||
};
|
||||
typedef enum BmpFormat BMPFORMAT;
|
||||
|
||||
@@ -210,11 +208,11 @@ APIDECL BMPHANDLE bmpread_new(FILE *file);
|
||||
APIDECL BMPRESULT bmpread_load_info(BMPHANDLE h);
|
||||
|
||||
APIDECL BMPRESULT bmpread_dimensions(BMPHANDLE h,
|
||||
int *width,
|
||||
int *height,
|
||||
int *channels,
|
||||
int *bitsperchannel,
|
||||
BMPORIENT *orientation);
|
||||
int *width,
|
||||
int *height,
|
||||
int *channels,
|
||||
int *bitsperchannel,
|
||||
BMPORIENT *orientation);
|
||||
|
||||
APIDECL int bmpread_width(BMPHANDLE h);
|
||||
APIDECL int bmpread_height(BMPHANDLE h);
|
||||
@@ -241,6 +239,9 @@ APIDECL void bmpread_set_insanity_limit(BMPHANDLE h, size_t limit);
|
||||
APIDECL int bmpread_is_64bit(BMPHANDLE h);
|
||||
APIDECL BMPRESULT bmpread_set_64bit_conv(BMPHANDLE h, BMPCONV64 conv);
|
||||
|
||||
APIDECL size_t bmpread_iccprofile_size(BMPHANDLE h);
|
||||
APIDECL BMPRESULT bmpread_load_iccprofile(BMPHANDLE h, unsigned char **profile);
|
||||
|
||||
APIDECL BMPINFOVER bmpread_info_header_version(BMPHANDLE h);
|
||||
APIDECL const char* bmpread_info_header_name(BMPHANDLE h);
|
||||
APIDECL int bmpread_info_header_size(BMPHANDLE h);
|
||||
@@ -255,10 +256,10 @@ APIDECL BMPRESULT bmpread_info_channel_bits(BMPHANDLE h, int *r, int *g, int *
|
||||
APIDECL BMPHANDLE bmpwrite_new(FILE *file);
|
||||
|
||||
APIDECL BMPRESULT bmpwrite_set_dimensions(BMPHANDLE h,
|
||||
unsigned width,
|
||||
unsigned height,
|
||||
unsigned channels,
|
||||
unsigned bitsperchannel);
|
||||
unsigned width,
|
||||
unsigned height,
|
||||
unsigned channels,
|
||||
unsigned bitsperchannel);
|
||||
APIDECL BMPRESULT bmpwrite_set_resolution(BMPHANDLE h, int xdpi, int ydpi);
|
||||
APIDECL BMPRESULT bmpwrite_set_output_bits(BMPHANDLE h, int red, int green, int blue, int alpha);
|
||||
APIDECL BMPRESULT bmpwrite_set_palette(BMPHANDLE h, int numcolors, const unsigned char *palette);
|
||||
@@ -268,12 +269,17 @@ APIDECL BMPRESULT bmpwrite_allow_rle24(BMPHANDLE h);
|
||||
APIDECL BMPRESULT bmpwrite_set_rle(BMPHANDLE h, BMPRLETYPE type);
|
||||
APIDECL BMPRESULT bmpwrite_set_orientation(BMPHANDLE h, BMPORIENT orientation);
|
||||
APIDECL BMPRESULT bmpwrite_set_64bit(BMPHANDLE h);
|
||||
APIDECL BMPRESULT bmpwrite_set_huffman_img_fg_idx(BMPHANDLE h, int idx);
|
||||
|
||||
APIDECL BMPRESULT bmpwrite_set_iccprofile(BMPHANDLE h, size_t size,
|
||||
const unsigned char *iccprofile);
|
||||
|
||||
APIDECL BMPRESULT bmpwrite_save_image(BMPHANDLE h, const unsigned char *image);
|
||||
APIDECL BMPRESULT bmpwrite_save_line(BMPHANDLE h, const unsigned char *line);
|
||||
|
||||
|
||||
APIDECL BMPRESULT bmp_set_number_format(BMPHANDLE h, BMPFORMAT format);
|
||||
APIDECL BMPRESULT bmp_set_huffman_t4black_value(BMPHANDLE h, int blackidx);
|
||||
|
||||
APIDECL void bmp_free(BMPHANDLE h);
|
||||
|
||||
|
||||
@@ -25,221 +25,221 @@ struct Huffcodetxt {
|
||||
};
|
||||
|
||||
static struct Huffcodetxt 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" },
|
||||
{ 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 Huffcodetxt 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" },
|
||||
{ 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 Huffcodetxt 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" },
|
||||
{ 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 Huffcodetxt 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" },
|
||||
{ 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" },
|
||||
};
|
||||
|
||||
119
gen-huffman.c
119
gen-huffman.c
@@ -25,22 +25,28 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#if (! __bool_true_false_are_defined)
|
||||
typedef int bool;
|
||||
#define true 1
|
||||
#define false 0
|
||||
#endif
|
||||
|
||||
#include "gen-huffman-codes.h"
|
||||
|
||||
|
||||
#define ARR_SIZE(a) (sizeof a / sizeof a[0])
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
struct Node {
|
||||
int l;
|
||||
int r;
|
||||
int value;
|
||||
int terminal;
|
||||
int makeup;
|
||||
int l;
|
||||
int r;
|
||||
int value;
|
||||
bool terminal;
|
||||
bool makeup;
|
||||
};
|
||||
|
||||
static int nnodes = 0;
|
||||
|
||||
static struct Node nodebuffer[416];
|
||||
|
||||
static int black_tree = -1;
|
||||
@@ -48,7 +54,7 @@ static int white_tree = -1;
|
||||
|
||||
|
||||
static void s_buildtree(void);
|
||||
static void add_node(int *nodeidx, const char *bits, int value, int makeup);
|
||||
static void add_node(int *nodeidx, const char *bits, int value, bool makeup);
|
||||
static unsigned short str2bits(const char *str);
|
||||
|
||||
|
||||
@@ -57,8 +63,8 @@ int main(int argc, char *argv[])
|
||||
int i;
|
||||
struct Node *n = nodebuffer;
|
||||
FILE *file;
|
||||
const char *src_name = "huffman-codes.h";
|
||||
const char *this_name = "gen-huffman.c";
|
||||
const char *src_name = "huffman-codes.h";
|
||||
const char *this_name = "gen-huffman.c";
|
||||
|
||||
if (argc == 2) {
|
||||
if (!(file = fopen(argv[1], "w"))) {
|
||||
@@ -71,27 +77,26 @@ int main(int argc, char *argv[])
|
||||
|
||||
s_buildtree();
|
||||
|
||||
fprintf(file, "/* bmplib - %s\n"
|
||||
" *\n"
|
||||
" * Copyright (c) 2024, Rupert Weber.\n"
|
||||
" *\n"
|
||||
" * This file is part of bmplib.\n"
|
||||
" * bmplib is free software: you can redistribute it and/or modify\n"
|
||||
" * it under the terms of the GNU Lesser General Public License as\n"
|
||||
" * published by the Free Software Foundation, either version 3 of\n"
|
||||
" * the License, or (at your option) any later version.\n"
|
||||
" *\n"
|
||||
" * This program is distributed in the hope that it will be useful,\n"
|
||||
" * but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
||||
" * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
|
||||
" * GNU Lesser General Public License for more details.\n"
|
||||
" *\n"
|
||||
" * You should have received a copy of the GNU Lesser General Public\n"
|
||||
" * License along with this library.\n"
|
||||
" * If not, see <https://www.gnu.org/licenses/>\n"
|
||||
" */\n\n"
|
||||
"/* This file is auto-generated by %s */\n\n\n",
|
||||
src_name, this_name);
|
||||
fprintf(file, "/* bmplib - %s\n", src_name);
|
||||
fprintf(file, " *\n"
|
||||
" * Copyright (c) 2024, Rupert Weber.\n"
|
||||
" *\n"
|
||||
" * This file is part of bmplib.\n"
|
||||
" * bmplib is free software: you can redistribute it and/or modify\n"
|
||||
" * it under the terms of the GNU Lesser General Public License as\n"
|
||||
" * published by the Free Software Foundation, either version 3 of\n"
|
||||
" * the License, or (at your option) any later version.\n"
|
||||
" *\n");
|
||||
fprintf(file, " * This program is distributed in the hope that it will be useful,\n"
|
||||
" * but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
||||
" * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
|
||||
" * GNU Lesser General Public License for more details.\n"
|
||||
" *\n"
|
||||
" * You should have received a copy of the GNU Lesser General Public\n"
|
||||
" * License along with this library.\n"
|
||||
" * If not, see <https://www.gnu.org/licenses/>\n"
|
||||
" */\n\n");
|
||||
fprintf(file, "/* This file is auto-generated by %s */\n\n\n", this_name);
|
||||
|
||||
fputs("struct Node {\n"
|
||||
"\tsigned short l;\n"
|
||||
@@ -111,17 +116,17 @@ int main(int argc, char *argv[])
|
||||
fprintf(file, "static const int blackroot = %d;\n", black_tree);
|
||||
fprintf(file, "static const int whiteroot = %d;\n\n\n", white_tree);
|
||||
fprintf(file, "static const struct Node nodebuffer[] = {\n");
|
||||
for (i = 0; i < ARR_SIZE(nodebuffer); i++) {
|
||||
for (i = 0; i < (int) ARR_SIZE(nodebuffer); i++) {
|
||||
fprintf(file, "\t{ %3d, %3d, %4d, %d, %d },\n",
|
||||
n[i].l, n[i].r, n[i].value, n[i].terminal, n[i].makeup);
|
||||
n[i].l, n[i].r, n[i].value, n[i].terminal, n[i].makeup);
|
||||
}
|
||||
fputs("};\n\n", file);
|
||||
|
||||
fputs("static const struct Huffcode huff_term_black[] = {\n\t", file);
|
||||
for (i = 0; i < ARR_SIZE(huff_term_black); i++) {
|
||||
for (i = 0; i < (int) ARR_SIZE(huff_term_black); i++) {
|
||||
fprintf(file, "{ 0x%02hx, %2d },",
|
||||
str2bits(huff_term_black[i].bits),
|
||||
(int) strlen(huff_term_black[i].bits));
|
||||
str2bits(huff_term_black[i].bits),
|
||||
(int) strlen(huff_term_black[i].bits));
|
||||
if ((i+1) % 4 == 0 && i != ARR_SIZE(huff_term_black) - 1)
|
||||
fputs("\n\t", file);
|
||||
else
|
||||
@@ -130,10 +135,10 @@ int main(int argc, char *argv[])
|
||||
fputs("\n};\n\n", file);
|
||||
|
||||
fputs("static const struct Huffcode huff_term_white[] = {\n\t", file);
|
||||
for (i = 0; i < ARR_SIZE(huff_term_white); i++) {
|
||||
for (i = 0; i < (int) ARR_SIZE(huff_term_white); i++) {
|
||||
fprintf(file, "{ 0x%02hx, %2d },",
|
||||
str2bits(huff_term_white[i].bits),
|
||||
(int) strlen(huff_term_white[i].bits));
|
||||
str2bits(huff_term_white[i].bits),
|
||||
(int) strlen(huff_term_white[i].bits));
|
||||
if ((i+1) % 4 == 0 && i != ARR_SIZE(huff_term_white) - 1)
|
||||
fputs("\n\t", file);
|
||||
else
|
||||
@@ -142,10 +147,10 @@ int main(int argc, char *argv[])
|
||||
fputs("\n};\n\n", file);
|
||||
|
||||
fputs("static const struct Huffcode huff_makeup_black[] = {\n\t", file);
|
||||
for (i = 0; i < ARR_SIZE(huff_makeup_black); i++) {
|
||||
for (i = 0; i < (int) ARR_SIZE(huff_makeup_black); i++) {
|
||||
fprintf(file, "{ 0x%02hx, %2d },",
|
||||
str2bits(huff_makeup_black[i].bits),
|
||||
(int) strlen(huff_makeup_black[i].bits));
|
||||
str2bits(huff_makeup_black[i].bits),
|
||||
(int) strlen(huff_makeup_black[i].bits));
|
||||
if ((i+1) % 4 == 0 && i != ARR_SIZE(huff_makeup_black) - 1)
|
||||
fputs("\n\t", file);
|
||||
else
|
||||
@@ -154,10 +159,10 @@ int main(int argc, char *argv[])
|
||||
fputs("\n};\n\n", file);
|
||||
|
||||
fputs("static const struct Huffcode huff_makeup_white[] = {\n\t", file);
|
||||
for (i = 0; i < ARR_SIZE(huff_makeup_white); i++) {
|
||||
for (i = 0; i < (int) ARR_SIZE(huff_makeup_white); i++) {
|
||||
fprintf(file, "{ 0x%02hx, %2d },",
|
||||
str2bits(huff_makeup_white[i].bits),
|
||||
(int) strlen(huff_makeup_white[i].bits));
|
||||
str2bits(huff_makeup_white[i].bits),
|
||||
(int) strlen(huff_makeup_white[i].bits));
|
||||
if ((i+1) % 4 == 0 && i != ARR_SIZE(huff_makeup_white) - 1)
|
||||
fputs("\n\t", file);
|
||||
else
|
||||
@@ -175,7 +180,7 @@ static unsigned short str2bits(const char *str)
|
||||
|
||||
while (*str) {
|
||||
value <<= 1;
|
||||
value |= *str - '0';
|
||||
value |= *str - '0';
|
||||
str++;
|
||||
}
|
||||
return value;
|
||||
@@ -192,22 +197,22 @@ static void s_buildtree(void)
|
||||
|
||||
memset(nodebuffer, 0, sizeof nodebuffer);
|
||||
|
||||
for (i = 0; i < ARR_SIZE(huff_term_black); i++) {
|
||||
for (i = 0; i < (int) ARR_SIZE(huff_term_black); i++) {
|
||||
add_node(&black_tree, huff_term_black[i].bits,
|
||||
huff_term_black[i].number, FALSE);
|
||||
huff_term_black[i].number, false);
|
||||
}
|
||||
for (i = 0; i < ARR_SIZE(huff_makeup_black); i++) {
|
||||
for (i = 0; i < (int) ARR_SIZE(huff_makeup_black); i++) {
|
||||
add_node(&black_tree, huff_makeup_black[i].bits,
|
||||
huff_makeup_black[i].number, TRUE);
|
||||
huff_makeup_black[i].number, true);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARR_SIZE(huff_term_white); i++) {
|
||||
for (i = 0; i < (int) ARR_SIZE(huff_term_white); i++) {
|
||||
add_node(&white_tree, huff_term_white[i].bits,
|
||||
huff_term_white[i].number, FALSE);
|
||||
huff_term_white[i].number, false);
|
||||
}
|
||||
for (i = 0; i < ARR_SIZE(huff_makeup_white); i++) {
|
||||
for (i = 0; i < (int) ARR_SIZE(huff_makeup_white); i++) {
|
||||
add_node(&white_tree, huff_makeup_white[i].bits,
|
||||
huff_makeup_white[i].number, TRUE);
|
||||
huff_makeup_white[i].number, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,14 +222,14 @@ static void s_buildtree(void)
|
||||
* add_node()
|
||||
****************************************************************************/
|
||||
|
||||
static void add_node(int *nodeidx, const char *bits, int value, int makeup)
|
||||
static void add_node(int *nodeidx, const char *bits, int value, bool makeup)
|
||||
{
|
||||
if (*nodeidx == -1) {
|
||||
*nodeidx = nnodes++;
|
||||
nodebuffer[*nodeidx].l = -1;
|
||||
nodebuffer[*nodeidx].r = -1;
|
||||
}
|
||||
if (nnodes > ARR_SIZE(nodebuffer)) {
|
||||
if (nnodes > (int) ARR_SIZE(nodebuffer)) {
|
||||
printf("too many nodes (have %d, max is %d)\n",
|
||||
nnodes, (int) ARR_SIZE(nodebuffer));
|
||||
exit(1);
|
||||
@@ -233,7 +238,7 @@ static void add_node(int *nodeidx, const char *bits, int value, int makeup)
|
||||
if (!*bits) {
|
||||
/* we are on the final bit of the sequence */
|
||||
nodebuffer[*nodeidx].value = value;
|
||||
nodebuffer[*nodeidx].terminal = TRUE;
|
||||
nodebuffer[*nodeidx].terminal = true;
|
||||
nodebuffer[*nodeidx].makeup = makeup;
|
||||
} else {
|
||||
switch (*bits) {
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
/* bmplib - gen-reversebits.c
|
||||
*
|
||||
* Copyright (c) 2024, Rupert Weber.
|
||||
*
|
||||
* This file is part of bmplib.
|
||||
* bmplib is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
* If not, see <https://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static int reverse(int val, int bits)
|
||||
{
|
||||
int mask;
|
||||
|
||||
bits /= 2;
|
||||
if (bits == 0)
|
||||
return val;
|
||||
mask = (1 << bits) - 1;
|
||||
return (reverse(val & mask, bits) << bits)
|
||||
| reverse(val >> bits, bits);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int reversed;
|
||||
FILE *file;
|
||||
const char *src_name = "reversebits.h";
|
||||
const char *this_name = "gen-reversebits.c";
|
||||
|
||||
if (argc == 2) {
|
||||
if (!(file = fopen(argv[1], "w"))) {
|
||||
perror(argv[1]);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
file = stdout;
|
||||
}
|
||||
|
||||
fprintf(file, "/* bmplib - %s\n"
|
||||
" *\n"
|
||||
" * Copyright (c) 2024, Rupert Weber.\n"
|
||||
" *\n"
|
||||
" * This file is part of bmplib.\n"
|
||||
" * bmplib is free software: you can redistribute it and/or modify\n"
|
||||
" * it under the terms of the GNU Lesser General Public License as\n"
|
||||
" * published by the Free Software Foundation, either version 3 of\n"
|
||||
" * the License, or (at your option) any later version.\n"
|
||||
" *\n"
|
||||
" * This program is distributed in the hope that it will be useful,\n"
|
||||
" * but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
||||
" * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
|
||||
" * GNU Lesser General Public License for more details.\n"
|
||||
" *\n"
|
||||
" * You should have received a copy of the GNU Lesser General Public\n"
|
||||
" * License along with this library.\n"
|
||||
" * If not, see <https://www.gnu.org/licenses/>\n"
|
||||
" */\n\n"
|
||||
"/* This file is auto-generated by %s */\n\n\n",
|
||||
src_name, this_name);
|
||||
|
||||
fprintf(file, "static const unsigned char reversebits[] = {\n\t");
|
||||
for (int i = 0; i < 256; i++) {
|
||||
reversed = reverse(i, 8);
|
||||
fprintf(file, "0x%02x, ", reversed);
|
||||
if ((i+1) % 8 == 0 && i < 255)
|
||||
fprintf(file, "\n\t");
|
||||
}
|
||||
fprintf(file, "\n};\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
64
huffman.c
64
huffman.c
@@ -23,20 +23,19 @@
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "bmplib.h"
|
||||
#include "logging.h"
|
||||
#include "bmp-common.h"
|
||||
#include "reversebits.h"
|
||||
#include "huffman.h"
|
||||
#include "huffman-codes.h"
|
||||
|
||||
|
||||
|
||||
static int s_findnode(uint32_t bits, int nbits, int black, int *found);
|
||||
static int s_zerofill(BMPWRITE_R wp);
|
||||
static int s_findnode(uint32_t bits, int nbits, bool black, int *found);
|
||||
static bool s_zerofill(BMPWRITE_R wp);
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
@@ -50,9 +49,10 @@ static int s_zerofill(BMPWRITE_R wp);
|
||||
|
||||
int huff_decode(BMPREAD_R rp, int black)
|
||||
{
|
||||
int idx;
|
||||
int bits_used = 0;
|
||||
int result = 0;
|
||||
int idx;
|
||||
int bits_used = 0;
|
||||
int result = 0;
|
||||
|
||||
do {
|
||||
huff_fillbuf(rp);
|
||||
bits_used = s_findnode(rp->hufbuf, rp->hufbuf_len, black, &idx);
|
||||
@@ -62,7 +62,7 @@ int huff_decode(BMPREAD_R rp, int black)
|
||||
}
|
||||
|
||||
result += nodebuffer[idx].value;
|
||||
rp->hufbuf >>= bits_used;
|
||||
rp->hufbuf <<= bits_used;
|
||||
rp->hufbuf_len -= bits_used;
|
||||
|
||||
} while (nodebuffer[idx].makeup && result < INT_MAX - 2560);
|
||||
@@ -76,7 +76,7 @@ int huff_decode(BMPREAD_R rp, int black)
|
||||
* s_findnode()
|
||||
****************************************************************************/
|
||||
|
||||
static int s_findnode(uint32_t bits, int nbits, int black, int *found)
|
||||
static int s_findnode(uint32_t bits, int nbits, bool black, int *found)
|
||||
{
|
||||
int idx;
|
||||
int bits_used = 0;
|
||||
@@ -84,12 +84,12 @@ static int s_findnode(uint32_t bits, int nbits, int black, int *found)
|
||||
idx = black ? blackroot : whiteroot;
|
||||
|
||||
while (idx != -1 && !nodebuffer[idx].terminal && bits_used < nbits) {
|
||||
if (bits & 1)
|
||||
if (bits & 0x80000000UL)
|
||||
idx = nodebuffer[idx].r;
|
||||
else
|
||||
idx = nodebuffer[idx].l;
|
||||
bits_used++;
|
||||
bits >>= 1;
|
||||
bits <<= 1;
|
||||
}
|
||||
*found = idx;
|
||||
return idx != -1 ? bits_used : 0;
|
||||
@@ -109,8 +109,7 @@ void huff_fillbuf(BMPREAD_R rp)
|
||||
if (EOF == (byte = getc(rp->file)))
|
||||
break;
|
||||
rp->bytes_read++;
|
||||
byte = reversebits[byte];
|
||||
rp->hufbuf |= ((uint32_t)byte) << rp->hufbuf_len;
|
||||
rp->hufbuf |= (uint32_t)byte << (24 - rp->hufbuf_len);
|
||||
rp->hufbuf_len += 8;
|
||||
}
|
||||
}
|
||||
@@ -121,16 +120,16 @@ void huff_fillbuf(BMPREAD_R rp)
|
||||
* s_push()
|
||||
****************************************************************************/
|
||||
|
||||
static int s_push(BMPWRITE_R wp, int bits, int nbits)
|
||||
static bool s_push(BMPWRITE_R wp, int bits, int nbits)
|
||||
{
|
||||
if (nbits > 32 - wp->hufbuf_len) {
|
||||
if (!huff_flush(wp))
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
wp->hufbuf <<= nbits;
|
||||
wp->hufbuf |= bits;
|
||||
wp->hufbuf_len += nbits;
|
||||
return TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -139,7 +138,7 @@ static int s_push(BMPWRITE_R wp, int bits, int nbits)
|
||||
* huff_encode()
|
||||
****************************************************************************/
|
||||
|
||||
int huff_encode(BMPWRITE_R wp, int val, int black)
|
||||
bool huff_encode(BMPWRITE_R wp, int val, bool black)
|
||||
{
|
||||
const struct Huffcode *makeup, *term;
|
||||
|
||||
@@ -159,13 +158,13 @@ int huff_encode(BMPWRITE_R wp, int val, int black)
|
||||
while (val > 63) {
|
||||
int n = MIN(2560 / 64, val / 64);
|
||||
if (!s_push(wp, makeup[n - 1].bits, makeup[n - 1].nbits))
|
||||
return FALSE;
|
||||
return false;
|
||||
val -= n * 64;
|
||||
}
|
||||
if (!s_push(wp, term[val].bits, term[val].nbits))
|
||||
return FALSE;
|
||||
return false;
|
||||
|
||||
return TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -174,7 +173,7 @@ int huff_encode(BMPWRITE_R wp, int val, int black)
|
||||
* huff_encode_eol()
|
||||
****************************************************************************/
|
||||
|
||||
int huff_encode_eol(BMPWRITE_R wp)
|
||||
bool huff_encode_eol(BMPWRITE_R wp)
|
||||
{
|
||||
return huff_encode(wp, -1, 0);
|
||||
}
|
||||
@@ -185,16 +184,16 @@ int huff_encode_eol(BMPWRITE_R wp)
|
||||
* huff_encode_rtc()
|
||||
****************************************************************************/
|
||||
|
||||
int huff_encode_rtc(BMPWRITE_R wp)
|
||||
bool huff_encode_rtc(BMPWRITE_R wp)
|
||||
{
|
||||
if (!s_zerofill(wp))
|
||||
return FALSE;
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
if (!huff_encode_eol(wp))
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
return TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -205,14 +204,14 @@ int huff_encode_rtc(BMPWRITE_R wp)
|
||||
* add fill 0s up to next byte boundary
|
||||
****************************************************************************/
|
||||
|
||||
static int s_zerofill(BMPWRITE_R wp)
|
||||
static bool s_zerofill(BMPWRITE_R wp)
|
||||
{
|
||||
int n = 8 - wp->hufbuf_len % 8;
|
||||
|
||||
if (n < 8)
|
||||
return s_push(wp, 0, n);
|
||||
|
||||
return TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -221,22 +220,19 @@ static int s_zerofill(BMPWRITE_R wp)
|
||||
* huff_flush()
|
||||
****************************************************************************/
|
||||
|
||||
int huff_flush(BMPWRITE_R wp)
|
||||
bool huff_flush(BMPWRITE_R wp)
|
||||
{
|
||||
int byte;
|
||||
|
||||
while (wp->hufbuf_len >= 8) {
|
||||
byte = 0x00ff & (wp->hufbuf >> (wp->hufbuf_len - 8));
|
||||
if (EOF == putc(byte, wp->file)) {
|
||||
logsyserr(wp->log, "writing Huffman bitmap");
|
||||
return FALSE;
|
||||
logsyserr(wp->c.log, "writing Huffman bitmap");
|
||||
return false;
|
||||
}
|
||||
wp->bytes_written++;
|
||||
wp->hufbuf_len -= 8;
|
||||
wp->hufbuf &= (1UL << wp->hufbuf_len) - 1;
|
||||
}
|
||||
return TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
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);
|
||||
bool huff_encode(BMPWRITE_R wp, int val, bool black);
|
||||
bool huff_encode_eol(BMPWRITE_R wp);
|
||||
bool huff_encode_rtc(BMPWRITE_R wp);
|
||||
bool huff_flush(BMPWRITE_R wp);
|
||||
|
||||
85
logging.c
85
logging.c
@@ -23,15 +23,23 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "logging.h"
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define MAY_BE_UNUSED __attribute__((unused))
|
||||
#else
|
||||
#define MAY_BE_UNUSED
|
||||
#endif
|
||||
|
||||
|
||||
struct Log {
|
||||
int size;
|
||||
char *buffer;
|
||||
bool panic;
|
||||
};
|
||||
|
||||
|
||||
@@ -50,9 +58,9 @@ static const char separator[]="\n"; /* separator between log entries */
|
||||
static const char inter[]=": "; /* between own message and sys err text */
|
||||
static const int air = 80; /* how much more than required we allocate */
|
||||
|
||||
static int s_allocate(LOG log, size_t add_chars);
|
||||
static bool s_allocate(LOG log, size_t add_chars);
|
||||
static void s_log(LOG log, const char *file, int line, const char *function,
|
||||
const char *etxt, const char *fmt, va_list args);
|
||||
const char *etxt, const char *fmt, va_list args);
|
||||
static void panic(LOG log);
|
||||
#ifdef DEBUG
|
||||
static int s_add_file_etc(LOG log, const char *file, int line, const char *function);
|
||||
@@ -66,7 +74,7 @@ static int s_add_file_etc(LOG log, const char *file, int line, const char *funct
|
||||
|
||||
LOG logcreate(void)
|
||||
{
|
||||
LOG log;
|
||||
LOG log;
|
||||
|
||||
if (!(log = malloc(sizeof *log)))
|
||||
return NULL;
|
||||
@@ -77,7 +85,7 @@ LOG logcreate(void)
|
||||
void logfree(LOG log)
|
||||
{
|
||||
if (log) {
|
||||
if (log->size != -1 && log->buffer)
|
||||
if (log->size > 0 && log->buffer)
|
||||
free(log->buffer);
|
||||
free(log);
|
||||
}
|
||||
@@ -97,10 +105,16 @@ void logreset(LOG log)
|
||||
|
||||
const char* logmsg(LOG log)
|
||||
{
|
||||
if (log && log->buffer)
|
||||
return log->buffer;
|
||||
else
|
||||
return "";
|
||||
if (log) {
|
||||
if (log->panic) {
|
||||
return "PANIC! bmplib encountered an error while "
|
||||
"trying to set an error message";
|
||||
}
|
||||
else if (log->buffer) {
|
||||
return log->buffer;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
@@ -115,17 +129,17 @@ void logerr_(LOG log, const char *file, int line, const char *function, const ch
|
||||
void logerr(LOG log, const char *fmt, ...)
|
||||
#endif
|
||||
{
|
||||
va_list args;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
va_start(args, fmt);
|
||||
|
||||
#ifdef DEBUG
|
||||
s_log(log, file, line, function, NULL, fmt, args);
|
||||
s_log(log, file, line, function, NULL, fmt, args);
|
||||
#else
|
||||
s_log(log, NULL, 0, NULL, NULL, fmt, args);
|
||||
s_log(log, NULL, 0, NULL, NULL, fmt, args);
|
||||
#endif
|
||||
|
||||
va_end(args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
||||
@@ -141,18 +155,18 @@ void logsyserr(LOG log, const char *fmt, ...)
|
||||
#endif
|
||||
{
|
||||
va_list args;
|
||||
const char *etxt;
|
||||
const char *etxt;
|
||||
|
||||
va_start(args, fmt);
|
||||
etxt = strerror(errno);
|
||||
va_start(args, fmt);
|
||||
etxt = strerror(errno);
|
||||
|
||||
#ifdef DEBUG
|
||||
s_log(log, file, line, function, etxt, fmt, args);
|
||||
s_log(log, file, line, function, etxt, fmt, args);
|
||||
#else
|
||||
s_log(log, NULL, 0, NULL, etxt, fmt, args);
|
||||
s_log(log, NULL, 0, NULL, etxt, fmt, args);
|
||||
#endif
|
||||
|
||||
va_end(args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
||||
@@ -161,14 +175,15 @@ void logsyserr(LOG log, const char *fmt, ...)
|
||||
* s_log()
|
||||
*********************************************************/
|
||||
|
||||
static void s_log(LOG log, const char *file, int line, const char *function,
|
||||
static void s_log(LOG log, const char *file MAY_BE_UNUSED, int line MAY_BE_UNUSED,
|
||||
const char *function MAY_BE_UNUSED,
|
||||
const char *etxt, const char *fmt, va_list args)
|
||||
{
|
||||
va_list argsdup;
|
||||
int len = 0,addl_len, required_len;
|
||||
va_list argsdup;
|
||||
int len = 0,addl_len, required_len;
|
||||
|
||||
if (log->size == -1)
|
||||
return; /* log is set to a string literal (panic) */
|
||||
if (log->panic)
|
||||
return;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!s_add_file_etc(log, file, line, function))
|
||||
@@ -176,7 +191,7 @@ static void s_log(LOG log, const char *file, int line, const char *function,
|
||||
#endif
|
||||
|
||||
if (log->buffer)
|
||||
len = strlen(log->buffer);
|
||||
len = strlen(log->buffer);
|
||||
|
||||
va_copy(argsdup, args);
|
||||
addl_len = vsnprintf(NULL, 0, fmt, argsdup);
|
||||
@@ -199,7 +214,7 @@ static void s_log(LOG log, const char *file, int line, const char *function,
|
||||
#endif
|
||||
|
||||
if (log->size - len <= vsnprintf(log->buffer + len, log->size - len,
|
||||
fmt, args)) {
|
||||
fmt, args)) {
|
||||
panic(log);
|
||||
return;
|
||||
}
|
||||
@@ -216,20 +231,20 @@ static void s_log(LOG log, const char *file, int line, const char *function,
|
||||
* s_allocate()
|
||||
*********************************************************/
|
||||
|
||||
static int s_allocate(LOG log, size_t add_chars)
|
||||
static bool s_allocate(LOG log, size_t add_chars)
|
||||
{
|
||||
char *tmp;
|
||||
size_t newsize;
|
||||
|
||||
if (log->size == -1)
|
||||
return 0; /* log is set to a string literal (panic) */
|
||||
if (log->panic)
|
||||
return false;
|
||||
|
||||
add_chars += air;
|
||||
|
||||
newsize = (size_t) log->size + add_chars;
|
||||
if (newsize > INT_MAX) {
|
||||
panic(log);
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
tmp = realloc(log->buffer, newsize);
|
||||
@@ -240,10 +255,10 @@ static int s_allocate(LOG log, size_t add_chars)
|
||||
log->size = newsize;
|
||||
} else {
|
||||
panic(log);
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -254,9 +269,7 @@ static int s_allocate(LOG log, size_t add_chars)
|
||||
|
||||
static void panic(LOG log)
|
||||
{
|
||||
log->size = -1;
|
||||
log->buffer = "PANIC! bmplib encountered an error while trying to set "
|
||||
"an error message";
|
||||
log->panic = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -290,7 +303,7 @@ static int s_add_file_etc(LOG log, const char *file, int line, const char *funct
|
||||
}
|
||||
|
||||
if (log->size - len <= snprintf(log->buffer + len, log->size - len,
|
||||
"[%s, line %d, %s()] ", file, line, function)) {
|
||||
"[%s, line %d, %s()] ", file, line, function)) {
|
||||
panic(log);
|
||||
return 0;
|
||||
}
|
||||
|
||||
20
logging.h
20
logging.h
@@ -25,23 +25,23 @@ typedef struct Log *LOG;
|
||||
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define PRINTF(a,b) __attribute__((format(printf, a, b)))
|
||||
#define PRINTF(a,b) __attribute__((format(printf, a, b)))
|
||||
#else
|
||||
#define PRINTF(a,b)
|
||||
#define PRINTF(a,b)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
#define logerr(log, ...) logerr_(log, __FILE__, __LINE__, __func__, __VA_ARGS__)
|
||||
void PRINTF(5,6) logerr_(LOG log, const char *file, int line,
|
||||
const char *function, const char *fmt, ...);
|
||||
#define logerr(log, ...) logerr_(log, __FILE__, __LINE__, __func__, __VA_ARGS__)
|
||||
void PRINTF(5,6) logerr_(LOG log, const char *file, int line,
|
||||
const char *function, const char *fmt, ...);
|
||||
|
||||
#define logsyserr(log, ...) logsyserr_(log, __FILE__, __LINE__, __func__, __VA_ARGS__)
|
||||
void PRINTF(5,6) logsyserr_(LOG log, const char *file, int line,
|
||||
const char *function, const char *fmt, ...);
|
||||
#define logsyserr(log, ...) logsyserr_(log, __FILE__, __LINE__, __func__, __VA_ARGS__)
|
||||
void PRINTF(5,6) logsyserr_(LOG log, const char *file, int line,
|
||||
const char *function, const char *fmt, ...);
|
||||
#else
|
||||
void PRINTF(2,3) logerr(LOG log, const char *fmt, ...);
|
||||
void PRINTF(2,3) logsyserr(LOG log, const char *fmt, ...);
|
||||
void PRINTF(2,3) logerr(LOG log, const char *fmt, ...);
|
||||
void PRINTF(2,3) logsyserr(LOG log, const char *fmt, ...);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
27
meson.build
27
meson.build
@@ -1,12 +1,23 @@
|
||||
project('bmplib', 'c', default_options: ['c_std=c11'], version: '1.7.0')
|
||||
project('bmplib', 'c', default_options: ['c_std=c11', 'warning_level=3'], version: '1.7.5')
|
||||
|
||||
cc = meson.get_compiler('c')
|
||||
|
||||
add_project_arguments(['-pedantic','-fvisibility=hidden'], language : 'c')
|
||||
|
||||
add_project_arguments('-pedantic', language : 'c')
|
||||
add_project_arguments('-fvisibility=hidden', language: 'c')
|
||||
if get_option('buildtype') == 'debug'
|
||||
add_project_arguments('-DDEBUG', language: 'c')
|
||||
elif get_option('buildtype') == 'release'
|
||||
add_project_arguments('-DNDEBUG', language: 'c')
|
||||
endif
|
||||
|
||||
if get_option('sanitize')
|
||||
sanitize = [
|
||||
'-fsanitize=signed-integer-overflow',
|
||||
'-fsanitize=undefined',
|
||||
'-fsanitize=float-divide-by-zero',
|
||||
]
|
||||
add_project_arguments(sanitize, language : 'c')
|
||||
add_project_link_arguments(sanitize, language: 'c')
|
||||
endif
|
||||
|
||||
m_dep = cc.find_library('m', required : false)
|
||||
@@ -37,22 +48,15 @@ elif cc.sizeof('int') < 4
|
||||
error('sizeof(int) must be at least 32 bit.')
|
||||
endif
|
||||
|
||||
|
||||
gen_huffman = executable('gen-huffman', 'gen-huffman.c')
|
||||
huff_codes = custom_target('huffman-codes.h',
|
||||
output: 'huffman-codes.h',
|
||||
command: [gen_huffman, '@OUTPUT@'],
|
||||
)
|
||||
|
||||
gen_reversebits = executable('gen-reversebits', 'gen-reversebits.c')
|
||||
reversebits = custom_target('reversebits.h',
|
||||
output: 'reversebits.h',
|
||||
command: [gen_reversebits, '@OUTPUT@'],
|
||||
)
|
||||
|
||||
|
||||
bmplib = shared_library('bmp',
|
||||
[bmplib_sources, huff_codes[0], reversebits[0]],
|
||||
[bmplib_sources, huff_codes[0]],
|
||||
version: meson.project_version(),
|
||||
install: true,
|
||||
dependencies: m_dep,
|
||||
@@ -65,4 +69,3 @@ pkg_mod.generate(libraries: bmplib,
|
||||
filebase: 'libbmp',
|
||||
description: 'Library for reading/writing Windows BMP files.',
|
||||
)
|
||||
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
option('insanity_limit_mb', type: 'integer', min: 0, value: 500)
|
||||
option('sanitize', type: 'boolean', value: false)
|
||||
|
||||
Reference in New Issue
Block a user