From 32859b87fdee440f10e5978a78e731a9f142482d Mon Sep 17 00:00:00 2001 From: br3aker Date: Sun, 2 Apr 2023 19:20:09 +0300 Subject: [PATCH] Fixed invalid jpeg buffer width compliment for scalar color converters --- .../Decoder/SpectralConverter{TPixel}.cs | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs index d6250127f5..5add4c6f06 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs @@ -184,34 +184,39 @@ internal class SpectralConverter : SpectralConverter, IDisposable MemoryAllocator allocator = this.Configuration.MemoryAllocator; - // color converter from RGB to TPixel + // Color converter from RGB to TPixel JpegColorConverterBase converter = this.GetColorConverter(this.frame, this.jpegData); this.colorConverter = converter; - // resulting image size + // Resulting image size Size pixelSize = CalculateResultingImageSize(this.frame.PixelSize, this.targetSize, out int blockPixelSize); - // iteration data + // Iteration data int majorBlockWidth = this.frame.Components.Max((component) => component.SizeInBlocks.Width); int majorVerticalSamplingFactor = this.frame.Components.Max((component) => component.SamplingFactors.Height); this.pixelRowsPerStep = majorVerticalSamplingFactor * blockPixelSize; - // pixel buffer for resulting image + // Pixel buffer for resulting image this.pixelBuffer = allocator.Allocate2D( pixelSize.Width, pixelSize.Height, this.Configuration.PreferContiguousImageBuffers); this.paddedProxyPixelRow = allocator.Allocate(pixelSize.Width + 3); - // component processors from spectral to RGB + // Component processors from spectral to RGB int bufferWidth = majorBlockWidth * blockPixelSize; - int batchSize = converter.ElementsPerBatch; - int batchRemainder = bufferWidth & (batchSize - 1); - Size postProcessorBufferSize = new(bufferWidth + (batchSize - batchRemainder), this.pixelRowsPerStep); + + // Converters process pixels in batches and require target buffer size to be divisible by a batch size + // Corner case: image size including jpeg padding is already divisible by a batch size or remainder == 0 + int elementsPerBatch = converter.ElementsPerBatch; + int batchRemainder = bufferWidth & (elementsPerBatch - 1); + int widthComplementaryValue = batchRemainder == 0 ? 0 : elementsPerBatch - batchRemainder; + + Size postProcessorBufferSize = new(bufferWidth + widthComplementaryValue, this.pixelRowsPerStep); this.componentProcessors = this.CreateComponentProcessors(this.frame, this.jpegData, blockPixelSize, postProcessorBufferSize); - // single 'stride' rgba32 buffer for conversion between spectral and TPixel + // Single 'stride' rgba32 buffer for conversion between spectral and TPixel this.rgbBuffer = allocator.Allocate(pixelSize.Width * 3); }