From db56b0293e32e050f9d842d1d263a39e30ef921c Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 5 Nov 2024 03:15:40 +0000 Subject: [PATCH] Add a Layout.read_bytes() method that reads a layout from a byte array in Python or Ruby. This is much more convenient and a bit more efficient than writing the bytes to a temporary file and reading that back in. It's useful when we have received a layout over the network or embedded in some file. This makes a copy of the bytes but there doesn't seem to be any way to avoid that currently. --- src/db/db/gsiDeclDbReader.cc | 19 +++++++++++++++++++ testdata/python/dbLayoutTest.py | 21 +++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/db/db/gsiDeclDbReader.cc b/src/db/db/gsiDeclDbReader.cc index 7d588a524a..981e19b150 100644 --- a/src/db/db/gsiDeclDbReader.cc +++ b/src/db/db/gsiDeclDbReader.cc @@ -433,6 +433,15 @@ namespace gsi return reader.read (*layout, options); } + static db::LayerMap + load_bytes_with_options (db::Layout *layout, const std::vector &bytes, const db::LoadLayoutOptions &options) + { + tl::InputMemoryStream byte_stream (bytes.data(), bytes.size()); + tl::InputStream stream (byte_stream); + db::Reader reader (stream); + return reader.read (*layout, options); + } + // extend the layout class by two reader methods static gsi::ClassExt layout_reader_decl ( @@ -454,6 +463,16 @@ namespace gsi "@return A layer map that contains the mapping used by the reader including the layers that have been created." "\n" "This method has been added in version 0.18." + ) + + gsi::method_ext ("read_bytes", &load_bytes_with_options, gsi::arg ("bytes"), gsi::arg ("options"), + "@brief Load the layout from the given bytes array with options\n" + "The format of the file is determined automatically and automatic unzipping is provided. " + "In this version, some reader options can be specified. " + "@param bytes The data to load.\n" + "@param options The options object specifying further options for the reader.\n" + "@return A layer map that contains the mapping used by the reader including the layers that have been created." + "\n" + "This method has been added in version 0.29." ), "" ); diff --git a/testdata/python/dbLayoutTest.py b/testdata/python/dbLayoutTest.py index 1e01a3533f..8f88d52d90 100644 --- a/testdata/python/dbLayoutTest.py +++ b/testdata/python/dbLayoutTest.py @@ -1200,6 +1200,27 @@ def test_bug1397(self): self.assertEqual(str(t), "r180 0,0") + def test_read_bytes(self): + + testtmp = os.getenv("TESTTMP_WITH_NAME", os.getenv("TESTTMP", ".")) + + file_gds = os.path.join(testtmp, "bytes.gds") + + ly = pya.Layout() + top = ly.create_cell("TOP") + l1 = ly.layer(1, 0) + shape = top.shapes(l1).insert(pya.Box(0, 10, 20, 30)) + ly.write(file_gds) + + with open(file_gds, "rb") as f: + byte_buffer = f.read() + + ly2 = pya.Layout() + ly2.read_bytes(byte_buffer, pya.LoadLayoutOptions()) + l2 = ly2.layer(1, 0) + self.assertEqual(ly2.top_cell().bbox().to_s(), "(0,10;20,30)") + + # run unit tests if __name__ == '__main__': suite = unittest.TestLoader().loadTestsFromTestCase(DBLayoutTest)