@@ -464,7 +464,6 @@ func (r *ScanlineReader) decodeUncompressedChunkParallel(chunkY int, data []byte
464464
465465 minY := int (r .dataWindow .Min .Y )
466466 maxY := int (r .dataWindow .Max .Y )
467- minX := int (r .dataWindow .Min .X )
468467
469468 comp := r .header .Compression ()
470469 linesPerChunk := comp .ScanlinesPerChunk ()
@@ -483,6 +482,11 @@ func (r *ScanlineReader) decodeUncompressedChunkParallel(chunkY int, data []byte
483482 continue
484483 }
485484
485+ // Map from absolute data window coordinates to buffer-relative coordinates.
486+ // The framebuffer is allocated for the data window dimensions, so pixel
487+ // (minX, minY) maps to buffer position (0, 0).
488+ bufY := y - minY
489+
486490 for i := range channelInfos {
487491 ci := & channelInfos [i ]
488492 if ci .slice == nil {
@@ -496,11 +500,11 @@ func (r *ScanlineReader) decodeUncompressedChunkParallel(chunkY int, data []byte
496500
497501 switch ci .ch .Type {
498502 case PixelTypeHalf :
499- ci .slice .WriteRowHalfBytes (y , data [pos :pos + ci .bytesInChannel ], minX , ci .pixelsInChannel )
503+ ci .slice .WriteRowHalfBytes (bufY , data [pos :pos + ci .bytesInChannel ], 0 , ci .pixelsInChannel )
500504 case PixelTypeFloat :
501- ci .slice .WriteRowFloat (y , data [pos :pos + ci .bytesInChannel ], minX , ci .pixelsInChannel )
505+ ci .slice .WriteRowFloat (bufY , data [pos :pos + ci .bytesInChannel ], 0 , ci .pixelsInChannel )
502506 case PixelTypeUint :
503- ci .slice .WriteRowUint (y , data [pos :pos + ci .bytesInChannel ], minX , ci .pixelsInChannel )
507+ ci .slice .WriteRowUint (bufY , data [pos :pos + ci .bytesInChannel ], 0 , ci .pixelsInChannel )
504508 }
505509 pos += ci .bytesInChannel
506510 }
@@ -519,7 +523,6 @@ func (r *ScanlineReader) decodeUncompressedChunk(chunkY int, data []byte) error
519523
520524 minY := int (r .dataWindow .Min .Y )
521525 maxY := int (r .dataWindow .Max .Y )
522- minX := int (r .dataWindow .Min .X )
523526
524527 // Calculate how many lines are in this chunk
525528 compression := r .header .Compression ()
@@ -540,6 +543,11 @@ func (r *ScanlineReader) decodeUncompressedChunk(chunkY int, data []byte) error
540543 continue
541544 }
542545
546+ // Map from absolute data window coordinates to buffer-relative coordinates.
547+ // The framebuffer is allocated for the data window dimensions, so pixel
548+ // (minX, minY) maps to buffer position (0, 0).
549+ bufY := y - minY
550+
543551 for i := range channelInfos {
544552 ci := & channelInfos [i ]
545553 if ci .slice == nil {
@@ -553,11 +561,11 @@ func (r *ScanlineReader) decodeUncompressedChunk(chunkY int, data []byte) error
553561
554562 switch ci .ch .Type {
555563 case PixelTypeHalf :
556- ci .slice .WriteRowHalfBytes (y , data [pos :pos + ci .bytesInChannel ], minX , ci .pixelsInChannel )
564+ ci .slice .WriteRowHalfBytes (bufY , data [pos :pos + ci .bytesInChannel ], 0 , ci .pixelsInChannel )
557565 case PixelTypeFloat :
558- ci .slice .WriteRowFloat (y , data [pos :pos + ci .bytesInChannel ], minX , ci .pixelsInChannel )
566+ ci .slice .WriteRowFloat (bufY , data [pos :pos + ci .bytesInChannel ], 0 , ci .pixelsInChannel )
559567 case PixelTypeUint :
560- ci .slice .WriteRowUint (y , data [pos :pos + ci .bytesInChannel ], minX , ci .pixelsInChannel )
568+ ci .slice .WriteRowUint (bufY , data [pos :pos + ci .bytesInChannel ], 0 , ci .pixelsInChannel )
561569 }
562570 pos += ci .bytesInChannel
563571 }
@@ -981,7 +989,7 @@ func (w *ScanlineWriter) writePixelsParallel(y1, y2, minY, maxY int, comp Compre
981989// encodeUncompressedChunk encodes scanlines as uncompressed data.
982990func (w * ScanlineWriter ) encodeUncompressedChunk (y1 , y2 int ) ([]byte , error ) {
983991 width := int (w .dataWindow .Width ())
984- minX := int (w .dataWindow .Min .X )
992+ minY := int (w .dataWindow .Min .Y )
985993
986994 // Calculate buffer size
987995 bufSize := 0
@@ -1003,6 +1011,11 @@ func (w *ScanlineWriter) encodeUncompressedChunk(y1, y2 int) ([]byte, error) {
10031011 pos := 0 // Current position in output
10041012
10051013 for y := y1 ; y <= y2 ; y ++ {
1014+ // Map from absolute data window coordinates to buffer-relative coordinates.
1015+ // The framebuffer is allocated for the data window dimensions, so pixel
1016+ // (minX, minY) maps to buffer position (0, 0).
1017+ bufY := y - minY
1018+
10061019 for _ , ch := range sortedChannels {
10071020 pixelsInChannel := (width + int (ch .XSampling ) - 1 ) / int (ch .XSampling )
10081021 bytesInChannel := pixelsInChannel * ch .Type .Size ()
@@ -1020,7 +1033,7 @@ func (w *ScanlineWriter) encodeUncompressedChunk(y1, y2 int) ([]byte, error) {
10201033 // Use optimized bulk row operations
10211034 switch ch .Type {
10221035 case PixelTypeHalf :
1023- slice .ReadRowHalf (y , halfBuf , minX , pixelsInChannel )
1036+ slice .ReadRowHalf (bufY , halfBuf , 0 , pixelsInChannel )
10241037 // Convert uint16 to bytes
10251038 for i := 0 ; i < pixelsInChannel ; i ++ {
10261039 output [pos ] = byte (halfBuf [i ])
@@ -1029,11 +1042,11 @@ func (w *ScanlineWriter) encodeUncompressedChunk(y1, y2 int) ([]byte, error) {
10291042 }
10301043
10311044 case PixelTypeFloat :
1032- slice .ReadRowFloat (y , output [pos :pos + bytesInChannel ], minX , pixelsInChannel )
1045+ slice .ReadRowFloat (bufY , output [pos :pos + bytesInChannel ], 0 , pixelsInChannel )
10331046 pos += bytesInChannel
10341047
10351048 case PixelTypeUint :
1036- slice .ReadRowUint (y , output [pos :pos + bytesInChannel ], minX , pixelsInChannel )
1049+ slice .ReadRowUint (bufY , output [pos :pos + bytesInChannel ], 0 , pixelsInChannel )
10371050 pos += bytesInChannel
10381051 }
10391052 }
0 commit comments