Skip to content

Commit 6d9c7be

Browse files
fix: use linesize stride when annotating text on padded images
Image buffers use a 32-byte-aligned linesize stride, but Image::Annotate walked rows using width. When width*bytesPerPixel is not a multiple of 32 (e.g. 848x480 grayscale/rgb24) linesize exceeds width, so each glyph row drifted horizontally and the timestamp text appeared distorted. Use linesize for the row stride in all three pixel-format branches (rgb32 stride is linesize/4 since the pointer is Rgb*). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent ccf1440 commit 6d9c7be

1 file changed

Lines changed: 15 additions & 9 deletions

File tree

src/zm_image.cpp

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2788,7 +2788,10 @@ void Image::Annotate(
27882788
uint32_t x = static_cast<uint32_t>(x0);
27892789

27902790
if (zm_bytes_per_pixel(imagePixFormat) == 1) {
2791-
uint8 *ptr = &buffer[(y * width) + x0];
2791+
// Rows are linesize bytes apart, which is >= width when the buffer is
2792+
// padded for alignment (e.g. FFALIGN to 32); using width here would skew
2793+
// the text. See Image::linesize.
2794+
uint8 *ptr = &buffer[(y * linesize) + x0];
27922795
for (char c : line) {
27932796
for (uint64 cp_row : font_variant.GetCodepoint(c)) {
27942797
if (bg_colour != kRGBTransparent) {
@@ -2800,9 +2803,9 @@ void Image::Annotate(
28002803
*(ptr + column_idx) = fg_colour & 0xff;
28012804
cp_row = cp_row & (cp_row - 1);
28022805
}
2803-
ptr += width;
2806+
ptr += linesize;
28042807
}
2805-
ptr -= (width * char_height);
2808+
ptr -= (linesize * char_height);
28062809
ptr += char_width;
28072810
x += char_width;
28082811
if (x >= width) {
@@ -2811,7 +2814,7 @@ void Image::Annotate(
28112814
}
28122815
} else if (zm_is_rgb24(imagePixFormat)) {
28132816
constexpr uint8 bytesPerPixel = 3;
2814-
uint8 *ptr = &buffer[((y * width) + x0) * bytesPerPixel];
2817+
uint8 *ptr = &buffer[(y * linesize) + x0 * bytesPerPixel];
28152818

28162819
for (char c : line) {
28172820
for (uint64 cp_row : font_variant.GetCodepoint(c)) {
@@ -2832,9 +2835,9 @@ void Image::Annotate(
28322835
BLUE_PTR_RGBA(colour_ptr) = BLUE_VAL_RGBA(fg_colour);
28332836
cp_row = cp_row & (cp_row - 1);
28342837
}
2835-
ptr += width * bytesPerPixel;
2838+
ptr += linesize;
28362839
}
2837-
ptr -= (width * char_height * bytesPerPixel);
2840+
ptr -= (linesize * char_height);
28382841
ptr += char_width * bytesPerPixel;
28392842
x += char_width;
28402843
if (x >= width) {
@@ -2843,7 +2846,10 @@ void Image::Annotate(
28432846
}
28442847
} else if (zm_is_rgb32(imagePixFormat)) {
28452848
constexpr uint8 bytesPerPixel = 4;
2846-
Rgb *ptr = reinterpret_cast<Rgb *>(&buffer[((y * width) + x0) * bytesPerPixel]);
2849+
// Row stride in Rgb units. linesize is byte-aligned (FFALIGN 32), so it is
2850+
// always a multiple of 4 here.
2851+
const unsigned int stride = linesize / bytesPerPixel;
2852+
Rgb *ptr = reinterpret_cast<Rgb *>(&buffer[(y * linesize) + x0 * bytesPerPixel]);
28472853

28482854
for (char c : line) {
28492855
for (uint64 cp_row : font_variant.GetCodepoint(c)) {
@@ -2856,9 +2862,9 @@ void Image::Annotate(
28562862
*(ptr + column_idx) = fg_rgb_col;
28572863
cp_row = cp_row & (cp_row - 1);
28582864
}
2859-
ptr += width;
2865+
ptr += stride;
28602866
}
2861-
ptr -= (width * char_height);
2867+
ptr -= (stride * char_height);
28622868
ptr += char_width;
28632869
x += char_width;
28642870
if (x >= width) {

0 commit comments

Comments
 (0)