/* 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 . */ module bpg; import std.stdint; import std.array; 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 */ } struct DecodedBPGImage { ubyte[] data; int width; int height; } 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, }; extern (C) BPGDecoderContext* bpg_decoder_open(); extern (C) int bpg_decoder_keep_extension_data (BPGDecoderContext* s, int enable); extern (C) int bpg_decoder_decode (BPGDecoderContext* s, const uint8_t* buf, int buf_len); extern (C) BPGExtensionData bpg_decoder_get_extension_data (BPGDecoderContext* s); extern (C) int bpg_decoder_get_info (BPGDecoderContext* s, BPGImageInfo* p); extern (C) void bpg_decoder_close (BPGDecoderContext* s); extern (C) void bpg_decoder_free_extension_data (BPGExtensionData* first_md); extern (C) int bpg_decoder_start (BPGDecoderContext* s, BPGDecoderOutputFormat out_fmt); extern (C) int bpg_decoder_get_line (BPGDecoderContext* s, void* buf); 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; }