Rendering bug with BLContext for certain image sizes
judicaelclair opened this issue · comments
With latest master, for certain image sizes, rendering with BLContext distorts the image.
Pseudocode:
void render_via_data(BLImage& img) {
BLImageData data;
img.makeMutable(&data);
uint32_t* pxs = static_cast<uint32_t*>(data.pixelData);
for (const int y : range(height)) {
for (const int x : range(width)) {
const BLRgba32 v = /* implementation details */;
pxs[y * width + x] = v.value;
}
}
}
void render_via_ctx(BLImage& img) {
BLContext ctx(img);
ctx.setCompOp(BL_COMP_OP_SRC_OVER);
for (const int y : range(height)) {
for (const int x : range(width)) {
const BLRgba32 v = /* implementation details */;
ctx.setFillStyle(v);
ctx.fillRect(BLRectI{x, y, 1, 1});
}
}
}
Here is the correct image by using render_via_data()
:
Here is the incorrect image by using render_via_ctx()
:
As you can see, the image is skewed and wrapped, and there is a weird diagonal line that shouldn't be there. This is for an image with width=75
and height=50
. If the image is instead width=300
and height=200
for example, render_via_ctx()
produces the correct results.
The following code is not correct:
pxs[y * width + x] = v.value;
To calculate a valid pixel address, use stride:
uint8_t* pxs = static_cast<uint8_t*>(data.pixelData);
for (const int y : range(height)) {
uint32_t* scanline = reinterpret_cast<uint32_t*>(pxs);
for (const int x : range(width)) {
const BLRgba32 v = /* implementation details */;
scanline[x] = v.value;
}
pxs += data.stride;
}
Blend2D would align large images to 4 pixels to maintain 16-byte alignment for each scanline. It would not align small images to not waste memory. Also, you can create subimages that have much larger stride than width, etc... So the only correct calculation is to use stride
.
Oh okay that makes sense, thank you! I was making the same mistake when generating an OpenGL texture from a BLImage, which is why the image rendered via BLContext looked weird. All works as expected now when using stride.