Skip to content

Commit ae40674

Browse files
author
Grok Compression
committed
fixed
1 parent 057ffca commit ae40674

8 files changed

Lines changed: 97 additions & 43 deletions

File tree

src/lib/codec/apps/GrkDecompress.cpp

Lines changed: 37 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,14 +1114,19 @@ int GrkDecompress::preProcess(grk_plugin_decompress_callback_info* info)
11141114
goto cleanup;
11151115
}
11161116
}
1117-
// 3a. initialize writer before decompress so it's ready for incremental output
1118-
if(!writeInit(info))
1119-
goto cleanup;
1120-
// enable incremental band writing when postProcess is a no-op
1117+
// 3a. initialize writer before decompress so it's ready for incremental output.
1118+
// Only call writeInit early when postProcess is a no-op, so we can write header
1119+
// and enable incremental band writes. When post-processing is needed, defer
1120+
// writeInit until after decompress (postProcess) so that the library's
1121+
// io_buffer_callback (strip write) doesn't write raw/unprocessed strips
1122+
// during decompress.
11211123
incrementalWriteActive_ = false;
11221124
if(storeToDisk && !parameters->single_tile_decompress && !info->init_decompressors_func &&
1123-
grk_image_is_post_process_no_op(info->image))
1125+
grk_image_is_post_process_no_op(info->image) &&
1126+
parameters->dw_y1 == 0)
11241127
{
1128+
if(!writeInit(info))
1129+
goto cleanup;
11251130
// write header early — metadata is already final since postProcess is a no-op
11261131
if(!writeHeader(info))
11271132
goto cleanup;
@@ -1267,37 +1272,38 @@ int GrkDecompress::postProcess(grk_plugin_decompress_callback_info* info)
12671272
}
12681273
if(storeToDisk)
12691274
{
1270-
// GPU decode path: format was not initialized during preProcess
1271-
// (writeInit was skipped because grk_decompress was not called).
1272-
// Initialize the format now with the bridge image that has actual data.
1273-
if(info->decompress_flags & GRK_DECODE_POST_T1 &&
1274-
fmt->getWriteState() == IMAGE_FORMAT_UNWRITTEN)
1275+
// Update the format's image pointer in case it changed (e.g. single tile decompress
1276+
// replaces info->image after writeInit was called in preProcess)
1277+
fmt->setImage(image);
1278+
// Initialize the format if not already done. writeInit is deferred to postProcess
1279+
// when post-processing is needed, so the library's io_buffer_callback (strip write)
1280+
// doesn't write raw/unprocessed strips during decompress.
1281+
if(fmt->getWriteState() == IMAGE_FORMAT_UNWRITTEN)
12751282
{
1276-
// Set decompress output fields on the bridge image
1277-
if(image->numcomps > 0)
1283+
if(info->decompress_flags & GRK_DECODE_POST_T1)
12781284
{
1279-
if(image->decompress_prec == 0)
1280-
{
1281-
image->decompress_prec = image->comps[0].prec;
1282-
image->decompress_width = image->comps[0].w;
1283-
image->decompress_height = image->comps[0].h;
1284-
image->decompress_num_comps = image->numcomps;
1285-
image->decompress_colour_space = image->color_space;
1286-
}
1287-
if(image->packed_row_bytes == 0)
1285+
// GPU decode path: set decompress output fields on the bridge image
1286+
if(image->numcomps > 0)
12881287
{
1289-
uint16_t ncmp = image->numcomps;
1290-
uint8_t prec = image->comps[0].prec;
1291-
image->packed_row_bytes = ((uint64_t)image->comps[0].w * ncmp * prec + 7U) / 8U;
1288+
if(image->decompress_prec == 0)
1289+
{
1290+
image->decompress_prec = image->comps[0].prec;
1291+
image->decompress_width = image->comps[0].w;
1292+
image->decompress_height = image->comps[0].h;
1293+
image->decompress_num_comps = image->numcomps;
1294+
image->decompress_colour_space = image->color_space;
1295+
}
1296+
if(image->packed_row_bytes == 0)
1297+
{
1298+
uint16_t ncmp = image->numcomps;
1299+
uint8_t prec = image->comps[0].prec;
1300+
image->packed_row_bytes = ((uint64_t)image->comps[0].w * ncmp * prec + 7U) / 8U;
1301+
}
1302+
if(image->rows_per_strip == 0)
1303+
image->rows_per_strip = std::min((uint32_t)32, image->comps[0].h);
12921304
}
1293-
if(image->rows_per_strip == 0)
1294-
image->rows_per_strip = std::min((uint32_t)32, image->comps[0].h);
12951305
}
1296-
if(!fmt->writeInit(
1297-
image, outfile ? std::string(outfile) : "",
1298-
info->cod_format == GRK_FMT_TIF ? info->decompressor_parameters->compression : 0,
1299-
info->decompressor_parameters->num_threads ? info->decompressor_parameters->num_threads
1300-
: std::thread::hardware_concurrency()))
1306+
if(!writeInit(info))
13011307
{
13021308
spdlog::error("Outfile {} not generated", outfile ? std::string(outfile) : "");
13031309
goto cleanup;

src/lib/codec/formats/IImageFormat.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@
2626
*
2727
*/
2828
const uint32_t IMAGE_FORMAT_UNWRITTEN = 1;
29-
const uint32_t IMAGE_FORMAT_HEADER_WRITTEN = 2;
30-
const uint32_t IMAGE_FORMAT_PIXELS_WRITTEN = 4;
31-
const uint32_t IMAGE_FORMAT_ERROR = 8;
29+
const uint32_t IMAGE_FORMAT_INITIALIZED = 2;
30+
const uint32_t IMAGE_FORMAT_HEADER_WRITTEN = 4;
31+
const uint32_t IMAGE_FORMAT_PIXELS_WRITTEN = 8;
32+
const uint32_t IMAGE_FORMAT_ERROR = 16;
3233

3334
/**
3435
* @class IImageReader

src/lib/codec/formats/ImageFormat.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ bool ImageFormat::writeInit(grk_image* image, const std::string& filename,
7575
compressionLevel_ = compression_level;
7676
fileName_ = filename;
7777
image_ = image;
78+
writeState_ = IMAGE_FORMAT_INITIALIZED;
7879

7980
return true;
8081
}

src/lib/codec/formats/TIFFFormat.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,20 @@ class TIFFFormat : public ImageFormat
641641
bool writeImageBand(uint32_t yBegin, uint32_t yEnd) override;
642642
bool supportsIncrementalBandWrite(void) const override
643643
{
644+
// Subsampled YCbCr TIFF packs luma+chroma into strips; incremental band
645+
// writes produce many small strips instead of one strip per rows_per_strip,
646+
// changing the TIFF structure.
647+
if(image_)
648+
{
649+
if(!image_->upsample && !image_->force_rgb)
650+
{
651+
for(uint32_t i = 0; i < image_->decompress_num_comps; ++i)
652+
{
653+
if(image_->comps[i].dx != 1 || image_->comps[i].dy != 1)
654+
return false;
655+
}
656+
}
657+
}
644658
return true;
645659
}
646660
/***

src/lib/core/codestream/decompress/CodeStreamDecompress.cpp

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -238,17 +238,23 @@ bool CodeStreamDecompress::decompress(grk_plugin_tile* tile)
238238
auto compositeBounds = multiTileComposite_->getBounds();
239239
uint32_t regionY0 = ceildivpow2<uint32_t>(compositeBounds.y0, reduce);
240240
uint32_t regionY1 = ceildivpow2<uint32_t>(compositeBounds.y1, reduce);
241-
uint32_t reducedTileHeight = ceildivpow2<uint32_t>(cp_.t_height_, reduce);
242-
uint32_t reducedTy0 = ceildivpow2<uint32_t>(cp_.ty0_, reduce);
241+
uint32_t unreducedTy0 = cp_.ty0_;
242+
uint32_t unreducedTileHeight = cp_.t_height_;
243+
uint32_t unreducedRegionY1 = compositeBounds.y1;
243244
tileCompletion_ = std::make_unique<TileCompletion>(
244245
tileCache_.get(), unreducedBounds, cp_.t_width_, cp_.t_height_,
245-
[this, regionY0, regionY1, reducedTileHeight, reducedTy0](uint16_t tileIndexBegin,
246-
uint16_t) {
246+
[this, regionY0, regionY1, unreducedTy0, unreducedTileHeight, unreducedRegionY1,
247+
reduce](uint16_t tileIndexBegin, uint16_t) {
247248
uint16_t numTileCols = tileCompletion_->getNumTileCols();
248249
uint16_t tileY = tileIndexBegin / numTileCols;
249-
uint32_t tileGlobalYBegin = reducedTy0 + (uint32_t)tileY * reducedTileHeight;
250-
uint32_t tileGlobalYEnd =
251-
std::min(reducedTy0 + ((uint32_t)tileY + 1) * reducedTileHeight, regionY1);
250+
// Compute exact reduced-resolution tile Y extents using ceildivpow2
251+
// on unreduced coordinates, since DWT reduction is not uniformly divisible
252+
uint32_t unreducedTileYBegin = unreducedTy0 + (uint32_t)tileY * unreducedTileHeight;
253+
uint32_t unreducedTileYEnd =
254+
std::min(unreducedTy0 + ((uint32_t)tileY + 1) * unreducedTileHeight,
255+
unreducedRegionY1);
256+
uint32_t tileGlobalYBegin = ceildivpow2<uint32_t>(unreducedTileYBegin, reduce);
257+
uint32_t tileGlobalYEnd = ceildivpow2<uint32_t>(unreducedTileYEnd, reduce);
252258
uint32_t yBegin = std::max(tileGlobalYBegin, regionY0) - regionY0;
253259
uint32_t yEnd = std::min(tileGlobalYEnd, regionY1) - regionY0;
254260
if(yEnd <= yBegin)

src/lib/core/codestream/decompress/CodeStreamDecompress_ReadMarkers.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,10 @@ void CodeStreamDecompress::postReadHeader(void)
189189
if(headerRead_)
190190
{
191191
setDecompressRegion(RectD(cp_.dw_x0, cp_.dw_y0, cp_.dw_x1, cp_.dw_y1));
192+
// Refresh decompress_width/height/etc. now that region bounds are applied.
193+
// Without this, formats that write headers before decompress() see stale
194+
// full-image dimensions instead of the (possibly reduced) region dimensions.
195+
multiTileComposite_->postReadHeader(&cp_);
192196

193197
if(cp_.asynchronous_ && cp_.simulate_synchronous_)
194198
{

src/lib/core/fileformat/decompress/FileFormatJP2Decompress.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,11 @@ bool FileFormatJP2Decompress::readHeader(grk_header_info* header_info)
105105
}
106106
image = codeStream->getCompositeNoWait();
107107
image->validateICC();
108+
// Update decompress_colour_space after validateICC may have changed color_space
109+
// (e.g. to GRK_CLRSPC_ICC). postReadHeader() ran before validateICC, so
110+
// decompress_colour_space still holds the old value. Writers that emit
111+
// headers before decompress() rely on this being current.
112+
image->decompress_colour_space = image->color_space;
108113

109114
// check RGB subsampling
110115
if(image->color_space == GRK_CLRSPC_SRGB)

src/lib/core/util/GrkImage.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -468,8 +468,25 @@ bool GrkImage::isPostProcessNoOp(void) const
468468
// convertPrecision
469469
if(precision)
470470
return false;
471-
if(decompress_fmt == GRK_FMT_JPG && comps[0].prec < 8 && numcomps > 1)
472-
return false;
471+
if(decompress_fmt == GRK_FMT_JPG)
472+
{
473+
uint8_t prec = comps[0].prec;
474+
if(prec < 8 && numcomps > 1)
475+
return false;
476+
if((prec > 1) && (prec < 8) && ((prec == 6) || ((prec & 1) == 1)))
477+
return false;
478+
}
479+
if(decompress_fmt == GRK_FMT_PNG)
480+
{
481+
uint8_t prec = comps[0].prec;
482+
uint16_t nr_comp = numcomps > 4 ? 4 : numcomps;
483+
if(prec > 8 && prec < 16)
484+
return false;
485+
if(prec < 8 && nr_comp > 1)
486+
return false;
487+
if((prec > 1) && (prec < 8) && ((prec == 6) || ((prec & 1) == 1)))
488+
return false;
489+
}
473490
// execUpsample
474491
if(upsample)
475492
{

0 commit comments

Comments
 (0)