@@ -522,7 +522,7 @@ struct GRKCodecWrapper
522522 * @param numResolutions number of resolutions
523523 * @return true if successful
524524 */
525- bool setUpDecompress (int numThreads, char *pszFilename,
525+ bool setUpDecompress (int numThreads, const char *pszFilename,
526526 vsi_l_offset nCodeStreamLength, uint32_t *nTileW,
527527 uint32_t *nTileH, int *numResolutions)
528528 {
@@ -1780,8 +1780,17 @@ struct JP2GRKDatasetBase : public JP2DatasetBase
17801780 nPromoteAlphaBandIdx);
17811781 };
17821782
1783- auto postPreload = decompressAsynch (nullptr , nullptr , nXOff, nYOff,
1784- nXSize, nYSize, rowCopy);
1783+ // When reading a subset of bands, tile images must persist
1784+ // across per-band reads. Use CACHE_IMAGE so that tile row
1785+ // release keeps the decoded pixels alive.
1786+ const int nTotalComps =
1787+ (m_codec && m_codec->psImage ) ? m_codec->psImage ->numcomps : 0 ;
1788+ const bool needPersistentTiles =
1789+ (!this ->bSingleTiled && nBandCount < nTotalComps);
1790+
1791+ auto postPreload =
1792+ decompressAsynch (nullptr , nullptr , nXOff, nYOff, nXSize, nYSize,
1793+ rowCopy, needPersistentTiles);
17851794
17861795 try
17871796 {
@@ -1862,7 +1871,8 @@ struct JP2GRKDatasetBase : public JP2DatasetBase
18621871 PostPreload decompressAsynch (decompress_callback cb, void *user_data,
18631872 int swath_x0, int swath_y0, int swath_width,
18641873 int swath_height,
1865- RowCopyFunc rowCopy = nullptr )
1874+ RowCopyFunc rowCopy = nullptr ,
1875+ bool needPersistentTiles = false )
18661876 {
18671877 PostPreload rc;
18681878
@@ -1876,8 +1886,7 @@ struct JP2GRKDatasetBase : public JP2DatasetBase
18761886 m_codec->open (fp_, nCodeStreamStart);
18771887 uint32_t nTileW = 0 , nTileH = 0 ;
18781888 int numRes = 0 ;
1879- char *pszFilename = const_cast <char *>(m_osFilename.c_str ());
1880- if (!m_codec->setUpDecompress (GetNumThreads (), pszFilename,
1889+ if (!m_codec->setUpDecompress (GetNumThreads (), m_osFilename.c_str (),
18811890 nCodeStreamLength, &nTileW, &nTileH,
18821891 &numRes))
18831892 {
@@ -1944,7 +1953,9 @@ struct JP2GRKDatasetBase : public JP2DatasetBase
19441953 decompressParams.simulate_synchronous = true ;
19451954 decompressParams.decompress_callback = cb;
19461955 decompressParams.decompress_callback_user_data = user_data;
1947- decompressParams.core .tile_cache_strategy = GRK_TILE_CACHE_IMAGE;
1956+ decompressParams.core .tile_cache_strategy =
1957+ needPersistentTiles ? GRK_TILE_CACHE_IMAGE
1958+ : GRK_TILE_CACHE_NONE;
19481959 // For multi-tile images, skip composite allocation to avoid
19491960 // a full-resolution buffer. Single-tile images need the
19501961 // composite because Grok stores their data there (not in the
@@ -2096,6 +2107,33 @@ struct JP2GRKDatasetBase : public JP2DatasetBase
20962107 const int nWidthToRead = std::min (nBlockXSize, nRasterXSize_ - nXOff);
20972108 const int nHeightToRead = std::min (nBlockYSize, nRasterYSize_ - nYOff);
20982109
2110+ // The async decompress pipeline decodes a fixed decode window and
2111+ // cleans up tiles after processing. IReadBlock calls us for each
2112+ // block, potentially a different tile each time. For multi-tile
2113+ // images, reset the codec so a fresh decompress can target just
2114+ // this block's region.
2115+ if (!bSingleTiled && (hasCachedPostPreload_ || initializedAsync))
2116+ {
2117+ delete m_codec;
2118+ m_codec = new GRKCodecWrapper ();
2119+ m_codec->open (fp_, nCodeStreamStart);
2120+ uint32_t tileW = 0 , tileH = 0 ;
2121+ int numRes = 0 ;
2122+ if (!m_codec->setUpDecompress (GetNumThreads (), m_osFilename.c_str (),
2123+ nCodeStreamLength, &tileW, &tileH,
2124+ &numRes))
2125+ {
2126+ delete m_codec;
2127+ m_codec = nullptr ;
2128+ CPLError (CE_Failure, CPLE_AppDefined,
2129+ " readBlockInit: codec reinit failed" );
2130+ return CE_Failure;
2131+ }
2132+ CPLErrorReset ();
2133+ hasCachedPostPreload_ = false ;
2134+ initializedAsync = false ;
2135+ }
2136+
20992137 auto postPreload = decompressAsynch (nullptr , nullptr , nXOff, nYOff,
21002138 nWidthToRead, nHeightToRead);
21012139 if (!postPreload.asynch_ )
@@ -2105,8 +2143,11 @@ struct JP2GRKDatasetBase : public JP2DatasetBase
21052143 return CE_Failure;
21062144 }
21072145
2108- uint16_t tileno = postPreload.tile_y0 * postPreload.num_tile_cols +
2109- postPreload.tile_x0 ;
2146+ // Compute the tile index from block coordinates (not from
2147+ // postPreload.tile_x0/y0, which reflect the full decompress range).
2148+ uint16_t tileno =
2149+ static_cast <uint16_t >(nBlockYOff) * postPreload.num_tile_cols +
2150+ static_cast <uint16_t >(nBlockXOff);
21102151 grk_image *img =
21112152 grk_decompress_get_tile_image (m_codec->pCodec , tileno, true );
21122153 // For single-tile images, Grok puts data in the composite
0 commit comments