[Git][debian-gis-team/glymur][master] 5 commits: New upstream version 0.11.1
Antonio Valentino (@antonio.valentino)
gitlab at salsa.debian.org
Tue Aug 9 08:12:16 BST 2022
Antonio Valentino pushed to branch master at Debian GIS Project / glymur
Commits:
194a02ee by Antonio Valentino at 2022-08-09T06:46:25+00:00
New upstream version 0.11.1
- - - - -
d653e98e by Antonio Valentino at 2022-08-09T06:46:29+00:00
Update upstream source from tag 'upstream/0.11.1'
Update to upstream version '0.11.1'
with Debian dir c10e6e0c53ef88b6f3ab8df3564bf5cf34021642
- - - - -
4a1626f1 by Antonio Valentino at 2022-08-09T06:47:02+00:00
New upstream release
- - - - -
4ede276e by Antonio Valentino at 2022-08-09T07:03:02+00:00
New 0001-Remove-breakpoint.patch
- - - - -
f4f179f3 by Antonio Valentino at 2022-08-09T07:03:24+00:00
Set dustribution to unstable
- - - - -
12 changed files:
- CHANGES.txt
- debian/changelog
- + debian/patches/0001-Remove-breakpoint.patch
- + debian/patches/series
- docs/source/conf.py
- docs/source/whatsnew/0.11.rst
- glymur/tiff.py
- glymur/version.py
- setup.cfg
- tests/test_jp2k.py
- tests/test_libtiff.py
- tests/test_tiff2jp2.py
Changes:
=====================================
CHANGES.txt
=====================================
@@ -1,3 +1,6 @@
+August 6, 2022 - v0.11.1
+ Improve efficiency of striped TIFF to tiled JP2 conversion
+
July 29, 2022 - v0.11.0
Add options for supporting ResolutionBoxes
Fix ctypes interface to C library on windows
=====================================
debian/changelog
=====================================
@@ -1,3 +1,11 @@
+glymur (0.11.1-1) unstable; urgency=medium
+
+ * New upstream release.
+ * debian/patches:
+ - new patch 0001-Remove-breakpoint.patch.
+
+ -- Antonio Valentino <antonio.valentino at tiscali.it> Tue, 09 Aug 2022 07:03:09 +0000
+
glymur (0.11.0-3) unstable; urgency=medium
* Skip test_thread_support: not supported on all platforms.
=====================================
debian/patches/0001-Remove-breakpoint.patch
=====================================
@@ -0,0 +1,21 @@
+From: Antonio Valentino <antonio.valentino at tiscali.it>
+Date: Tue, 9 Aug 2022 07:00:57 +0000
+Subject: Remove breakpoint
+
+Forwarded: https://github.com/quintusdias/glymur/pull/570
+---
+ tests/test_jp2k.py | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/tests/test_jp2k.py b/tests/test_jp2k.py
+index ec85cb3..af43f4d 100644
+--- a/tests/test_jp2k.py
++++ b/tests/test_jp2k.py
+@@ -1259,7 +1259,6 @@ class TestJp2k_write(fixtures.MetadataBase):
+
+ EXPECTED RESULT: A TLM segment is detected.
+ """
+- breakpoint()
+ kwargs = {
+ 'data': self.jp2_data,
+ 'tlm': True
=====================================
debian/patches/series
=====================================
@@ -0,0 +1 @@
+0001-Remove-breakpoint.patch
=====================================
docs/source/conf.py
=====================================
@@ -78,7 +78,7 @@ copyright = '2013-2022, John Evans'
# The short X.Y version.
version = '0.11'
# The full version, including alpha/beta/rc tags.
-release = '0.11.0'
+release = '0.11.1'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
=====================================
docs/source/whatsnew/0.11.rst
=====================================
@@ -2,6 +2,12 @@
Changes in glymur 0.11
######################
+*****************
+Changes in 0.11.1
+*****************
+ * Improve efficiency of striped TIFF to tiled JP2 conversion
+
+
*****************
Changes in 0.11.0
*****************
=====================================
glymur/tiff.py
=====================================
@@ -495,45 +495,6 @@ class Tiff2Jp2k(object):
offset, = struct.unpack(self.endian + 'I', buffer)
tfp.seek(offset)
- def _process_header(self, b, tfp):
-
- buffer = tfp.read(4)
- data = struct.unpack('BB', buffer[:2])
-
- # big endian or little endian?
- if data[0] == 73 and data[1] == 73:
- # little endian
- endian = '<'
- elif data[0] == 77 and data[1] == 77:
- # big endian
- endian = '>'
- else:
- msg = (
- f"The byte order indication in the TIFF header "
- f"({data}) is invalid. It should be either "
- f"{bytes([73, 73])} or {bytes([77, 77])}."
- )
- raise RuntimeError(msg)
-
- # version number and offset to the first IFD
- version, = struct.unpack(endian + 'H', buffer[2:4])
- self.version = _TIFF if version == 42 else _BIGTIFF
-
- if self.version == _BIGTIFF:
- buffer = tfp.read(12)
- _, _, offset = struct.unpack(endian + 'HHQ', buffer)
- else:
- buffer = tfp.read(4)
- offset, = struct.unpack(endian + 'I', buffer)
- tfp.seek(offset)
-
- # write this 32-bit header into the UUID, no matter if we had bigtiff
- # or regular tiff or big endian
- data = struct.pack('<BBHI', 73, 73, 42, 8)
- b.write(data)
-
- return endian
-
def get_tag_value(self, tagnum):
"""
Return the value associated with the tag. Some tags are not actually
@@ -882,7 +843,7 @@ class Tiff2Jp2k(object):
):
"""
The input TIFF image is striped and we are to create the output
- JPEG2000 image as a single tile.
+ JPEG2000 image as a tiled JP2K.
Parameters
----------
@@ -904,25 +865,15 @@ class Tiff2Jp2k(object):
Write to this JPEG2000 file
"""
- partial_jp2_tile_rows = (imageheight / jth) != (imageheight // jth)
- partial_jp2_tile_cols = (imagewidth / jtw) != (imagewidth // jtw)
-
self.logger.debug(f'image: {imageheight} x {imagewidth}')
self.logger.debug(f'jptile: {jth} x {jtw}')
num_strips = libtiff.numberOfStrips(self.tiff_fp)
num_jp2k_tile_cols = int(np.ceil(imagewidth / jtw))
- partial_jp2_tile_rows = (imageheight / jth) != (imageheight // jth)
- partial_jp2_tile_cols = (imagewidth / jtw) != (imagewidth // jtw)
-
- tiff_strip = np.zeros((rps, imagewidth, spp), dtype=dtype)
- rgba_strip = np.zeros((rps, imagewidth, 4), dtype=np.uint8)
-
for idx, tilewriter in enumerate(jp2.get_tilewriters()):
- self.logger.info(f'Tile: #{idx}')
- jp2k_tile = np.zeros((jth, jtw, spp), dtype=dtype)
+ self.logger.info(f'Tile: #{idx}')
jp2k_tile_row = idx // num_jp2k_tile_cols
jp2k_tile_col = idx % num_jp2k_tile_cols
@@ -930,84 +881,111 @@ class Tiff2Jp2k(object):
# the coordinates of the upper left pixel of the jp2k tile
julr, julc = jp2k_tile_row * jth, jp2k_tile_col * jtw
- # Populate the jp2k tile with tiff strips.
- # Move by strips from the start of the jp2k tile to the bottom
- # of the jp2k tile. That last strip may be partially empty,
- # worry about that later.
- #
- # loop while the upper left corner of the current tiff file is
- # less than the lower left corner of the jp2k tile
- r = julr
- while (r // rps) * rps < min(julr + jth, imageheight):
+ if jp2k_tile_col == 0:
- stripnum = libtiff.computeStrip(self.tiff_fp, r, 0)
- self.logger.debug(f'Strip: #{stripnum}')
+ tiff_multi_strip = self._construct_multi_strip(
+ julr, num_strips, jth, imageheight, imagewidth, rps, spp,
+ dtype, use_rgba_interface
+ )
- if stripnum >= num_strips:
- # we've moved past the end of the tiff
- break
+ # Get the multi-strip coordinates of the upper left jp2k corner
+ stripnum = libtiff.computeStrip(self.tiff_fp, julr, 0)
+ tulr = stripnum * rps
- if use_rgba_interface:
+ ms_ulr = julr - tulr
+ ms_ulc = julc
- # must use the first row in the strip
- libtiff.readRGBAStrip(
- self.tiff_fp, stripnum * rps, rgba_strip
- )
- # must flip the rows (!!) and get rid of the alpha
- # plane
- tiff_strip = np.flipud(rgba_strip[:, :, :spp])
+ # ms_lrr = ms_ulr + min(ms_ulr + jth, imageheight)
+ # ms_lrc = ms_ulc + min(ms_ulc + jtw, imagewidth)
+ ms_lrr = min(ms_ulr + jth, imageheight - tulr)
+ ms_lrc = min(ms_ulc + jtw, imagewidth)
- else:
- libtiff.readEncodedStrip(
- self.tiff_fp, stripnum, tiff_strip
- )
+ rows = slice(ms_ulr, ms_lrr)
+ cols = slice(ms_ulc, ms_lrc)
- # the coordinates of the upper left pixel of the TIFF
- # strip
- tulr = stripnum * rps
- tulc = 0
+ tilewriter[:] = tiff_multi_strip[rows, cols, :]
- # determine how to fit this tiff strip into the jp2k
- # tile
- #
- # these are the section coordinates in image space
- ulr = max(julr, tulr)
- llr = min(julr + jth, tulr + rps)
+ def _construct_multi_strip(
+ self, julr, num_strips, jth, imageheight, imagewidth, rps, spp, dtype,
+ use_rgba_interface
+ ):
+ """
+ TIFF strips are pretty inefficient. If our I/O was stupidly focused
+ solely on each JP2K tile, we would read in each TIFF strip multiple
+ times. If instead, we read in ALL the strips that will encompass that
+ current row of JP2K tiles, we will save ourselves from pushing around
+ a lot of electrons.
- ulc = max(julc, tulc)
- urc = min(julc + jtw, tulc + imagewidth)
+ Parameters
+ ----------
+ imagewidth, imageheight, spp : int
+ TIFF tag values corresponding to the photometric interpretation,
+ image width and height, and samples per pixel.
+ jth : int
+ The number of rows in a JP2K tile.
+ rps : int
+ The number of rows per strip in the TIFF.
+ julr : int
+ The top row of the current JP2K tile row.
+ dtype : np.dtype
+ Datatype of the image.
+ use_rgba_interface : bool
+ If true, use the RGBA interface to read the TIFF image data.
- # convert to JP2K tile coordinates
- jrows = slice(ulr % jth, (llr - 1) % jth + 1)
- jcols = slice(ulc % jtw, (urc - 1) % jtw + 1)
+ Returns
+ -------
+ tiff_multi_strip : np.array
+ Holds all the TIFF strips that tightly encompass the current JP2K
+ tile row.
+ """
+ # We need to create a TIFF "multi-strip" that can hold all of
+ # the JP2K tiles in a JP2K tile row.
+ r = julr
+ top_strip_num = libtiff.computeStrip(self.tiff_fp, r, 0)
+
+ # advance thru to the next tile row
+ while (r // rps) * rps < min(julr + jth, imageheight):
+ r += rps
+ bottom_strip_num = libtiff.computeStrip(self.tiff_fp, r, 0)
+
+ # compute the number of rows contained between the top strip
+ # and the bottom strip
+ num_rows = (bottom_strip_num - top_strip_num) * rps
+
+ if use_rgba_interface:
+ tiff_strip = np.zeros((rps, imagewidth, 4), dtype=np.uint8)
+ tiff_multi_strip = np.zeros(
+ (num_rows, imagewidth, spp), dtype=np.uint8
+ )
+ else:
+ tiff_strip = np.zeros((rps, imagewidth, spp), dtype=dtype)
+ tiff_multi_strip = np.zeros(
+ (num_rows, imagewidth, spp), dtype=dtype
+ )
- # convert to TIFF strip coordinates
- trows = slice(ulr % rps, (llr - 1) % rps + 1)
- tcols = slice(ulc % imagewidth, (urc - 1) % imagewidth + 1)
+ # fill the multi-strip
+ for stripnum in range(top_strip_num, bottom_strip_num):
- jp2k_tile[jrows, jcols, :] = tiff_strip[trows, tcols, :]
+ if use_rgba_interface:
- r += rps
+ libtiff.readRGBAStrip(
+ self.tiff_fp, stripnum * rps, tiff_strip
+ )
- # last tile column? If so, we may have a partial tile.
- # j2k_cols is not sufficient here, must shorten it from 250
- # to 230
- if (
- partial_jp2_tile_cols
- and jp2k_tile_col == num_jp2k_tile_cols - 1
- ):
- # decrease the number of columns by however many it sticks
- # over the image width
- last_j2k_cols = slice(0, imagewidth - julc)
- jp2k_tile = jp2k_tile[:, last_j2k_cols, :].copy()
+ # must flip the rows (!!) and get rid of the alpha
+ # plane
+ tiff_strip = np.flipud(tiff_strip[:, :, :spp])
- if (
- partial_jp2_tile_rows
- and stripnum == num_strips - 1
- ):
- # decrease the number of rows by however many it sticks
- # over the image height
- last_j2k_rows = slice(0, imageheight - julr)
- jp2k_tile = jp2k_tile[last_j2k_rows, :, :].copy()
+ else:
- tilewriter[:] = jp2k_tile
+ libtiff.readEncodedStrip(
+ self.tiff_fp, stripnum, tiff_strip
+ )
+
+ # push the strip into the multi-strip
+ top_row = (stripnum - top_strip_num) * rps
+ bottom_row = (stripnum - top_strip_num + 1) * rps
+ rows = slice(top_row, bottom_row)
+ tiff_multi_strip[rows, :, :] = tiff_strip
+
+ return tiff_multi_strip
=====================================
glymur/version.py
=====================================
@@ -21,7 +21,7 @@ from .lib import tiff
# Do not change the format of this next line! Doing so risks breaking
# setup.py
-version = "0.11.0"
+version = "0.11.1"
version_tuple = parse(version).release
=====================================
setup.cfg
=====================================
@@ -1,6 +1,6 @@
[metadata]
name = Glymur
-version = 0.11.0
+version = 0.11.1
author = 'John Evans'
author_email = "John Evans" <john.g.evans.ne at gmail.com>
license = 'MIT'
=====================================
tests/test_jp2k.py
=====================================
@@ -1259,6 +1259,7 @@ class TestJp2k_write(fixtures.MetadataBase):
EXPECTED RESULT: A TLM segment is detected.
"""
+ breakpoint()
kwargs = {
'data': self.jp2_data,
'tlm': True
=====================================
tests/test_libtiff.py
=====================================
@@ -18,6 +18,9 @@ class TestSuite(fixtures.TestCommon):
def test_simple_tile(self):
"""
SCENARIO: create a simple monochromatic 2x2 tiled image
+
+ Expected result: The image matches. The number of tiles checks out.
+ The tile width and height checks out.
"""
data = fixtures.skimage.data.moon()
h, w = data.shape
@@ -58,6 +61,15 @@ class TestSuite(fixtures.TestCommon):
libtiff.readEncodedTile(fp, 3, tile)
actual_data[th:h, tw:w] = tile
- libtiff.close(fp)
-
np.testing.assert_array_equal(data, actual_data)
+
+ n = libtiff.numberOfTiles(fp)
+ self.assertEqual(n, 4)
+
+ actual_th = libtiff.getFieldDefaulted(fp, 'TileLength')
+ self.assertEqual(actual_th, th)
+
+ actual_tw = libtiff.getFieldDefaulted(fp, 'TileWidth')
+ self.assertEqual(actual_tw, tw)
+
+ libtiff.close(fp)
=====================================
tests/test_tiff2jp2.py
=====================================
@@ -383,6 +383,53 @@ class TestSuite(fixtures.TestCommon):
cls.astronaut_uint16_data = actual_data
cls.astronaut_uint16_filename = path
+ @classmethod
+ def setup_ycbcr_striped_jpeg(cls, path):
+ """
+ SCENARIO: create a simple color 2x1 stripped image
+ """
+ data = fixtures.skimage.data.astronaut()
+ h, w, z = data.shape
+ rps = h // 2
+
+ fp = libtiff.open(path, mode='w')
+
+ libtiff.setField(fp, 'Photometric', libtiff.Photometric.YCBCR)
+ libtiff.setField(fp, 'Compression', libtiff.Compression.JPEG)
+
+ l, w = data.shape[:2]
+ libtiff.setField(fp, 'ImageLength', l)
+ libtiff.setField(fp, 'ImageWidth', w)
+ libtiff.setField(fp, 'RowsPerStrip', rps)
+
+ libtiff.setField(fp, 'BitsPerSample', 8)
+ libtiff.setField(fp, 'SamplesPerPixel', 3)
+ libtiff.setField(fp, 'PlanarConfig', libtiff.PlanarConfig.CONTIG)
+ libtiff.setField(fp, 'JPEGColorMode', libtiff.PlanarConfig.CONTIG)
+ libtiff.setField(fp, 'JPEGQuality', 100)
+
+ libtiff.writeEncodedStrip(fp, 0, data[:rps, :, :])
+ libtiff.writeEncodedStrip(fp, 1, data[rps:rps * 2, :, :])
+
+ libtiff.close(fp)
+
+ # now read it back
+ fp = libtiff.open(path)
+
+ strip = np.zeros((rps, w, 4), dtype=np.uint8)
+ actual_data = np.zeros((h, w, 3), dtype=np.uint8)
+
+ libtiff.readRGBAStrip(fp, 0, strip)
+ actual_data[:rps, :, :] = strip[::-1, :, :3]
+
+ libtiff.readRGBAStrip(fp, rps, strip)
+ actual_data[rps:rps * 2, :, :] = strip[::-1, :, :3]
+
+ libtiff.close(fp)
+
+ cls.astronaut_ycbcr_striped_jpeg_data = actual_data
+ cls.astronaut_ycbcr_striped_jpeg_tif = path
+
@classmethod
def setup_ycbcr_jpeg(cls, path):
"""
@@ -564,6 +611,10 @@ class TestSuite(fixtures.TestCommon):
cls.test_tiff_path / 'astronaut_ycbcr_jpeg_tiled.tif'
)
+ cls.setup_ycbcr_striped_jpeg(
+ cls.test_tiff_path / 'astronaut_ycbcr_striped_jpeg.tif'
+ )
+
cls.setup_rgb_uint16(cls.test_tiff_path / 'astronaut_uint16.tif')
@classmethod
@@ -667,6 +718,67 @@ class TestSuite(fixtures.TestCommon):
self.assertEqual(j.box[-1].data['ImageWidth'], 512)
self.assertEqual(j.box[-1].data['ImageLength'], 512)
+ def test_smoke_rgba(self):
+ """
+ SCENARIO: Convert RGCA TIFF file to JP2
+
+ EXPECTED RESULT: data matches, number of resolution is the default.
+ There should be just one layer. The number of resolutions should be
+ the default (5). There are not PLT segments. There are no EPH
+ markers. There are no SOP markers. The progression order is LRCP.
+ The irreversible transform will NOT be used. PSNR cannot be tested
+ if it is not applied.
+
+ There is a UUID box appended at the end containing the metadata.
+ """
+ with Tiff2Jp2k(
+ self.astronaut_ycbcr_striped_jpeg_tif, self.temp_jp2_filename,
+ tilesize=[256, 256]
+ ) as j:
+ j.run()
+
+ j = Jp2k(self.temp_jp2_filename)
+
+ actual = j[:]
+ self.assertEqual(actual.shape, (512, 512, 3))
+
+ c = j.get_codestream(header_only=False)
+
+ actual = c.segment[2].code_block_size
+ expected = (64, 64)
+ self.assertEqual(actual, expected)
+
+ self.assertEqual(c.segment[2].layers, 1)
+ self.assertEqual(c.segment[2].num_res, 5)
+
+ at_least_one_eph = any(
+ isinstance(seg, glymur.codestream.EPHsegment)
+ for seg in c.segment
+ )
+ self.assertFalse(at_least_one_eph)
+
+ at_least_one_plt = any(
+ isinstance(seg, glymur.codestream.PLTsegment)
+ for seg in c.segment
+ )
+ self.assertFalse(at_least_one_plt)
+
+ at_least_one_sop = any(
+ isinstance(seg, glymur.codestream.SOPsegment)
+ for seg in c.segment
+ )
+ self.assertFalse(at_least_one_sop)
+
+ self.assertEqual(c.segment[2].prog_order, glymur.core.LRCP)
+
+ self.assertEqual(
+ c.segment[2].xform, glymur.core.WAVELET_XFORM_5X3_REVERSIBLE
+ )
+
+ self.assertEqual(j.box[-1].box_id, 'uuid')
+ self.assertEqual(j.box[-1].data['ImageWidth'], 512)
+ self.assertEqual(j.box[-1].data['ImageLength'], 512)
+
def test_geotiff(self):
"""
SCENARIO: Convert a one-component GEOTIFF file to JP2
@@ -961,7 +1073,7 @@ class TestSuite(fixtures.TestCommon):
"""
with Tiff2Jp2k(
self.minisblack_3strip_partial_last_strip, self.temp_jp2_filename,
- tilesize=(240, 240)
+ tilesize=(240, 240), verbose='DEBUG'
) as j:
j.run()
View it on GitLab: https://salsa.debian.org/debian-gis-team/glymur/-/compare/c93b7db12b9e11f6d42f8061834cc51855431670...f4f179f3a8dcd349f63dd234a8a9a4e56ad9c991
--
View it on GitLab: https://salsa.debian.org/debian-gis-team/glymur/-/compare/c93b7db12b9e11f6d42f8061834cc51855431670...f4f179f3a8dcd349f63dd234a8a9a4e56ad9c991
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20220809/409bc46a/attachment-0001.htm>
More information about the Pkg-grass-devel
mailing list