jumping-in-d/bpg.d

110 lines
4 KiB
D

/* Copyright 2015, Michele Santullo
* This file is part of "Jumping in D".
*
* "Jumping in D" is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* "Jumping in D" is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with "Jumping in D". If not, see <http://www.gnu.org/licenses/>.
*/
module bpg;
import std.stdint;
import std.array;
//Define structs as in the c header file (libbpg.h)
struct BPGDecoderContext;
struct BPGExtensionData {
BPGExtensionTagEnum tag;
uint32_t buf_len;
uint8_t *buf;
BPGExtensionData* next;
}
struct BPGImageInfo {
uint32_t width;
uint32_t height;
uint8_t format; /* see BPGImageFormatEnum */
uint8_t has_alpha; /* TRUE if an alpha plane is present */
uint8_t color_space; /* see BPGColorSpaceEnum */
uint8_t bit_depth;
uint8_t premultiplied_alpha; /* TRUE if the color is alpha premultiplied */
uint8_t has_w_plane; /* TRUE if a W plane is present (for CMYK encoding) */
uint8_t limited_range; /* TRUE if limited range for the color */
uint8_t has_animation; /* TRUE if the image contains animations */
uint16_t loop_count; /* animations: number of loop, 0 = infinity */
}
//Just a convenience struct to return the uncompressed image and its size
struct DecodedBPGImage {
ubyte[] data;
int width;
int height;
}
//Enums, as defined in the c header (libbpg.h)
enum BPGDecoderOutputFormat : int {
BPG_OUTPUT_FORMAT_RGB24,
BPG_OUTPUT_FORMAT_RGBA32, /* not premultiplied alpha */
BPG_OUTPUT_FORMAT_RGB48,
BPG_OUTPUT_FORMAT_RGBA64, /* not premultiplied alpha */
BPG_OUTPUT_FORMAT_CMYK32,
BPG_OUTPUT_FORMAT_CMYK64,
};
enum BPGExtensionTagEnum : int {
BPG_EXTENSION_TAG_EXIF = 1,
BPG_EXTENSION_TAG_ICCP = 2,
BPG_EXTENSION_TAG_XMP = 3,
BPG_EXTENSION_TAG_THUMBNAIL = 4,
BPG_EXTENSION_TAG_ANIM_CONTROL = 5,
};
//Declaration of the c functions
private extern (C) BPGDecoderContext* bpg_decoder_open();
private extern (C) int bpg_decoder_keep_extension_data (BPGDecoderContext* s, int enable);
private extern (C) int bpg_decoder_decode (BPGDecoderContext* s, const uint8_t* buf, int buf_len);
private extern (C) BPGExtensionData bpg_decoder_get_extension_data (BPGDecoderContext* s);
private extern (C) int bpg_decoder_get_info (BPGDecoderContext* s, BPGImageInfo* p);
private extern (C) void bpg_decoder_close (BPGDecoderContext* s);
private extern (C) void bpg_decoder_free_extension_data (BPGExtensionData* first_md);
private extern (C) int bpg_decoder_start (BPGDecoderContext* s, BPGDecoderOutputFormat out_fmt);
private extern (C) int bpg_decoder_get_line (BPGDecoderContext* s, void* buf);
//Use the c functions to decode the compressed data in parData.
//This function does just that, and only returns 24 bit images.
public DecodedBPGImage decode_bpg_image (const(char)[] parData) {
auto context = bpg_decoder_open();
scope(exit) bpg_decoder_close(context);
if (bpg_decoder_decode(context, cast(ubyte*)parData.ptr, cast(int)parData.length) < 0) {
throw new Exception("Could not decode image");
}
BPGImageInfo img_info;
bpg_decoder_get_info(context, &img_info);
ubyte[] rgbline = new ubyte[img_info.width * 3];
ubyte[] retdata;
retdata.reserve(img_info.width * 3 * img_info.height);
bpg_decoder_start(context, BPGDecoderOutputFormat.BPG_OUTPUT_FORMAT_RGB24);
for (auto z = 0; z < img_info.height; ++z) {
bpg_decoder_get_line(context, rgbline.ptr);
retdata ~= rgbline;
}
assert(img_info.width * 3 * img_info.height == retdata.length);
DecodedBPGImage retval;
retval.width = img_info.width;
retval.height = img_info.height;
retval.data = retdata;
return retval;
}