Files
bimg/tools/meta/meta.cpp
2026-08-09 01:23:58 -07:00

217 lines
4.5 KiB
C++

/*
* Copyright 2011-2026 Branimir Karadzic. All rights reserved.
* License: https://github.com/bkaradzic/bimg/blob/master/LICENSE
*/
#include <bx/bx.h>
#include <bx/allocator.h>
#include <bx/commandline.h>
#include <bx/file.h>
#include <bx/readerwriter.h>
#include <bx/string.h>
#include <bimg/bimg.h>
#include <bimg/decode.h>
#define BIMG_META_VERSION_MAJOR 1
#define BIMG_META_VERSION_MINOR 0
static const char* orientationName(bimg::Orientation::Enum _orientation)
{
switch (_orientation)
{
case bimg::Orientation::R0: return "0";
case bimg::Orientation::R90: return "rotate 90";
case bimg::Orientation::R180: return "rotate 180";
case bimg::Orientation::R270: return "rotate 270";
case bimg::Orientation::HFlip: return "h-flip";
case bimg::Orientation::HFlipR90: return "h-flip+rotate 90";
case bimg::Orientation::HFlipR270: return "h-flip+rotate 270";
case bimg::Orientation::VFlip: return "v-flip";
default: break;
}
return "unknown";
}
static void version()
{
bx::printf(
"meta, bimg image metadata tool, version %d.%d.%d.\n"
"Copyright 2011-2026 Branimir Karadzic. All rights reserved.\n"
"License: https://github.com/bkaradzic/bimg/blob/master/LICENSE\n"
, BIMG_META_VERSION_MAJOR
, BIMG_META_VERSION_MINOR
, BIMG_API_VERSION
);
}
static const bx::CommandLineOption s_options[] =
{
{ 'h', "help", 0, NULL, "Display this help and exit." },
{ 'v', "version", 0, NULL, "Output version information and exit." },
};
static void help(const char* _error = NULL)
{
if (NULL != _error)
{
bx::printf("Error:\n%s\n\n", _error);
}
version();
bx::printf(
"\n"
"Usage: meta <file> [<file>...]\n"
"\n"
"Prints image metadata (format, dimensions, mips, etc.) for each input\n"
"file without decoding pixel data, similar to the UNIX `file` tool.\n"
"\n"
"Options:\n"
);
bx::Error err;
bx::write(bx::getStdOut(), s_options, BX_COUNTOF(s_options), &err);
bx::printf(
"\n"
"For more information, see https://github.com/bkaradzic/bimg\n"
);
}
static bool processFile(bx::AllocatorI* _allocator, const char* _filePath)
{
bx::Error err;
bx::FileReader reader;
if (!bx::open(&reader, _filePath, &err) )
{
bx::printf("%s: cannot open file\n", _filePath);
return false;
}
const uint32_t size = uint32_t(bx::getSize(&reader) );
if (0 == size)
{
bx::close(&reader);
bx::printf("%s: empty file\n", _filePath);
return false;
}
void* data = bx::alloc(_allocator, size);
bx::read(&reader, data, size, &err);
bx::close(&reader);
if (!err.isOk() )
{
bx::free(_allocator, data);
bx::printf("%s: failed to read file\n", _filePath);
return false;
}
bimg::ImageContainer info;
const bool parsed = bimg::imageParseInfo(_allocator, info, data, size, &err);
bx::free(_allocator, data);
if (!parsed)
{
bx::printf("%s: not a recognized image (%S)\n", _filePath, &err.getMessage() );
return false;
}
bx::printf("%s: %s image, %u x %u"
, _filePath
, bimg::getName(info.m_parser)
, info.m_width
, info.m_height
);
if (info.m_depth > 1)
{
bx::printf(" x %u", info.m_depth);
}
bx::printf(", %s", bimg::getName(info.m_format) );
if (info.m_cubeMap)
{
bx::printf(", cubemap");
}
if (info.m_numLayers > 1)
{
bx::printf(", %u layers", info.m_numLayers);
}
if (info.m_numMips > 1)
{
bx::printf(", %u mips", info.m_numMips);
}
if (info.m_hasAlpha)
{
bx::printf(", alpha");
}
if (info.m_srgb)
{
bx::printf(", sRGB");
}
if (bimg::Orientation::R0 != info.m_orientation)
{
bx::printf(", %s", orientationName(info.m_orientation) );
}
bx::printf("\n");
return true;
}
int main(int _argc, const char* _argv[])
{
bx::CommandLine cmdLine(_argc, _argv, s_options, BX_COUNTOF(s_options) );
if (cmdLine.hasArg('v', "version") )
{
version();
return bx::kExitSuccess;
}
if (cmdLine.hasArg('h', "help") )
{
help();
return bx::kExitSuccess;
}
const char* unknown = cmdLine.findUnknownOption();
if (NULL != unknown)
{
char error[256];
bx::snprintf(error, BX_COUNTOF(error), "Unknown option '%s'.", unknown);
help(error);
return bx::kExitFailure;
}
bx::DefaultAllocator allocator;
bool any = false;
bool ok = true;
for (int32_t ii = 1, num = cmdLine.getNumPositional(); ii < num; ++ii)
{
any = true;
ok &= processFile(&allocator, cmdLine.getPositional(ii) );
}
if (!any)
{
help("No input file specified.");
return bx::kExitFailure;
}
return ok ? bx::kExitSuccess : bx::kExitFailure;
}