Skip to content

GeotiffReader decodes wrong value #1959

Closed

Description

@jdries

We have a simple unit test, based on single pixel images, to test an algorithm. With Geotrellis 1.0.0, this test fails because a test file is decoded incorrectly.
The code snippet below exposes the issue, it saves a single pixel geotiff, with a pixel value of 145. When it is decoded again, the value in the tile is 389. The issue seems to occur during decoding, because according to GDAL, the only value in the saved geotiff is 145, which is correct.

test("Geotiffreading"){
    val extent = Extent(0,0,100,100)
    val tile = IntArrayTile(Array(145  ), 1, 1)
    val raster = Raster(tile, extent)
    val resultTiff = GeoTiff(raster, CRS.fromName("EPSG:4326"))
    resultTiff.write("test.tif")
    val singlebandGeoTiff2: SinglebandGeoTiff = GeoTiffReader.readSingleband("test.tif")
    tile.asciiDraw() shouldEqual singlebandGeoTiff2.tile.asciiDraw()
  }

Activity

  1. jdries commented on Jan 31, 2017

    @jdries
    ContributorAuthor

    I found the issue. It's specific for geotiffs that consist of less than 4 bytes. This method is wrong in this case:
    geotrellis.raster.io.geotiff.util.ByteReaderExtensions.ByteReaderUtilities#getSignedByteArray
    (There are a number of similar methods there that also contain the same issue.)
    This line:
    val bb = ByteBuffer.allocate(4).order(byteReader.order).putInt(0, offset.toInt)
    stores the offset in a new bytebuffer, not sure why, and the code never reads from the byteReader containing the actual pixels.
    I'm not a Scala expert, but a fix could look like this:

    if (length <= 4) {
            val arr = Array.ofDim[Byte](len)
            val bb = ByteBuffer.allocate(4).order(byteReader.order).putInt(0, offset.toInt)
            val oldPos = byteReader.position
            byteReader.position(offset)
            cfor(0)(_ < len, _ + 1) { i =>
              arr(i) = byteReader.get
            }
            byteReader.position(oldPos)
            arr
          }
    
  2. modified the milestones: 1.2, 1.1 on Mar 12, 2017
  3. lossyrob commented on Mar 12, 2017

    @lossyrob
    Member

    Apologies, I didn't see this when it was incoming. Thanks for the bug report, I'll look into it.

  4. lossyrob commented on Mar 13, 2017

    @lossyrob
    Member

    @jdries this has to do with a weird property of Tiffs - when the length is less than or equal to 4 bytes, the value is just stored in the offset (and the offset doesn't actually point to anything). So the line

    val bb = ByteBuffer.allocate(4).order(byteReader.order).putInt(0, offset.toInt)
    

    Puts the offset into a new byte buffer, and then that byte buffer is read in.

  5. self-assigned this
    on Mar 14, 2017
  6. jdries commented on Mar 14, 2017

    @jdries
    ContributorAuthor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions