Skip to content

Commit 057ffca

Browse files
author
Grok Compression
committed
ImageFormat: refactor to incremental write II
1 parent c059a28 commit 057ffca

21 files changed

Lines changed: 300 additions & 14 deletions

src/lib/codec/apps/GrkDecompress.cpp

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
{}
112114
GrkDecompress::~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+
924935
bool 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
{

src/lib/codec/apps/GrkDecompress.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ class GrkDecompress
8080
int shmBatchDecompress(DecompressInitParams* initParams);
8181

8282
bool storeToDisk;
83+
bool incrementalWriteActive_;
8384
IImageFormat* imageFormat;
8485
grk_plugin::Messenger* messenger_;
8586
};

src/lib/codec/formats/IImageFormat.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,14 @@ class IImageWriter
8787
virtual bool writeInit(grk_image* image, const std::string& filename, uint32_t compression_level,
8888
uint32_t concurrency) = 0;
8989

90+
/**
91+
* @brief Replace the image pointer used by subsequent write calls.
92+
*
93+
* Used for incremental band writing when the source image differs
94+
* from the one originally passed to writeInit().
95+
*/
96+
virtual void setImage(grk_image* image) = 0;
97+
9098
/**
9199
* @brief Writes format-specific header
92100
*
@@ -117,6 +125,11 @@ class IImageWriter
117125
*/
118126
virtual bool writeImageBand(uint32_t yBegin, uint32_t yEnd) = 0;
119127

128+
/**
129+
* @brief Returns true if this format supports incremental band writing via writeImageBand().
130+
*/
131+
virtual bool supportsIncrementalBandWrite(void) const = 0;
132+
120133
/**
121134
* @brief Writes a single strip of pre-packed pixel data (push-based, incremental).
122135
*

src/lib/codec/formats/ImageFormat.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,14 @@ bool ImageFormat::writeInit(grk_image* image, const std::string& filename,
7878

7979
return true;
8080
}
81+
void ImageFormat::setImage(grk_image* image)
82+
{
83+
image_ = image;
84+
}
85+
bool ImageFormat::supportsIncrementalBandWrite(void) const
86+
{
87+
return false;
88+
}
8189
/***
8290
* library-orchestrated pixel encoding
8391
*/

src/lib/codec/formats/ImageFormat.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ class ImageFormat : public IImageFormat
4040
void reclaim(uint32_t workerId, grk_io_buf pixels);
4141
virtual bool writeInit(grk_image* image, const std::string& filename, uint32_t compression_level,
4242
uint32_t concurrency) override;
43+
virtual void setImage(grk_image* image) override;
44+
bool supportsIncrementalBandWrite(void) const override;
4345
virtual bool writeStrip(uint32_t workerId, grk_io_buf pixels) override;
4446
virtual bool writeFinish(void) override;
4547
uint32_t getWriteState(void) override;

src/lib/codec/formats/JPEGFormat.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ class JPEGFormat : public ImageFormat
9595
bool writeHeader(void) override;
9696
bool writeImage() override;
9797
bool writeImageBand(uint32_t yBegin, uint32_t yEnd) override;
98+
bool supportsIncrementalBandWrite(void) const override
99+
{
100+
return true;
101+
}
98102
using ImageFormat::writeStrip;
99103
bool writeFinish(void) override;
100104
grk_image* readImage(const std::string& filename, grk_cparameters* parameters) override;

src/lib/codec/formats/PNGFormat.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ class PNGFormat : public ImageFormat
4343
bool writeHeader(void) override;
4444
bool writeImage() override;
4545
bool writeImageBand(uint32_t yBegin, uint32_t yEnd) override;
46+
bool supportsIncrementalBandWrite(void) const override
47+
{
48+
return true;
49+
}
4650
using ImageFormat::writeStrip;
4751
bool writeFinish(void) override;
4852
grk_image* readImage(const std::string& filename, grk_cparameters* parameters) override;
@@ -129,11 +133,6 @@ bool PNGFormat<T>::writeHeader(void)
129133
break;
130134
if(image_->comps[0].sgnd != image_->comps[i].sgnd)
131135
break;
132-
if(!image_->comps[i].data)
133-
{
134-
spdlog::error("imagetopng: component {} is null.", i);
135-
return false;
136-
}
137136
}
138137
if(i != nr_comp_)
139138
{

src/lib/codec/formats/PNMFormat.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ class PNMFormat : public ImageFormat
5252
bool writeHeader(void) override;
5353
bool writeImage() override;
5454
bool writeImageBand(uint32_t yBegin, uint32_t yEnd) override;
55+
bool supportsIncrementalBandWrite(void) const override
56+
{
57+
// Split PGM files (forceSplit + single component) need the full image at once
58+
if(forceSplit && image_ && image_->decompress_num_comps <= 1)
59+
return false;
60+
return true;
61+
}
5562
using ImageFormat::writeStrip;
5663
bool writeFinish(void) override;
5764
grk_image* readImage(const std::string& filename, grk_cparameters* parameters) override;

src/lib/codec/formats/TIFFFormat.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,10 @@ class TIFFFormat : public ImageFormat
639639
*/
640640
bool writeImage() override;
641641
bool writeImageBand(uint32_t yBegin, uint32_t yEnd) override;
642+
bool supportsIncrementalBandWrite(void) const override
643+
{
644+
return true;
645+
}
642646
/***
643647
* library-orchestrated pixel encoding
644648
*/

src/lib/core/codestream/IDecompressor.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,17 @@ struct IDecompressor
6363
*/
6464
virtual void init(grk_decompress_parameters* param) = 0;
6565

66+
/**
67+
* @brief Sets a band-completion callback for incremental writing.
68+
*
69+
* Must be called after readHeader() but before decompress().
70+
*/
71+
virtual void setBandCallback(grk_io_band_callback callback, void* user_data)
72+
{
73+
(void)callback;
74+
(void)user_data;
75+
}
76+
6677
/**
6778
* @brief Gets the @ref grk_progression_state for a tile
6879
*

0 commit comments

Comments
 (0)