@@ -108,7 +108,9 @@ static void decompress_help_display(void)
108108 grk_version ());
109109 fputs (decompress_help_text, stdout);
110110}
111- GrkDecompress::GrkDecompress () : storeToDisk(true ), imageFormat(nullptr ), messenger_(nullptr ) {}
111+ GrkDecompress::GrkDecompress ()
112+ : storeToDisk(true ), incrementalWriteActive_(false ), imageFormat(nullptr ), messenger_(nullptr )
113+ {}
112114GrkDecompress::~GrkDecompress (void )
113115{
114116 delete imageFormat;
@@ -921,6 +923,15 @@ static bool grkWriteStripCallback(uint32_t workerId, grk_io_buf buffer, void* us
921923 return imageFormat->writeStrip (workerId, buffer);
922924}
923925
926+ static bool grkWriteBandCallback (uint32_t yBegin, uint32_t yEnd, grk_image* image, void * user_data)
927+ {
928+ if (!user_data || !image)
929+ return false ;
930+ auto imageFormat = (IImageFormat*)user_data;
931+ imageFormat->setImage (image);
932+ return imageFormat->writeImageBand (yBegin, yEnd);
933+ }
934+
924935bool GrkDecompress::writeHeader (grk_plugin_decompress_callback_info* info)
925936{
926937 if (!storeToDisk)
@@ -1106,8 +1117,21 @@ int GrkDecompress::preProcess(grk_plugin_decompress_callback_info* info)
11061117 // 3a. initialize writer before decompress so it's ready for incremental output
11071118 if (!writeInit (info))
11081119 goto cleanup;
1109- if (!writeHeader (info))
1110- goto cleanup;
1120+ // enable incremental band writing when postProcess is a no-op
1121+ incrementalWriteActive_ = false ;
1122+ if (storeToDisk && !parameters->single_tile_decompress && !info->init_decompressors_func &&
1123+ grk_image_is_post_process_no_op (info->image ))
1124+ {
1125+ // write header early — metadata is already final since postProcess is a no-op
1126+ if (!writeHeader (info))
1127+ goto cleanup;
1128+ auto fmt = info->format_private ? (IImageFormat*)info->format_private : imageFormat;
1129+ if (fmt->supportsIncrementalBandWrite ())
1130+ {
1131+ grk_decompress_set_band_callback (info->codec , grkWriteBandCallback, fmt);
1132+ incrementalWriteActive_ = true ;
1133+ }
1134+ }
11111135 // 3b. decompress one particular tile
11121136 if (parameters->single_tile_decompress )
11131137 {
@@ -1280,10 +1304,22 @@ int GrkDecompress::postProcess(grk_plugin_decompress_callback_info* info)
12801304 }
12811305 }
12821306 auto outfileStr = outfile ? std::string (outfile) : " " ;
1283- if (!fmt-> writeImage () )
1307+ if (incrementalWriteActive_ )
12841308 {
1285- spdlog::error (" Outfile {} not generated" , outfileStr);
1286- goto cleanup;
1309+ // bands already written during decompress; just finalize
1310+ }
1311+ else
1312+ {
1313+ if (!(fmt->getWriteState () & IMAGE_FORMAT_HEADER_WRITTEN) && !fmt->writeHeader ())
1314+ {
1315+ spdlog::error (" Encode header failed for {}" , outfileStr);
1316+ goto cleanup;
1317+ }
1318+ if (!fmt->writeImage ())
1319+ {
1320+ spdlog::error (" Outfile {} not generated" , outfileStr);
1321+ goto cleanup;
1322+ }
12871323 }
12881324 if (!fmt->writeFinish ())
12891325 {
0 commit comments