Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 76 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# C++ Bitmap header files

This repo is compatible with the [cpp-container](https://github.com/ChicoState/cpp-container) Docker container.
This repo is compatible with the [cpp-container](https://github.com/ChicoState/cpp-container) Docker container and requires C++11 or newer.

## Development and releases

Expand Down Expand Up @@ -32,7 +32,7 @@ assets.
1. Clone this repository onto your development environment
2. Copy `bitmap.h` and `bitmap.cpp` to your project directory
3. In your C++ project, include the header file with
`#include "bitmap.h"` and include bitmap in your compilation
`#include "bitmap.h"` and include `bitmap.cpp` in your compilation
4. Declare your variables of type *Bitmap* or *Pixel*.

See the guides for the Bitmap and Pixel data types below.
Expand Down Expand Up @@ -63,30 +63,84 @@ purpleDot.blue = 255;

## Bitmap

Represents a bitmap where a grid of pixels (in row-major order)
describes the color of each pixel within the image. Limited to Windows BMP
formatted images with no compression and 24 bit color depth.
Represents a bitmap where a grid of pixels in row-major order describes the
color of each pixel. Supported BMP inputs are normalized to 8-bit red, green,
and blue components. Saving always produces an uncompressed 24-bpp BMP.

### Input compatibility

| DIB header | Encoding | Supported depths |
|---|---|---|
| 12-byte `BITMAPCOREHEADER` | Uncompressed indexed/direct RGB | 1, 4, 8, 24 bpp |
| 40-byte `BITMAPINFOHEADER` and 52/56/108/124-byte extensions | `BI_RGB` | 1, 4, 8, 16, 24, 32 bpp |
| 40/52/56/108/124-byte headers | `BI_BITFIELDS` | 16, 32 bpp |
| 40/52/56/108/124-byte headers | `BI_RLE4` | 4 bpp |
| 40/52/56/108/124-byte headers | `BI_RLE8` | 8 bpp |

The decoder supports bottom-up images and top-down uncompressed/bitfield
images. Microsoft defines RLE-compressed BMPs as bottom-up, so top-down RLE is
rejected. Palettes, bitfields, scanline padding, and row orientation are
converted internally; the returned matrix is always top-to-bottom RGB.

### Lossiness rules

`isLossy()` reports whether the most recent successful `open()` discarded
color information or precision while creating the RGB-only matrix. It does
not refer to image width, height, or pixel density; dimensions are not
resampled.

| Import behavior | `isLossy()` |
|---|---:|
| Palette expansion, RLE expansion, row reordering, or padding removal | `false` |
| Expanding 5-bit or 6-bit RGB components to 8-bit components | `false` |
| Ignoring the undefined byte in 32-bpp `BI_RGB` BGRX data | `false` |
| Discarding a declared alpha channel whose pixels are all opaque | `false` |
| Discarding a declared alpha channel with any non-opaque pixel | `true` |
| Reducing an RGB bitfield component wider than 8 bits | `true` |
| Preserving numeric RGB values without applying meaningful V4/V5 color-profile or gamma metadata | `true` |

When alpha is discarded, the stored red, green, and blue values are preserved
unchanged. The library does not composite pixels against an assumed
background.

For a new `Bitmap`, after a failed `open()`, or after `fromPixelMatrix()`,
`isLossy()` returns `false`. Calling `save()` does not alter the value.

### Limitations

- Embedded `BI_JPEG` and `BI_PNG` payloads are not decoded.
- CMYK BMP encodings and later OS/2 2.x-specific headers/compression are not supported.
- Unknown DIB header sizes are rejected rather than guessed.
- ICC/profile and gamma transforms are not applied; numeric RGB values are retained and the import is marked lossy when meaningful metadata is present.
- Alpha is not retained in `PixelMatrix` or saved output.
- Input files larger than 512 MiB are rejected before allocation.
- Inputs whose decoded dimensions exceed 100 million pixels are rejected as a memory-safety limit.
- `save()` writes only bottom-up, uncompressed, 24-bpp `BI_RGB` files.

The decoder behavior follows Microsoft's documentation for
[bitmap headers](https://learn.microsoft.com/en-us/windows/win32/gdi/bitmap-header-types),
[bitmap storage](https://learn.microsoft.com/en-us/windows/win32/gdi/bitmap-storage),
[`BITMAPINFOHEADER`](https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader),
and [RLE compression](https://learn.microsoft.com/en-us/windows/win32/gdi/bitmap-compression).

### Functions

#### open

`void open(std::string)`

*Opens a file as its name is provided and reads pixel-by-pixel the colors
into a matrix of RGB pixels. Any errors will cout but will result in an
empty matrix (with no rows and no columns).*
*Opens a supported BMP and converts it to a matrix of RGB pixels. Any error is
written to `std::cerr` and leaves an empty matrix.*

*parameter: name of the filename to be opened and read as a matrix of pixels*

#### save

`void save(std::string)`

*Saves the current image, represented by the matrix of pixels, as a
Windows BMP file with the name provided by the parameter. File extension
is not forced but should be .bmp. Any errors will cout and will NOT
attempt to save the file.*
*Saves the current matrix as an uncompressed 24-bpp Windows BMP. The file
extension is not forced but should be `.bmp`. Errors are written to
`std::cerr`.*

#### isImage

Expand All @@ -99,6 +153,14 @@ to have red, green, and blue components with values between 0 and 255*

*return: boolean value of whether or not the matrix is a valid image*

#### isLossy

`bool isLossy()`

*Returns whether the most recent successful `open()` discarded color
information or precision while converting the input to RGB pixels. See the
lossiness table above for exact behavior.*

#### toPixelMatrix

`std::vector <std::vector <Pixel> > toPixelMatrix()`
Expand Down Expand Up @@ -137,6 +199,7 @@ int main()

//verify that the file opened was a valid image
bool validBmp = image.isImage();
bool lostColorInformation = image.isLossy();

if( validBmp == true )
{
Expand All @@ -152,6 +215,7 @@ int main()
image.fromPixelMatrix(bmp);
image.save("example.bmp");
}
(void)lostColorInformation;
return 0;
}
```
Loading
Loading