ImageFileInfo DetectImageFormat(array_view<uint8_t> data) { ImageFileInfo info; stbi__context ctx; stbi__start_mem(&ctx, &data[0], data.bytes()); int comp; if (stbi__bmp_info(&ctx, &info.width, &info.height, &comp)) { info.hasAlpha = (comp == 4); info.format = ImageFileFormat::BMP; return info; } TjDecompressHandle handle; if (tjDecompressHeader(handle, &data[0], data.bytes(), &info.width, &info.height) == 0) { info.hasAlpha = false; info.format = ImageFileFormat::JPEG; return info; } if (DetectTga(data, info)) { return info; } // Not a very good heuristic if (data.size() == 256 * 256) { info.width = 256; info.height = 256; info.hasAlpha = true; info.format = ImageFileFormat::FNTART; return info; } return info; }
std::unique_ptr<uint8_t[]> DecodeJpeg(const array_view<uint8_t> data) { TjDecompressHandle handle; int w, h; tjDecompressHeader(handle, &data[0], data.bytes(), &w, &h); std::unique_ptr<uint8_t[]> result(new uint8_t[w * h * 4]); auto status = tjDecompress2(handle, &data[0], data.bytes(), &result[0], w, w * 4, h, TJPF_BGRX, 0); if (status != 0) { throw TempleException("Unable to decompress jpeg image: {}", tjGetErrorStr()); } return result; }
DecodedImage DecodeImage(const array_view<uint8_t> data) { DecodedImage result; result.info = DetectImageFormat(data); stbi__context ctx; stbi__start_mem(&ctx, &data[0], data.bytes()); int w, h, comp; switch (result.info.format) { case ImageFileFormat::BMP: result.data.reset(stbi__bmp_load(&ctx, &w, &h, &comp, 4)); break; case ImageFileFormat::JPEG: result.data = DecodeJpeg(data); break; case ImageFileFormat::TGA: result.data = DecodeTga(data); break; case ImageFileFormat::FNTART: return DecodeFontArt(data); default: case ImageFileFormat::Unknown: throw TempleException("Unrecognized image format."); } return result; }