1 /*
2 * Copyright (C) 2013 DENSO CORPORATION
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and
5 * its documentation for any purpose is hereby granted without fee, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of the copyright holders not be used in
9 * advertising or publicity pertaining to distribution of the software
10 * without specific, written prior permission. The copyright holders make
11 * no representations about the suitability of this software for any
12 * purpose. It is provided "as is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 */
22 #include "bitmap.h"
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stdlib.h>
26 #include <stdbool.h>
27 #include <arpa/inet.h>
28 #include <endian.h>
29 #include "ivi-wm-client-protocol.h"
30
31 struct __attribute__ ((__packed__)) BITMAPFILEHEADER {
32 char bfType[2];
33 uint32_t bfSize;
34 uint16_t bfReserved1;
35 uint16_t bfReserved2;
36 uint32_t bfOffBits;
37 };
38
39 struct __attribute__ ((__packed__)) BITMAPINFOHEADER {
40 uint32_t biSize;
41 uint32_t biWidth;
42 uint32_t biHeight;
43 uint16_t biPlanes;
44 uint16_t biBitCount;
45 uint32_t biCompression;
46 uint32_t biSizeImage;
47 uint32_t biXPixPerMeter;
48 uint32_t biYPixPerMeter;
49 uint32_t biClrUsed;
50 uint32_t biClrImporant;
51 };
52
53 static void
create_file_header(struct BITMAPFILEHEADER * file_header,int32_t image_size)54 create_file_header(struct BITMAPFILEHEADER *file_header, int32_t image_size)
55 {
56 file_header->bfType[0] = 'B';
57 file_header->bfType[1] = 'M';
58 file_header->bfSize = htole32(sizeof(struct BITMAPFILEHEADER) +
59 sizeof(struct BITMAPINFOHEADER) +
60 image_size);
61 file_header->bfOffBits = htole32(sizeof(struct BITMAPFILEHEADER) +
62 sizeof(struct BITMAPINFOHEADER));
63 }
64
65 static void
create_info_header(struct BITMAPINFOHEADER * info_header,int32_t image_size,int32_t width,int32_t height,int16_t bpp)66 create_info_header(struct BITMAPINFOHEADER *info_header, int32_t image_size, int32_t width, int32_t height, int16_t bpp)
67 {
68 info_header->biSize = htole32(sizeof(struct BITMAPINFOHEADER));
69 info_header->biWidth = htole32(width);
70 info_header->biHeight = htole32(height);
71 info_header->biPlanes = htole16(1);
72 info_header->biBitCount = htole16(bpp);
73 info_header->biSizeImage = htole32(image_size);
74 }
75
76 static int
write_bitmap(const char * filename,const struct BITMAPFILEHEADER * file_header,const struct BITMAPINFOHEADER * info_header,const char * buffer)77 write_bitmap(const char *filename,
78 const struct BITMAPFILEHEADER *file_header,
79 const struct BITMAPINFOHEADER *info_header,
80 const char *buffer)
81 {
82 FILE *fp = fopen(filename, "w");
83 if (fp == NULL) {
84 return -1;
85 }
86
87 fwrite(file_header, sizeof(struct BITMAPFILEHEADER), 1, fp);
88 fwrite(info_header, sizeof(struct BITMAPINFOHEADER), 1, fp);
89 fwrite(buffer, info_header->biSizeImage, 1, fp);
90
91 fclose(fp);
92 return 0;
93 }
94
95 int
save_as_bitmap(const char * filename,const char * buffer,int32_t width,int32_t height,uint32_t format)96 save_as_bitmap(const char *filename,
97 const char *buffer,
98 int32_t width,
99 int32_t height,
100 uint32_t format)
101 {
102 int32_t image_stride = 0;
103 int32_t image_size = 0;
104 char *image_buffer = NULL;
105 int32_t row = 0;
106 int32_t col = 0;
107 int32_t image_offset = 0;
108 int32_t offset = 0;
109 int32_t i = 0;
110 int32_t j = 0;
111 int bytes_per_pixel;
112 bool flip_order;
113 bool has_alpha;
114
115 if ((filename == NULL) || (buffer == NULL)) {
116 return -1;
117 }
118
119 switch (format) {
120 case WL_SHM_FORMAT_ARGB8888:
121 flip_order = true;
122 has_alpha = true;
123 break;
124 case WL_SHM_FORMAT_XRGB8888:
125 flip_order = true;
126 has_alpha = false;
127 break;
128 case WL_SHM_FORMAT_ABGR8888:
129 flip_order = false;
130 has_alpha = true;
131 break;
132 case WL_SHM_FORMAT_XBGR8888:
133 flip_order = false;
134 has_alpha = false;
135 break;
136 default:
137 fprintf(stderr, "unsupported pixelformat 0x%x\n", format);
138 return -1;
139 }
140
141 bytes_per_pixel = has_alpha ? 4 : 3;
142 image_stride = (((width * bytes_per_pixel) + 3) & ~3);
143 image_size = image_stride * height;
144
145 image_buffer = malloc(image_size);
146 if (image_buffer == NULL) {
147 fprintf(stderr, "failed to allocate %d bytes for image buffer: %m\n",
148 image_size);
149 return -1;
150 }
151
152 // Store the image in image_buffer in the follwing order B, G, R, [A](B at the lowest address)
153 for (row = 0; row < height; ++row) {
154 for (col = 0; col < width; ++col) {
155 offset = (height - row - 1) * width + col;
156 uint32_t pixel = htonl(((uint32_t*)buffer)[offset]);
157 char * pixel_p = (char*) &pixel;
158 image_offset = row * image_stride + col * bytes_per_pixel;
159 for (i = 0; i < 3; ++i) {
160 j = flip_order ? 2 - i : i;
161 image_buffer[image_offset + i] = pixel_p[1 + j];
162 }
163 if (has_alpha) {
164 image_buffer[image_offset + 3] = pixel_p[0];
165 }
166 }
167 }
168
169 struct BITMAPFILEHEADER file_header = {};
170 struct BITMAPINFOHEADER info_header = {};
171
172 create_file_header(&file_header, image_size);
173 create_info_header(&info_header, image_size, width, height, bytes_per_pixel * 8);
174 if (write_bitmap(filename, &file_header, &info_header, image_buffer) != 0) {
175 free(image_buffer);
176 return -1;
177 }
178
179 free(image_buffer);
180 return 0;
181 }
182