xiaozhuai / imageinfo

Free Palestine🇵🇸🇵🇸🇵🇸Cross platform super fast single header c++ library to get image size and format without loading/decoding. Support avif, bmp, cur, dds, gif, hdr (pic), heic (heif), icns, ico, j2k, jp2, jpeg (jpg), jpx, ktx, png, psd, qoi, tga, tiff (tif), webp ...
MIT License
106 stars 26 forks source link

imageinfo

Cross platform super fast single header c++ library to get image size and format without loading/decoding.

The imageinfo don't get image format by file ext name, but infer by file header bytes and character.

As few I/O times as possible! Read as few bytes as possible!

Some test image files are from image-size. Many thanks to @netroy.

Rust version: imageinfo-rs

ci

imageinfo has been restructured, if you are using old version, please check v1 branch.

Supported formats

Vcpkg

imageinfo is available on vcpkg

vcpgk install imageinfo

Build & Test

Linux & MacOS

cmake -B build .
cmake --build build -- all
cmake --build build -- check

Windows

Open Visual Studio Command Prompt and run these command

cmake -G "NMake Makefiles" -B build .
cmake --build build -- all
cmake --build build -- check

Usage

Simplest Demo

const char *file = "images/valid/jpg/sample.jpg";
auto info = imageinfo::parse<imageinfo::FilePathReader>(file);
std::cout << "File: " << file << "\n";
std::cout << "  - Error    : " << info.error_msg() << "\n";
std::cout << "  - Width    : " << info.size().width << "\n";
std::cout << "  - Height   : " << info.size().height << "\n";
std::cout << "  - Format   : " << info.format() << "\n";
std::cout << "  - Ext      : " << info.ext() << "\n";
std::cout << "  - Full Ext : " << info.full_ext() << "\n";
std::cout << "  - Mimetype : " << info.mimetype() << "\n\n";

You can pass a file path and use imageinfo::FilePathReader,

and there are some builtin reader imageinfo::FileReader, imageinfo::FileStreamReader, imageinfo::RawDataReader

FILE *file = fopen("images/valid/jpg/sample.jpg", "rb");
auto info = imageinfo::parse<imageinfo::FileReader>(file);
fclose(file);
std::ifstream file("images/valid/jpg/sample.jpg", std::ios::in | std::ios::binary);
auto info = imageinfo::parse<imageinfo::FileStreamReader>(file);
file.close();
// Suppose we already got data and size
// void *data;
// size_t size;
auto info = imageinfo::parse<imageinfo::RawDataReader>(imageinfo::RawData(data, size));

If you known the file is likely a JPEG, you can provide likely_formats parameter to improve performance;

auto imageInfo = imageinfo::parse<imageinfo::FilePathReader>("images/valid/jpg/sample.jpg", {II_FORMAT_JPEG});

Custom Reader

First, take a look at imageinfo::FileReader, all your need to do is define a class and implement size and read method. (not override)

class FileReader {
public:
    explicit FileReader(FILE *file) : file_(file) {}

    inline size_t size() {
        if (file_ != nullptr) {
            fseek(file_, 0, SEEK_END);
            return ftell(file_);
        } else {
            return 0;
        }
    }

    inline void read(void *buf, off_t offset, size_t size) {
        fseek(file_, offset, SEEK_SET);
        fread(buf, 1, size, file_);
    }

private:
    FILE *file_ = nullptr;
};

Then, let's try to make a reader for Android assets file

class AndroidAssetFileReader {
public:
    explicit AndroidAssetFileReader(AAsset *file) : file_(file) {}

    inline size_t size() {
        if (file_ != nullptr) {
            return AAsset_getLength(file_);
        } else {
            return 0;
        }
    }

    inline void read(void *buf, off_t offset, size_t size) {
        AAsset_seek(file_, offset, SEEK_SET);
        AAsset_read(file_, buf, size);
    }

private:
    AAsset *file_ = nullptr;
};
// Suppose we have a AAssetManager
// AAssetManager *manager;
// Open with AASSET_MODE_RANDOM mode to seek forward and backward
AAsset *file = AAssetManager_open(manager, "test.png", AASSET_MODE_RANDOM);
auto imageInfo = imageinfo::parse<imageinfo::AndroidAssetFileReader>(file);
AAsset_close(file);

Pretty easy?

Don't be stingy with your star : )