Fix camcount to work with caffeine proxitude
[7seg/.git] / shit.c
1 #include <stdlib.h>
2 #include <unistd.h>
3 #include <stdio.h>
4 #include <stdint.h>
5 #include <fcntl.h>
6 #include <linux/fb.h>
7 #include <sys/mman.h>
8 #include <sys/ioctl.h>
9 #include <assert.h>
10 #include <png.h>
11
12 #define MIN(x, y) ((x) < (y) ? (x) : (y))
13 #define MAX(x, y) ((x) > (y) ? (x) : (y))
14
15 static inline void log_color_type(png_structp png_ptr, png_infop info_ptr) {
16     switch(png_get_color_type(png_ptr, info_ptr)) {
17       case PNG_COLOR_TYPE_GRAY:
18         puts("gray shit");
19         break;
20       case PNG_COLOR_TYPE_GRAY_ALPHA:
21         puts("transparent gray shit");
22         break;
23       case PNG_COLOR_TYPE_PALETTE:
24         puts("some shit");
25         break;
26       case PNG_COLOR_TYPE_RGB:
27         puts("rgb shit");
28         break;
29       case PNG_COLOR_TYPE_RGB_ALPHA:
30         puts("rgba shit");
31         break;
32     }
33 }
34
35 int main(int argc, char** argv)
36 {
37     int fbfd = 0;
38     struct fb_var_screeninfo vinfo;
39     struct fb_fix_screeninfo finfo;
40     long int screensize = 0;
41     char *fbp = 0;
42     long int location = 0;
43     if (argc < 2) {
44       perror("Error: need a png to shit");
45       return 1;
46     }
47     FILE * fp = fopen(argv[1], "rb");
48     if (!fp) {
49       perror("Error: need a valid png to shit");
50       perror(argv[1]);
51       return 1;
52     }
53     png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL,
54         NULL, NULL);;
55     if (!png_ptr) {
56       perror("THAT SHIT CRAY");
57       exit(1);
58     }
59     png_infop info_ptr = png_create_info_struct(png_ptr);
60     if (!info_ptr) {
61       perror("THAT SHIT CRAY");
62       exit(1);
63     }
64     png_init_io(png_ptr, fp);
65     png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
66
67     // Open the file for reading and writing
68     fbfd = open("/dev/fb0", O_RDWR);
69     if (fbfd == -1) {
70         perror("Error: cannot open framebuffer device");
71         exit(1);
72     }
73     printf("The framebuffer device was opened successfully.\n");
74
75     // Get fixed screen information
76     if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) {
77         perror("Error reading fixed information");
78         exit(2);
79     }
80
81     // Get variable screen information
82     if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
83         perror("Error reading variable information");
84         exit(3);
85     }
86
87     printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);
88
89     // Figure out the size of the screen in bytes
90     screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
91
92     // Map the device to memory
93     fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
94     if ((int)fbp == -1) {
95         perror("Error: failed to map framebuffer device to memory");
96         exit(4);
97     }
98     printf("The framebuffer device was mapped to memory successfully.\n");
99     uint8_t png_channels = png_get_channels(png_ptr, info_ptr);
100     uint32_t png_bit_depth = png_get_bit_depth(png_ptr, info_ptr);
101     log_color_type(png_ptr, info_ptr);
102     // dump this shit to a framebuffer nigga
103     assert(vinfo.bits_per_pixel == 32);
104     if (info_ptr->interlace_type || png_bit_depth != 8) {
105       perror("NON RBG888? INTERLACING!? FUCK OFF AND DIE");
106       munmap(fbp, screensize);
107       close(fbfd);
108       fclose(fp);
109       return 1;
110     }
111
112     printf("png %ux%u\n", png_get_image_width(png_ptr, info_ptr),
113         png_get_image_height(png_ptr, info_ptr));
114     printf("png # of png_channels: %d\n", png_channels);
115     printf("png interlace: %s\n", png_get_interlace_type(png_ptr, info_ptr) ? "YES" :  "NO");
116     printf("png bit depth: %u\n", png_get_bit_depth(png_ptr, info_ptr));
117     printf("screen x-yoffset: %d %d\n", vinfo.xoffset, vinfo.yoffset);
118
119     png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr);
120     for (int y = 0; y < MIN(info_ptr->height, vinfo.yres-2); ++y) {
121       for (int x = 0; x < MIN(info_ptr->width, png_channels*vinfo.xres-2); ++x) {
122         assert(x*y*png_channels < png_channels*screensize);
123         location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +
124                     (y+vinfo.yoffset) * finfo.line_length;
125
126         if (png_channels == 3 || png_channels == 4) {
127           *(fbp + location) = row_pointers[y][png_channels*x+2]; // BLUE
128           *(fbp + location + 1) = row_pointers[y][(png_channels*x)+1]; // GREEN
129           *(fbp + location + 2) = row_pointers[y][(png_channels*x)]; // RED
130         } else if (png_channels == 1) {
131           *(fbp + location) = row_pointers[y][x]; // BLUE
132           *(fbp + location + 1) = row_pointers[y][x]; // GREEN
133           *(fbp + location + 2) = row_pointers[y][x]; // RED
134         }
135         *(fbp + location + 3) = 0;      // No transparency
136       }
137     }
138     vinfo.activate |= FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
139     munmap(fbp, screensize);
140     close(fbfd);
141     fclose(fp);
142     return 0;
143 }