Skip to content

Commit

Permalink
karm-image: Basic gif metadata extraction.
Browse files Browse the repository at this point in the history
  • Loading branch information
sleepy-monax committed Nov 16, 2024
1 parent 7178b13 commit c68c1b0
Show file tree
Hide file tree
Showing 12 changed files with 111 additions and 11 deletions.
4 changes: 4 additions & 0 deletions src/apps/hideo-images/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ Async::Task<> entryPointAsync(Sys::Context &ctx) {
if (args.len()) {
auto url = co_try$(Mime::parseUrlOrPath(args[0]));
image = Image::load(url);

if (not image) {
logError("Failed to load image: {}", image.none());
}
}

co_return Ui::runApp(ctx, Hideo::Images::app(image));
Expand Down
2 changes: 1 addition & 1 deletion src/apps/hideo-images/viewer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Ui::Child viewer(State const &state) {

Ui::Child viewerPreview(State const &state) {
if (not state.image)
return Kr::errorPage(Mdi::ALERT_DECAGRAM, "No Image"s, "Unable to display this image."s);
return Kr::errorPage(Mdi::ALERT_DECAGRAM, "Unable to display this image."s, Str{state.image.none().msg()});

return Ui::image(state.image.unwrap()) |
Ui::box({
Expand Down
8 changes: 4 additions & 4 deletions src/libs/karm-image/bmp/decoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ Res<Decoder> Decoder::init(Bytes slice) {

Decoder dec{};
Io::BScan s{slice};
try$(dec.readHeader(s));
try$(dec.readInfoHeader(s));
try$(dec._readHeader(s));
try$(dec._readInfoHeader(s));
try$(dec._readPalette(s));
try$(dec._readPixels(s));

return Ok(dec);
}

Res<> Decoder::readHeader(Io::BScan &s) {
Res<> Decoder::_readHeader(Io::BScan &s) {
if (s.rem() < 54) {
return Error::invalidData("image too small");
}
Expand All @@ -30,7 +30,7 @@ Res<> Decoder::readHeader(Io::BScan &s) {
return Ok();
}

Res<> Decoder::readInfoHeader(Io::BScan &s) {
Res<> Decoder::_readInfoHeader(Io::BScan &s) {
auto start = s.tell();
auto size = s.nextU32le(); // header size
if (size < 40) {
Expand Down
7 changes: 3 additions & 4 deletions src/libs/karm-image/bmp/decoder.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#pragma once

// BMP image decoder/encoder
// BMP image decoder
// References:
// - https://en.wikipedia.org/wiki/BMP_file_format
// - https://docs.microsoft.com/en-us/windows/win32/gdi/bitmap-storage
Expand All @@ -10,7 +10,6 @@
#include <karm-base/vec.h>
#include <karm-gfx/buffer.h>
#include <karm-io/bscan.h>
#include <karm-io/emit.h>
#include <karm-logger/logger.h>

namespace Bmp {
Expand All @@ -31,7 +30,7 @@ struct Decoder {

usize _dataOffset;

Res<> readHeader(Io::BScan &s);
Res<> _readHeader(Io::BScan &s);

isize _width;
isize _height;
Expand All @@ -53,7 +52,7 @@ struct Decoder {

usize _numsColors;

Res<> readInfoHeader(Io::BScan &s);
Res<> _readInfoHeader(Io::BScan &s);

// MARK: Palette -----------------------------------------------------------

Expand Down
74 changes: 74 additions & 0 deletions src/libs/karm-image/gif/decoder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#pragma once

// GIF Image decoder
// References:
// - https://www.w3.org/Graphics/GIF/spec-gif89a.txt

#include <karm-gfx/buffer.h>
#include <karm-io/bscan.h>

namespace Gif {

struct Decoder {
struct Header {
Array<u8, 6> signature;
};

struct LogicalScreenDescriptor {
u16le width;
u16le height;
u8 packed;
u8 backgroundColorIndex;
u8 pixelAspectRatio;
};

static bool sniff(Bytes slice) {
bool isGif = slice.len() >= 6 and
slice[0] == 'G' and
slice[1] == 'I' and
slice[2] == 'F';

bool isGif89a = slice.len() >= 6 and
slice[3] == '8' and
slice[4] == '9' and
slice[5] == 'a';

bool isGif87a = slice.len() >= 6 and
slice[3] == '8' and
slice[4] == '7' and
slice[5] == 'a';

return isGif and (isGif89a or isGif87a);
}

static Res<Decoder> init(Bytes slice) {
if (not sniff(slice))
return Error::invalidData("invalid signature");

Decoder dec{};
Io::BScan scan{slice};

Header header{};
scan.readTo(&header);

LogicalScreenDescriptor lsd{};
scan.readTo(&lsd);

dec._size = {lsd.width, lsd.height};

return Ok(dec);
}

Math::Vec2i _size;

isize width() const { return _size.x; }

isize height() const { return _size.y; }

Res<> decode(Gfx::MutPixels pixels) {
(void)pixels;
return Ok();
}
};

} // namespace Gif
12 changes: 12 additions & 0 deletions src/libs/karm-image/gif/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1",
"id": "karm-image.gif",
"type": "lib",
"description": "GIF image decoding and encoding",
"props": {
"cpp-excluded": true
},
"requires": [
"karm-base"
]
}
Binary file added src/libs/karm-image/gif/tests/res/berd.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/libs/karm-image/gif/tests/res/bot.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/libs/karm-image/gif/tests/res/gif.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/libs/karm-image/gif/tests/res/tode.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 12 additions & 2 deletions src/libs/karm-image/loader.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <karm-sys/file.h>

#include "bmp/decoder.h"
#include "gif/decoder.h"
#include "jpeg/decoder.h"
#include "png/decoder.h"
#include "qoi/decoder.h"
Expand Down Expand Up @@ -39,13 +40,20 @@ static Res<Picture> loadJpeg(Bytes bytes) {
return Ok(img);
}

static Res<Picture> load(Bytes bytes) {
static Res<Picture> loadTga(Bytes bytes) {
auto tga = try$(Tga::Decoder::init(bytes));
auto img = Gfx::Surface::alloc({tga.width(), tga.height()});
try$(tga.decode(*img));
return Ok(img);
}

static Res<Picture> loadGif(Bytes bytes) {
auto gif = try$(Gif::Decoder::init(bytes));
auto img = Gfx::Surface::alloc({gif.width(), gif.height()});
try$(gif.decode(*img));
return Ok(img);
}

Res<Picture> load(Sys::Mmap &&map) {
if (Bmp::Decoder::sniff(map.bytes())) {
return loadBmp(map.bytes());
Expand All @@ -56,7 +64,9 @@ Res<Picture> load(Sys::Mmap &&map) {
} else if (Jpeg::Decoder::sniff(map.bytes())) {
return loadJpeg(map.bytes());
} else if (Tga::Decoder::sniff(map.bytes())) {
return load(map.bytes());
return loadTga(map.bytes());
} else if (Gif::Decoder::sniff(map.bytes())) {
return loadGif(map.bytes());
} else {
return Error::invalidData("unknown image format");
}
Expand Down
1 change: 1 addition & 0 deletions src/libs/karm-image/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"karm-image.png",
"karm-image.qoi",
"karm-image.tga",
"karm-image.gif",
"karm-gfx",
"karm-sys",
"karm-logger"
Expand Down

0 comments on commit c68c1b0

Please sign in to comment.