@@ -476,8 +476,9 @@ struct GRKCodecWrapper
476476 */
477477 void allocComponentParams (int nBands)
478478 {
479+ // need to zero-init the component structs
479480 pasBandParams = static_cast <grk_image_comp *>(
480- CPLMalloc (nBands * sizeof (grk_image_comp)));
481+ CPLCalloc (nBands, sizeof (grk_image_comp)));
481482 }
482483
483484 /* *
@@ -2131,6 +2132,91 @@ struct JP2GRKDatasetBase : public JP2DatasetBase
21312132 if (xStart >= xEnd || yStart >= yEnd)
21322133 return CE_None;
21332134
2135+ // can use fast path when there is no sub-sampling, no alpha promotion
2136+ // and output pixels are contiguous
2137+ const int elemSize = GDALGetDataTypeSizeBytes (eBufType);
2138+ bool canFastCopy = (nPromoteAlphaBandIdx < 0 &&
2139+ nPixelSpace == elemSize && elemSize > 0 );
2140+ for (int i = 0 ; i < nBandCount && canFastCopy; ++i)
2141+ {
2142+ const int b = panBandMap[i] - 1 ;
2143+ if (b < 0 || b >= img->numcomps )
2144+ canFastCopy = false ;
2145+ else
2146+ {
2147+ const auto &comp = img->comps [b];
2148+ if (comp.dx != 1 || comp.dy != 1 || !comp.data )
2149+ canFastCopy = false ;
2150+ }
2151+ }
2152+
2153+ if (canFastCopy)
2154+ {
2155+ const int copyWidth = xEnd - xStart;
2156+ for (int i = 0 ; i < nBandCount; ++i)
2157+ {
2158+ const int srcBandIdx = panBandMap[i] - 1 ;
2159+ const auto &comp = img->comps [srcBandIdx];
2160+ const int srcXStart = xStart - tileXOff;
2161+
2162+ for (int iY = yStart; iY < yEnd; ++iY)
2163+ {
2164+ const int srcRow = iY - tileYOff;
2165+ const int dstRow = iY - nYOff;
2166+ const int dstX = xStart - nXOff;
2167+ auto dst = static_cast <uint8_t *>(pData) +
2168+ dstRow * nLineSpace + dstX * nPixelSpace +
2169+ i * nBandSpace;
2170+
2171+ if (comp.data_type == GRK_INT_16)
2172+ {
2173+ const auto src =
2174+ static_cast <int16_t *>(comp.data ) +
2175+ srcRow * static_cast <int >(comp.stride ) + srcXStart;
2176+ if (eBufType == GDT_UInt16 || eBufType == GDT_Int16)
2177+ {
2178+ memcpy (dst, src, copyWidth * sizeof (int16_t ));
2179+ }
2180+ else if (eBufType == GDT_Byte)
2181+ {
2182+ for (int x = 0 ; x < copyWidth; ++x)
2183+ dst[x] = static_cast <GByte>(src[x]);
2184+ }
2185+ else if (eBufType == GDT_Int32 ||
2186+ eBufType == GDT_UInt32)
2187+ {
2188+ auto dst32 = reinterpret_cast <int32_t *>(dst);
2189+ for (int x = 0 ; x < copyWidth; ++x)
2190+ dst32[x] = src[x];
2191+ }
2192+ }
2193+ else
2194+ {
2195+ const auto src =
2196+ static_cast <int32_t *>(comp.data ) +
2197+ srcRow * static_cast <int >(comp.stride ) + srcXStart;
2198+ if (eBufType == GDT_Int32 || eBufType == GDT_UInt32)
2199+ {
2200+ memcpy (dst, src, copyWidth * sizeof (int32_t ));
2201+ }
2202+ else if (eBufType == GDT_UInt16 ||
2203+ eBufType == GDT_Int16)
2204+ {
2205+ auto dst16 = reinterpret_cast <int16_t *>(dst);
2206+ for (int x = 0 ; x < copyWidth; ++x)
2207+ dst16[x] = static_cast <int16_t >(src[x]);
2208+ }
2209+ else if (eBufType == GDT_Byte)
2210+ {
2211+ for (int x = 0 ; x < copyWidth; ++x)
2212+ dst[x] = static_cast <GByte>(src[x]);
2213+ }
2214+ }
2215+ }
2216+ }
2217+ return CE_None;
2218+ }
2219+
21342220 // Scalar per-pixel loop that handles dx/dy subsampling, alpha promotion,
21352221 // and all five output types.
21362222 CPLErr eErr = CE_None;
@@ -2165,7 +2251,13 @@ struct JP2GRKDatasetBase : public JP2DatasetBase
21652251 const GPtrDiff_t dstOffset =
21662252 bufX * nPixelSpace + bufY * nLineSpace + i * nBandSpace;
21672253
2168- int32_t value = static_cast <int32_t *>(comp.data )[tileIdx];
2254+ // Grok v20.3.x can use 16 bit storage for images with
2255+ // precision ≤ 12 bits - we need to cast to correct type
2256+ int32_t value;
2257+ if (comp.data_type == GRK_INT_16)
2258+ value = static_cast <int16_t *>(comp.data )[tileIdx];
2259+ else
2260+ value = static_cast <int32_t *>(comp.data )[tileIdx];
21692261 if (srcBandIdx == nPromoteAlphaBandIdx)
21702262 value *= 255 ;
21712263 if (eBufType == GDT_Byte)
0 commit comments