X11 でスクリーンキャプチャー その2
32bpp, 16bpp, 8bpp, まで対応してみる.暇なのか?
しかし結局手元の環境で 8bpp の場合に正常な絵をキャプチャすることはできませんでしたとさ.
16bpp だとこんな絵が撮れます.
しかし 8bpp だとこんな絵になってしまいます.
問01 8bpp の絵が変なのは何が間違っているのでしょうか?
以下コード.
/************************************************************ * gcc capture_screen_x11-02.c -L/usr/X11R6/lib -lX11 ************************************************************/ #include <X11/Xlib.h> #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <assert.h> #define IMAGE_FILE_PATH "capture_screen_x11.ppm" int mask2shiftbit(unsigned long mask) { int result = -1; int i; const int bits = sizeof(unsigned long) * 8; const unsigned long msb = 1 << (bits-1); for (i = 0;i < bits;i++) { if (mask & msb) { result = bits - 8 - i; break; } mask <<= 1; } return result; } static void write32bppXImageToP3File(XImage *image, const char *file_path) { FILE *file; assert(image != NULL); assert(image->bits_per_pixel == 32); assert(file_path != NULL); file = fopen(file_path, "wb"); if (file != NULL) { int x, y; uint8_t *datap; int red_shift, green_shift, blue_shift; red_shift = mask2shiftbit(image->red_mask); green_shift = mask2shiftbit(image->green_mask); blue_shift = mask2shiftbit(image->blue_mask); fprintf(file, "P3\n"); fprintf(file, "%d %d\n", image->width, image->height); fprintf(file, "255\n"); for (y = 0;y < image->height;y++) { datap = (uint8_t *)(image->data + y * image->bytes_per_line); for (x = 0;x < image->width;x++) { uint32_t pixel; pixel = *(uint32_t *)datap; fprintf(file, "%lu %lu %lu ", (pixel & image->red_mask) >> red_shift, (pixel & image->green_mask) >> green_shift, (pixel & image->blue_mask) >> blue_shift); datap += 4; } fprintf(file, "\n"); } fclose(file); } } static void write16bppXImageToP3File(XImage *image, const char *file_path) { FILE *file; assert(image != NULL); assert(image->bits_per_pixel == 16); assert(file_path != NULL); file = fopen(file_path, "wb"); if (file != NULL) { int x, y; uint8_t *datap; int red_shift, green_shift, blue_shift; red_shift = mask2shiftbit(image->red_mask); green_shift = mask2shiftbit(image->green_mask); blue_shift = mask2shiftbit(image->blue_mask); fprintf(file, "P3\n"); fprintf(file, "%d %d\n", image->width, image->height); fprintf(file, "255\n"); for (y = 0;y < image->height;y++) { datap = (uint8_t *)(image->data + y * image->bytes_per_line); for (x = 0;x < image->width;x++) { unsigned long r, g, b; uint16_t pixel; pixel = *(uint16_t *)datap; r = pixel & image->red_mask; g = pixel & image->green_mask; b = pixel & image->blue_mask; r = red_shift >= 0 ? r >> red_shift : r << -red_shift; g = green_shift >= 0 ? g >> green_shift : g << -green_shift; b = blue_shift >= 0 ? b >> blue_shift : b << -blue_shift; fprintf(file, "%lu %lu %lu ", r, g, b); datap += 2; } fprintf(file, "\n"); } fclose(file); } } static void write8bppXImageToP3File(XImage *image, XColor *colors, const char *file_path) { FILE *file; assert(image != NULL); assert(image->bits_per_pixel == 8); assert(file_path != NULL); file = fopen(file_path, "wb"); if (file != NULL) { int x, y; uint8_t *datap; fprintf(file, "P3\n"); fprintf(file, "%d %d\n", image->width, image->height); fprintf(file, "255\n"); for (y = 0;y < image->height;y++) { datap = ((uint8_t *)image->data + (y * image->bytes_per_line)); for (x = 0;x < image->width;x++) { XColor color; uint8_t pixel; pixel = *datap; color = colors[pixel]; fprintf(file, "%u %u %u ", color.red >> 8, color.green >> 8, color.blue >> 8); datap += 1; } fprintf(file, "\n"); fflush(file); } fclose(file); } } int main(int argc, char* argv[]) { Display* display; int screen; Window rootWindow; XWindowAttributes attributes; int width, height; XImage *image; display = XOpenDisplay(""); screen = DefaultScreen(display); rootWindow = RootWindow(display, screen); XGetWindowAttributes(display, rootWindow, &attributes); width = attributes.width; height = attributes.height; image = XGetImage(display, rootWindow, 0, 0, width, height, AllPlanes, ZPixmap); if (image != NULL) { switch (image->bits_per_pixel) { case 32 : write32bppXImageToP3File(image, IMAGE_FILE_PATH); break; case 16 : write16bppXImageToP3File(image, IMAGE_FILE_PATH); break; case 8 : { int i, num_colors;; XColor *colors; num_colors = attributes.visual->map_entries; colors = (XColor *)malloc(sizeof(XColor) * num_colors); for (i = 0;i < num_colors;i++) colors[i].pixel = i; XQueryColors(display, attributes.colormap, colors, num_colors); write8bppXImageToP3File(image, colors, IMAGE_FILE_PATH); free(colors); } break; default: fprintf(stderr, "Not supported image : bits_per_pixel = %d\n", image->bits_per_pixel); break; } XFree(image); } XCloseDisplay(display); return 0; }
以下試した環境.
ところで Colormap を処理するかどうかの分岐は Visual class を見るべきなのかなぁ…?