I am trying to use freetype to rasterize a 8-bit depth bitmap and render it on a 8-bit depth pixmap in xcb.
Everything works as accordingly until I try to call xcb_put_image_checked(). The function returns an error code of 16 (Length), a major code of 72 (PutImage) and a minor code of 0. From what I have gathered the error means the length of the bitmap buffer I am passing to the function is incorrect. After lots of testing I have printed the buffer out byte for byte and manually converted the data to a bitmap and the bitmap comes out correct with the size I have specified to the function. There is no padding in the bitmap that could change the size as bitmap.pitch = 7, bitmap.rows = 7, and bitmap.width = 7. The depth of the pixmap and bitmap match. I am confused as to why xcb_put_image_checked() fails. I have also tried (ft_bitmap.width*ft_bitmap.rows)-1 for the size too.
Here is my code that generates the error (sorry its sloppy)
void testing() {
FT_Library library;
char *fonts[] = {"DejaVuSans"};
FT_Init_FreeType(&library);
/* custom function that loads faces from font config patterns proven to work in this instance */
xcb_drw_face_t *ft = xcb_drw_faces_load(library,fonts,1);
if (!ft) {
logmsg(INFO,"could not load face");
}
FT_Load_Char(ft->face,'a',FT_LOAD_RENDER|FT_LOAD_FORCE_AUTOHINT);
FT_Bitmap ft_bitmap = ft->face->glyph->bitmap;
logmsg(INFO,"pitch = %i | rows = %i | width = %i",ft_bitmap.pitch,ft_bitmap.rows,ft_bitmap.width); /* pitch = 7 | rows = 7 | width = 7 */
for (size_t i = 0; i < ft_bitmap.rows*ft_bitmap.width; i++) {
logmsg(INFO, "value = %i | index = %i",ft_bitmap.buffer[i],i);
}
xcb_void_cookie_t cookie;
xcb_generic_error_t *error;
xcb_pixmap_t pixmap = xcb_generate_id(c);
cookie = xcb_create_pixmap_checked(c,8,pixmap,screen.data->root,screen.data->width_in_pixels,screen.data->height_in_pixels);
if (xcb_request_check(c,cookie)) {
logmsg(INFO,"could not create pixmap");
}
xcb_gcontext_t gc = xcb_generate_id(c);
cookie = xcb_create_gc_checked(c,gc,pixmap,0,0);
if (xcb_request_check(c,cookie)) {
logmsg(INFO,"could not create gc");
}
cookie = xcb_put_image_checked(c,XCB_IMAGE_FORMAT_Z_PIXMAP,pixmap,gc,ft_bitmap.width,ft_bitmap.rows,0,0,0,8,ft_bitmap.width*ft_bitmap.rows,ft_bitmap.buffer);
if ((error = xcb_request_check(c,cookie))) {
logmsg(INFO,"could not put image on pixmap | err %i | maj %i | min %i",error->error_code,error->major_code,error->minor_code);
}
xcb_drw_faces_free(ft);
xcb_free_pixmap(c,pixmap);
xcb_free_gc(c,gc);
FT_Done_FreeType(library);
return;
}
Here is the image I manually converted - enter image description here
This comes from a requirement from your X11 server. Here is a snippet of output from xdpyinfo
:
supported pixmap formats:
depth 1, bits_per_pixel 1, scanline_pad 32
depth 4, bits_per_pixel 8, scanline_pad 32
depth 8, bits_per_pixel 8, scanline_pad 32
depth 15, bits_per_pixel 16, scanline_pad 32
depth 16, bits_per_pixel 16, scanline_pad 32
depth 24, bits_per_pixel 32, scanline_pad 32
depth 32, bits_per_pixel 32, scanline_pad 32
The scanline_pad
of 32 here is the four bytes of padding you are seeing.
This is (a bit) explained in https://www.x.org/releases/X11R7.6/doc/xproto/x11protocol.html#id2625443:
Each scanline is padded to a multiple of bits as given by bitmap-scanline-pad. The pad bits are of arbitrary value. The scanline is quantized in multiples of bits as given by bitmap-scanline-unit. The bitmap-scanline-unit is always less than or equal to the bitmap-scanline-pad. Within
(To be honest, I think I never saw an X11 server not requiring a padding to a multiple of four bytes.)