Skip to content

Commit

Permalink
Add size-validation and 128bit "mode" to from_blob
Browse files Browse the repository at this point in the history
  • Loading branch information
Kjarrigan committed Mar 26, 2018
1 parent 6726e88 commit 67b09da
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 4 deletions.
21 changes: 19 additions & 2 deletions ext/gosu/gosu.i
Original file line number Diff line number Diff line change
Expand Up @@ -662,8 +662,25 @@ namespace Gosu
%newobject from_blob;
static Gosu::Image* from_blob(const std::string& blob, int width, int height)
{
Gosu::Bitmap bitmap(width, height);
memcpy(bitmap.data(), &blob[0], width * height * 4);
Gosu::Bitmap bitmap(width, height, Gosu::Color::NONE);

std::size_t size = width * height * 4;
if (blob.size() == size) {
// 32 bit per pixel, assume R8G8B8A8
std::memcpy(bitmap.data(), &blob[0], size);
}
else if (blob.size() == size * sizeof(float)) {
// 128 bit per channel, assume float/float/float/float
const float* in = reinterpret_cast<const float*>(&blob);
Gosu::Color::Channel* out = reinterpret_cast<Gosu::Color::Channel*>(bitmap.data());
for (int i = size; i > 0; --i) {
*(out++) = static_cast<Gosu::Color::Channel>(*(in++) * 255);
}
}
else {
rb_raise(rb_eArgError, "Blob length mismatch (%i) - must be 4 * width * height (as 32bit "
"R8G8B8A8 or 128bit float/float/float/float", blob.size());
}

return new Gosu::Image(bitmap);
}
Expand Down
21 changes: 19 additions & 2 deletions src/RubyGosu.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -2889,8 +2889,25 @@ SWIGINTERN Gosu::Image *Gosu_Image_subimage(Gosu::Image *self,int x,int y,int w,
return image_data.get() ? new Gosu::Image(std::move(image_data)) : nullptr;
}
SWIGINTERN Gosu::Image *Gosu_Image_from_blob(std::string const &blob,int width,int height){
Gosu::Bitmap bitmap(width, height);
memcpy(bitmap.data(), &blob[0], width * height * 4);
Gosu::Bitmap bitmap(width, height, Gosu::Color::NONE);

std::size_t size = width * height * 4;
if (blob.size() == size) {
// 32 bit per pixel, assume R8G8B8A8
std::memcpy(bitmap.data(), &blob[0], size);
}
else if (blob.size() == size * sizeof(float)) {
// 128 bit per channel, assume float/float/float/float
const float* in = reinterpret_cast<const float*>(&blob);
Gosu::Color::Channel* out = reinterpret_cast<Gosu::Color::Channel*>(bitmap.data());
for (int i = size; i > 0; --i) {
*(out++) = static_cast<Gosu::Color::Channel>(*(in++) * 255);
}
}
else {
rb_raise(rb_eArgError, "Blob length mismatch (%i) - must be 4 * width * height (as 32bit "
"R8G8B8A8 or 128bit float/float/float/float", blob.size());
}

return new Gosu::Image(bitmap);
}
Expand Down
8 changes: 8 additions & 0 deletions test/test_image.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@ def test_subimage
def test_from_blob
img = Gosu::Image.new(media_path('triangle-25.bmp'))
assert_equal img.to_blob, Gosu::Image.from_blob(img.to_blob, 25, 25).to_blob

# TODO: "Fix" this test. so far it looks like the resulting image is different every time I rerun the test Oo?
# Maybe use a real 128bit image as base so the differences are easier to spot - at the moment it 95% transparent
# with a few dots here and there.
Gosu::Image.from_blob(img.to_blob*4, 25, 25)

assert_raises(::ArgumentError) { Gosu::Image.from_blob(img.to_blob, 26, 25) }
assert_raises(::ArgumentError) { Gosu::Image.from_blob(img.to_blob*2, 25, 25) }
end

#----------- Drawing an image
Expand Down

0 comments on commit 67b09da

Please sign in to comment.