mirror of https://github.com/KLayout/klayout.git
Add PixelBuffer#from_bytes and width/height header to to_bytes
This commit is contained in:
parent
35ec1107b6
commit
2fa7b24345
|
|
@ -126,12 +126,32 @@ static std::vector<char> pixel_buffer_to_png (const tl::PixelBuffer *pb)
|
|||
#endif
|
||||
}
|
||||
|
||||
// Returns the raw ARGB32 pixel data as a byte vector (no encoding overhead)
|
||||
// Returns an 8-byte header (width, height as uint32) followed by the raw ARGB32 pixel data
|
||||
static std::vector<char> pixel_buffer_to_bytes (const tl::PixelBuffer *pb)
|
||||
{
|
||||
const char *p = (const char *) pb->data ();
|
||||
size_t n = (size_t) pb->width () * (size_t) pb->height () * 4;
|
||||
return std::vector<char> (p, p + n);
|
||||
uint32_t w = pb->width (), h = pb->height ();
|
||||
size_t n = (size_t) w * (size_t) h * 4;
|
||||
std::vector<char> data (8 + n);
|
||||
memcpy (data.data (), &w, 4);
|
||||
memcpy (data.data () + 4, &h, 4);
|
||||
memcpy (data.data () + 8, pb->data (), n);
|
||||
return data;
|
||||
}
|
||||
|
||||
// Inverse of to_bytes: reads width/height from the header and checks the length
|
||||
static tl::PixelBuffer pixel_buffer_from_bytes (const std::vector<char> &data)
|
||||
{
|
||||
uint32_t w = 0, h = 0;
|
||||
if (data.size () >= 8) {
|
||||
memcpy (&w, data.data (), 4);
|
||||
memcpy (&h, data.data () + 4, 4);
|
||||
}
|
||||
if (data.size () != 8 + (size_t) w * (size_t) h * 4) {
|
||||
throw tl::Exception (tl::to_string (tr ("Invalid PixelBuffer byte stream: length does not match the width and height in the header")));
|
||||
}
|
||||
tl::PixelBuffer pb (w, h, (const tl::color_t *) (data.data () + 8));
|
||||
pb.set_transparent (true);
|
||||
return pb;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -199,10 +219,19 @@ Class<tl::PixelBuffer> decl_PixelBuffer ("lay", "PixelBuffer",
|
|||
gsi::method_ext ("to_bytes", &pixel_buffer_to_bytes,
|
||||
"@brief Converts the pixel buffer to a raw byte stream\n"
|
||||
"\n"
|
||||
"Returns the raw ARGB32 pixel data with 4 bytes per pixel in row-major order, "
|
||||
"top to bottom. Unlike \\to_png_data this method has zero encoding overhead.\n"
|
||||
"The stream starts with an 8-byte header (width and height as 32-bit unsigned integers) "
|
||||
"followed by the raw ARGB32 pixel data with 4 bytes per pixel in row-major order, "
|
||||
"top to bottom. Unlike \\to_png_data this method has zero encoding overhead. "
|
||||
"Use \\from_bytes to reconstruct the pixel buffer.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.30.9."
|
||||
"This method has been added in version 0.30.10."
|
||||
) +
|
||||
gsi::method ("from_bytes", &pixel_buffer_from_bytes, gsi::arg ("data"),
|
||||
"@brief Reconstructs a pixel buffer from a byte stream produced by \\to_bytes\n"
|
||||
"\n"
|
||||
"The width and height are taken from the header and the stream length is checked against them.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.30.10."
|
||||
) +
|
||||
gsi::method ("patch", &tl::PixelBuffer::patch, gsi::arg ("other"),
|
||||
"@brief Patches another pixel buffer into this one\n"
|
||||
|
|
|
|||
|
|
@ -57,6 +57,27 @@ class LAYPixelBufferTests(unittest.TestCase):
|
|||
pb_copy = pya.PixelBuffer.read_png(tmp)
|
||||
self.assertEqual(compare(pb, pb_copy), True)
|
||||
|
||||
def test_2(self):
|
||||
|
||||
# to_bytes / from_bytes round-trip
|
||||
|
||||
import struct
|
||||
|
||||
pb = pya.PixelBuffer(10, 20)
|
||||
pb.transparent = True
|
||||
pb.fill(0xf0010203)
|
||||
pb.set_pixel(1, 2, 0x80102030)
|
||||
|
||||
data = bytes(pb.to_bytes())
|
||||
self.assertEqual(len(data), 8 + 10 * 20 * 4)
|
||||
self.assertEqual(struct.unpack("=II", data[0:8]), (10, 20)) # width, height header
|
||||
|
||||
self.assertEqual(pb == pya.PixelBuffer.from_bytes(data), True)
|
||||
|
||||
# a mismatched stream is rejected
|
||||
with self.assertRaises(Exception):
|
||||
pya.PixelBuffer.from_bytes(data[:-4])
|
||||
|
||||
|
||||
# run unit tests
|
||||
if __name__ == '__main__':
|
||||
|
|
|
|||
|
|
@ -152,6 +152,32 @@ class LAYPixelBuffer_TestClass < TestBase
|
|||
|
||||
end
|
||||
|
||||
def test_5
|
||||
|
||||
# to_bytes / from_bytes round-trip
|
||||
|
||||
pb = RBA::PixelBuffer::new(10, 20)
|
||||
pb.transparent = true
|
||||
pb.fill(0xf0010203)
|
||||
pb.set_pixel(1, 2, 0x80102030)
|
||||
|
||||
bytes = pb.to_bytes
|
||||
assert_equal(bytes.size, 8 + 10 * 20 * 4)
|
||||
assert_equal(bytes[0, 8].unpack("VV"), [ 10, 20 ]) # width, height header
|
||||
|
||||
assert_equal(pb == RBA::PixelBuffer.from_bytes(bytes), true)
|
||||
|
||||
# a mismatched stream is rejected
|
||||
error = false
|
||||
begin
|
||||
RBA::PixelBuffer.from_bytes(bytes[0, bytes.size - 4])
|
||||
rescue
|
||||
error = true
|
||||
end
|
||||
assert_equal(error, true)
|
||||
|
||||
end
|
||||
|
||||
def test_11
|
||||
|
||||
pb = RBA::BitmapBuffer::new
|
||||
|
|
|
|||
Loading…
Reference in New Issue