diff --git a/paligemma/image.cc b/paligemma/image.cc index 76753d8..2853712 100644 --- a/paligemma/image.cc +++ b/paligemma/image.cc @@ -64,6 +64,69 @@ void SkipWhitespaceAndComments(std::istream& in) { } in.unget(); // Rewind last byte. } + +template > +class basic_spanbuf : public std::basic_streambuf { + public: + using base_type = std::basic_streambuf; + using char_type = typename base_type::char_type; + using traits_type = typename base_type::traits_type; + using int_type = typename traits_type::int_type; + using pos_type = typename traits_type::pos_type; + using off_type = typename traits_type::off_type; + + basic_spanbuf(const hwy::Span& buf) { + this->setg(buf.data(), buf.data(), buf.data() + buf.size()); + } + + std::streamsize showmanyc() override { + return this->egptr() - this->gptr(); + } + + std::streamsize xsgetn(char_type* s, std::streamsize n) override { + if (n == 0) { + return 0; + } + if (this->gptr() + n > this->egptr()) { + n = this->egptr() - this->gptr(); + if (n == 0) { + if (this->uflow() == traits_type::eof()) { + return -1; + } + return 0; + } + } + std::memmove(s, this->gptr(), n); + this->gbump(n); + return n; + } + + int_type pbackfail(int_type c) override { + *(this->gptr() - 1) = traits_type::to_char_type(c); + this->pbump(-1); + return 1; + } +}; + +template > +class basic_ispanstream : public std::basic_istream { + public: + using base_type = std::basic_istream; + using char_type = typename base_type::char_type; + using traits_type = typename base_type::traits_type; + using int_type = typename traits_type::int_type; + using pos_type = typename traits_type::pos_type; + using off_type = typename traits_type::off_type; + + basic_ispanstream(const hwy::Span& buf) + : base_type(nullptr) + , sb_(buf) { + this->init(&sb_); + } + + private: + basic_spanbuf sb_; +}; } // namespace bool Image::ReadPPM(const std::string& filename) { @@ -123,6 +186,11 @@ bool Image::ReadPPM(std::istream& in) { return true; } +bool Image::ReadPPM(const hwy::Span& buf) { + basic_ispanstream in(buf); + return ReadPPM(in); +} + void Image::Resize() { int new_width = 224; int new_height = kImageSize; diff --git a/paligemma/image.h b/paligemma/image.h index 1b15215..ad3a3c3 100644 --- a/paligemma/image.h +++ b/paligemma/image.h @@ -21,6 +21,8 @@ #include #include +#include "hwy/aligned_allocator.h" // Span + namespace gcpp { // Very basic image loading and processing for PaliGemma-224. Does not try to be @@ -34,6 +36,9 @@ class Image { // Reads PPM format (P6, binary) data from a stream, normalizes to [-1, 1]. // Returns true on success. bool ReadPPM(std::istream& in); + // Reads PPM format (P6, binary) data from a hwy::Span, normalizes to [-1, 1]. + // Returns true on success. + bool ReadPPM(const hwy::Span& buf); // Resizes to 224x224 (nearest-neighbor for now, bilinear or antialias would // be better). void Resize();