File: | ./io/_ccv_io_bmp.inc |
Warning: | line 64, column 12 File position of the stream might be 'indeterminate' after a failed operation. Can cause undefined behavior |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | #include "ccv.h" | ||||
2 | #include "ccv_internal.h" | ||||
3 | #ifdef HAVE_LIBPNG1 | ||||
4 | #ifdef __APPLE__ | ||||
5 | #include "TargetConditionals.h" | ||||
6 | #if TARGET_OS_IPHONE | ||||
7 | // iOS | ||||
8 | #elif TARGET_IPHONE_SIMULATOR | ||||
9 | // iOS Simulator | ||||
10 | #elif TARGET_OS_MAC | ||||
11 | #include <zlib.h> | ||||
12 | #include <png.h> | ||||
13 | #else | ||||
14 | // Unsupported platform | ||||
15 | #endif | ||||
16 | #else | ||||
17 | #include <zlib.h> | ||||
18 | #include <png.h> | ||||
19 | #endif | ||||
20 | #include "io/_ccv_io_libpng.inc" | ||||
21 | #endif | ||||
22 | #ifdef HAVE_LIBJPEG1 | ||||
23 | #include <jpeglib.h> | ||||
24 | #include "io/_ccv_io_libjpeg.inc" | ||||
25 | #endif | ||||
26 | #if defined(__unix__1) || (defined(__APPLE__) && defined(__MACH__)) | ||||
27 | #include <sys/param.h> | ||||
28 | #endif | ||||
29 | #include "io/_ccv_io_bmp.inc" | ||||
30 | #include "io/_ccv_io_binary.inc" | ||||
31 | #include "io/_ccv_io_raw.inc" | ||||
32 | |||||
33 | static int _ccv_read_and_close_fd(FILE* fd, ccv_dense_matrix_t** x, int type) | ||||
34 | { | ||||
35 | int ctype = (type & 0xF00) ? CCV_8U | ((type & 0xF00) >> 8) : 0; | ||||
36 | if ((type & 0XFF) == CCV_IO_ANY_FILE) | ||||
37 | { | ||||
38 | unsigned char sig[8]; | ||||
39 | (void) fread(sig, 1, 8, fd); | ||||
40 | if (memcmp(sig, "\x89\x50\x4e\x47\xd\xa\x1a\xa", 8) == 0) | ||||
41 | type = CCV_IO_PNG_FILE; | ||||
42 | else if (memcmp(sig, "\xff\xd8\xff", 3) == 0) | ||||
43 | type = CCV_IO_JPEG_FILE; | ||||
44 | else if (memcmp(sig, "BM", 2) == 0) | ||||
45 | type = CCV_IO_BMP_FILE; | ||||
46 | else if (memcmp(sig, "CCVBINDM", 8) == 0) | ||||
47 | type = CCV_IO_BINARY_FILE; | ||||
48 | fseek(fd, 0, SEEK_SET0); | ||||
49 | } | ||||
50 | switch (type & 0XFF) | ||||
51 | { | ||||
52 | #ifdef HAVE_LIBJPEG1 | ||||
53 | case CCV_IO_JPEG_FILE: | ||||
54 | _ccv_read_jpeg_fd(fd, x, ctype); | ||||
55 | break; | ||||
56 | #endif | ||||
57 | #ifdef HAVE_LIBPNG1 | ||||
58 | case CCV_IO_PNG_FILE: | ||||
59 | _ccv_read_png_fd(fd, x, ctype); | ||||
60 | break; | ||||
61 | #endif | ||||
62 | case CCV_IO_BMP_FILE: | ||||
63 | _ccv_read_bmp_fd(fd, x, ctype); | ||||
64 | break; | ||||
65 | case CCV_IO_BINARY_FILE: | ||||
66 | _ccv_read_binary_fd(fd, x, ctype); | ||||
67 | } | ||||
68 | if (*x != 0) | ||||
69 | ccv_make_matrix_immutable(*x); | ||||
70 | if (type & CCV_IO_ANY_FILE) | ||||
71 | fclose(fd); | ||||
72 | return CCV_IO_FINAL; | ||||
73 | } | ||||
74 | |||||
75 | static int _ccv_read_raw(ccv_dense_matrix_t** x, void* data, int type, int rows, int cols, int scanline) | ||||
76 | { | ||||
77 | assert(rows > 0 && cols > 0 && scanline > 0)((void) sizeof ((rows > 0 && cols > 0 && scanline > 0) ? 1 : 0), __extension__ ({ if (rows > 0 && cols > 0 && scanline > 0) ; else __assert_fail ("rows > 0 && cols > 0 && scanline > 0" , "ccv_io.c", 77, __extension__ __PRETTY_FUNCTION__); })); | ||||
78 | if (type & CCV_IO_NO_COPY) | ||||
79 | { | ||||
80 | // there is no conversion that we can apply if it is NO_COPY mode | ||||
81 | // NO_COPY mode generate an "unreusable" matrix, which requires you to | ||||
82 | // manually release its data block (which is, in fact the same data | ||||
83 | // block you passed in) | ||||
84 | int ctype = CCV_8U | CCV_C1; | ||||
85 | switch (type & 0xFF) | ||||
86 | { | ||||
87 | case CCV_IO_RGB_RAW: | ||||
88 | case CCV_IO_BGR_RAW: | ||||
89 | ctype = CCV_8U | CCV_C3; | ||||
90 | break; | ||||
91 | case CCV_IO_RGBA_RAW: | ||||
92 | case CCV_IO_ARGB_RAW: | ||||
93 | case CCV_IO_BGRA_RAW: | ||||
94 | case CCV_IO_ABGR_RAW: | ||||
95 | ctype = CCV_8U | CCV_C4; | ||||
96 | break; | ||||
97 | case CCV_IO_GRAY_RAW: | ||||
98 | default: | ||||
99 | /* default one */ | ||||
100 | break; | ||||
101 | } | ||||
102 | *x = ccv_dense_matrix_new(rows, cols, ctype | CCV_NO_DATA_ALLOC, data, 0); | ||||
103 | (*x)->step = scanline; | ||||
104 | } else { | ||||
105 | switch (type & 0xFF) | ||||
106 | { | ||||
107 | case CCV_IO_RGB_RAW: | ||||
108 | _ccv_read_rgb_raw(x, data, type, rows, cols, scanline); | ||||
109 | break; | ||||
110 | case CCV_IO_RGBA_RAW: | ||||
111 | _ccv_read_rgba_raw(x, data, type, rows, cols, scanline); | ||||
112 | break; | ||||
113 | case CCV_IO_ARGB_RAW: | ||||
114 | _ccv_read_argb_raw(x, data, type, rows, cols, scanline); | ||||
115 | break; | ||||
116 | case CCV_IO_BGR_RAW: | ||||
117 | _ccv_read_bgr_raw(x, data, type, rows, cols, scanline); | ||||
118 | break; | ||||
119 | case CCV_IO_BGRA_RAW: | ||||
120 | _ccv_read_bgra_raw(x, data, type, rows, cols, scanline); | ||||
121 | break; | ||||
122 | case CCV_IO_ABGR_RAW: | ||||
123 | _ccv_read_abgr_raw(x, data, type, rows, cols, scanline); | ||||
124 | break; | ||||
125 | case CCV_IO_GRAY_RAW: | ||||
126 | _ccv_read_gray_raw(x, data, type, rows, cols, scanline); | ||||
127 | break; | ||||
128 | } | ||||
129 | } | ||||
130 | if (*x != 0) | ||||
131 | ccv_make_matrix_immutable(*x); | ||||
132 | return CCV_IO_FINAL; | ||||
133 | } | ||||
134 | |||||
135 | #if defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) | ||||
136 | |||||
137 | typedef struct { | ||||
138 | char* buffer; | ||||
139 | off_t pos; | ||||
140 | size_t size; | ||||
141 | } ccv_io_mem_t; | ||||
142 | |||||
143 | static int readfn(void* context, char* buf, int size) | ||||
144 | { | ||||
145 | ccv_io_mem_t* mem = (ccv_io_mem_t*)context; | ||||
146 | if (size + mem->pos > mem->size) | ||||
147 | size = mem->size - mem->pos; | ||||
148 | memcpy(buf, mem->buffer + mem->pos, size); | ||||
149 | mem->pos += size; | ||||
150 | return size; | ||||
151 | } | ||||
152 | |||||
153 | static off_t seekfn(void* context, off_t off, int whence) | ||||
154 | { | ||||
155 | ccv_io_mem_t* mem = (ccv_io_mem_t*)context; | ||||
156 | off_t pos; | ||||
157 | switch (whence) | ||||
158 | { | ||||
159 | case SEEK_SET0: | ||||
160 | pos = off; | ||||
161 | break; | ||||
162 | case SEEK_CUR1: | ||||
163 | pos = mem->pos + off; | ||||
164 | break; | ||||
165 | case SEEK_END2: | ||||
166 | pos = mem->size + off; | ||||
167 | break; | ||||
168 | } | ||||
169 | if (pos >= mem->size) | ||||
170 | return -1; | ||||
171 | mem->pos = pos; | ||||
172 | return pos; | ||||
173 | } | ||||
174 | |||||
175 | static int writefn(void* context, const char* buf, int size) | ||||
176 | { | ||||
177 | ccv_io_mem_t* mem = (ccv_io_mem_t*)context; | ||||
178 | if (size + mem->pos > mem->size) | ||||
179 | return -1; | ||||
180 | memcpy(mem->buffer + mem->pos, buf, size); | ||||
181 | mem->pos += size; | ||||
182 | return size; | ||||
183 | } | ||||
184 | #endif | ||||
185 | |||||
186 | int ccv_read_impl(const void* in, ccv_dense_matrix_t** x, int type, int rows, int cols, int scanline) | ||||
187 | { | ||||
188 | FILE* fd = 0; | ||||
189 | if (type & CCV_IO_ANY_FILE) | ||||
| |||||
190 | { | ||||
191 | assert(rows == 0 && cols == 0 && scanline == 0)((void) sizeof ((rows == 0 && cols == 0 && scanline == 0) ? 1 : 0), __extension__ ({ if (rows == 0 && cols == 0 && scanline == 0) ; else __assert_fail ("rows == 0 && cols == 0 && scanline == 0" , "ccv_io.c", 191, __extension__ __PRETTY_FUNCTION__); })); | ||||
192 | fd = fopen((const char*)in, "rb"); | ||||
193 | if (!fd
| ||||
194 | return CCV_IO_ERROR; | ||||
195 | return _ccv_read_and_close_fd(fd, x, type); | ||||
196 | } else if (type & CCV_IO_ANY_STREAM) { | ||||
197 | assert(rows > 8 && cols == 0 && scanline == 0)((void) sizeof ((rows > 8 && cols == 0 && scanline == 0) ? 1 : 0), __extension__ ({ if (rows > 8 && cols == 0 && scanline == 0) ; else __assert_fail ("rows > 8 && cols == 0 && scanline == 0" , "ccv_io.c", 197, __extension__ __PRETTY_FUNCTION__); })); | ||||
198 | assert((type & 0xFF) != CCV_IO_DEFLATE_STREAM)((void) sizeof (((type & 0xFF) != CCV_IO_DEFLATE_STREAM) ? 1 : 0), __extension__ ({ if ((type & 0xFF) != CCV_IO_DEFLATE_STREAM ) ; else __assert_fail ("(type & 0xFF) != CCV_IO_DEFLATE_STREAM" , "ccv_io.c", 198, __extension__ __PRETTY_FUNCTION__); })); // deflate stream (compressed stream) is not supported yet | ||||
199 | #if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE200809L >= 200809L || defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) | ||||
200 | // this is only supported by glibc | ||||
201 | #if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE200809L >= 200809L | ||||
202 | fd = fmemopen((void*)in, (size_t)rows, "rb"); | ||||
203 | #else | ||||
204 | ccv_io_mem_t mem = { | ||||
205 | .size = rows, | ||||
206 | .pos = 0, | ||||
207 | .buffer = (char*)in, | ||||
208 | }; | ||||
209 | fd = funopen(&mem, readfn, 0, seekfn, 0); | ||||
210 | #endif | ||||
211 | if (!fd) | ||||
212 | return CCV_IO_ERROR; | ||||
213 | // mimicking itself as a "file" | ||||
214 | type = (type & ~0x10) | 0x20; | ||||
215 | return _ccv_read_and_close_fd(fd, x, type); | ||||
216 | #endif | ||||
217 | } else if (type & CCV_IO_ANY_RAW) { | ||||
218 | return _ccv_read_raw(x, (void*)in /* it can be modifiable if it is NO_COPY mode */, type, rows, cols, scanline); | ||||
219 | } | ||||
220 | return CCV_IO_UNKNOWN; | ||||
221 | } | ||||
222 | |||||
223 | int ccv_write(ccv_dense_matrix_t* mat, char* const out, size_t* const len, int type, void* conf) | ||||
224 | { | ||||
225 | FILE* fd = 0; | ||||
226 | #if defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) | ||||
227 | ccv_io_mem_t mem = {0}; | ||||
228 | #endif | ||||
229 | if (type & CCV_IO_ANY_FILE) | ||||
230 | { | ||||
231 | fd = fopen(out, "wb"); | ||||
232 | if (!fd) | ||||
233 | return CCV_IO_ERROR; | ||||
234 | } else if ((type & CCV_IO_ANY_STREAM) && type != CCV_IO_PLAIN_STREAM) { | ||||
235 | assert(len)((void) sizeof ((len) ? 1 : 0), __extension__ ({ if (len) ; else __assert_fail ("len", "ccv_io.c", 235, __extension__ __PRETTY_FUNCTION__ ); })); | ||||
236 | assert((type & 0xFF) != CCV_IO_DEFLATE_STREAM)((void) sizeof (((type & 0xFF) != CCV_IO_DEFLATE_STREAM) ? 1 : 0), __extension__ ({ if ((type & 0xFF) != CCV_IO_DEFLATE_STREAM ) ; else __assert_fail ("(type & 0xFF) != CCV_IO_DEFLATE_STREAM" , "ccv_io.c", 236, __extension__ __PRETTY_FUNCTION__); })); // deflate stream (compressed stream) is not supported yet | ||||
237 | #if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE200809L >= 200809L || defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) | ||||
238 | // this is only supported by glibc | ||||
239 | #if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE200809L >= 200809L | ||||
240 | fd = fmemopen((void*)out, *len, "wb"); | ||||
241 | #else | ||||
242 | mem.size = *len; | ||||
243 | mem.buffer = out; | ||||
244 | fd = funopen(&mem, 0, writefn, seekfn, 0); | ||||
245 | #endif | ||||
246 | #endif | ||||
247 | } | ||||
248 | int err = 0; | ||||
249 | switch (type) | ||||
250 | { | ||||
251 | case CCV_IO_JPEG_FILE: | ||||
252 | #ifdef HAVE_LIBJPEG1 | ||||
253 | err = _ccv_write_jpeg_fd(mat, fd, conf); | ||||
254 | if (len != 0) | ||||
255 | *len = 0; | ||||
256 | #else | ||||
257 | assert(0 && "ccv_write requires libjpeg support for JPEG format")((void) sizeof ((0 && "ccv_write requires libjpeg support for JPEG format" ) ? 1 : 0), __extension__ ({ if (0 && "ccv_write requires libjpeg support for JPEG format" ) ; else __assert_fail ("0 && \"ccv_write requires libjpeg support for JPEG format\"" , "ccv_io.c", 257, __extension__ __PRETTY_FUNCTION__); })); | ||||
258 | #endif | ||||
259 | break; | ||||
260 | case CCV_IO_PNG_FILE: | ||||
261 | #ifdef HAVE_LIBPNG1 | ||||
262 | err = _ccv_write_png_fd(mat, fd, conf); | ||||
263 | if (len != 0) | ||||
264 | *len = 0; | ||||
265 | #else | ||||
266 | assert(0 && "ccv_write requires libpng support for PNG format")((void) sizeof ((0 && "ccv_write requires libpng support for PNG format" ) ? 1 : 0), __extension__ ({ if (0 && "ccv_write requires libpng support for PNG format" ) ; else __assert_fail ("0 && \"ccv_write requires libpng support for PNG format\"" , "ccv_io.c", 266, __extension__ __PRETTY_FUNCTION__); })); | ||||
267 | #endif | ||||
268 | break; | ||||
269 | case CCV_IO_BINARY_FILE: | ||||
270 | _ccv_write_binary_fd(mat, fd, conf); | ||||
271 | if (len != 0) | ||||
272 | *len = 0; | ||||
273 | break; | ||||
274 | case CCV_IO_JPEG_STREAM: | ||||
275 | #ifdef HAVE_LIBJPEG1 | ||||
276 | err = _ccv_write_jpeg_fd(mat, fd, conf); | ||||
277 | #else | ||||
278 | assert(0 && "ccv_write requires libjpeg support for JPEG format")((void) sizeof ((0 && "ccv_write requires libjpeg support for JPEG format" ) ? 1 : 0), __extension__ ({ if (0 && "ccv_write requires libjpeg support for JPEG format" ) ; else __assert_fail ("0 && \"ccv_write requires libjpeg support for JPEG format\"" , "ccv_io.c", 278, __extension__ __PRETTY_FUNCTION__); })); | ||||
279 | #endif | ||||
280 | break; | ||||
281 | case CCV_IO_PNG_STREAM: | ||||
282 | #ifdef HAVE_LIBPNG1 | ||||
283 | err = _ccv_write_png_fd(mat, fd, conf); | ||||
284 | #else | ||||
285 | assert(0 && "ccv_write requires libpng support for PNG format")((void) sizeof ((0 && "ccv_write requires libpng support for PNG format" ) ? 1 : 0), __extension__ ({ if (0 && "ccv_write requires libpng support for PNG format" ) ; else __assert_fail ("0 && \"ccv_write requires libpng support for PNG format\"" , "ccv_io.c", 285, __extension__ __PRETTY_FUNCTION__); })); | ||||
286 | #endif | ||||
287 | break; | ||||
288 | case CCV_IO_PLAIN_STREAM: | ||||
289 | err = _ccv_write_plain_stream(mat, out, *len); | ||||
290 | *len = 20 + mat->step * mat->rows; | ||||
291 | break; | ||||
292 | } | ||||
293 | if ((type & CCV_IO_ANY_STREAM) && type != CCV_IO_PLAIN_STREAM) | ||||
294 | *len = (size_t)ftell(fd); | ||||
295 | if (fd) | ||||
296 | fclose(fd); | ||||
297 | return err != 0 ? CCV_IO_ERROR : CCV_IO_FINAL; | ||||
298 | } |
1 | static void _ccv_read_bmp_fd(FILE* in, ccv_dense_matrix_t** x, int type) | ||||
2 | { | ||||
3 | fseek(in, 10, SEEK_SET0); | ||||
4 | int offset; | ||||
5 | (void) fread(&offset, 4, 1, in); | ||||
6 | int size; | ||||
7 | (void) fread(&size, 4, 1, in); | ||||
8 | int width = 0, height = 0, bpp = 0, rle_code = 0, clrused = 0; | ||||
9 | if (size >= 36) | ||||
10 | { | ||||
11 | (void) fread(&width, 4, 1, in); | ||||
12 | (void) fread(&height, 4, 1, in); | ||||
13 | (void) fread(&bpp, 4, 1, in); | ||||
14 | bpp = bpp >> 16; | ||||
15 | (void) fread(&rle_code, 4, 1, in); | ||||
16 | fseek(in, 12, SEEK_CUR1); | ||||
17 | (void) fread(&clrused, 4, 1, in); | ||||
18 | fseek(in, size - 36, SEEK_CUR1); | ||||
19 | /* only support 24-bit bmp */ | ||||
20 | } else if (size == 12) { | ||||
21 | (void) fread(&width, 4, 1, in); | ||||
22 | (void) fread(&height, 4, 1, in); | ||||
23 | (void) fread(&bpp, 4, 1, in); | ||||
24 | bpp = bpp >> 16; | ||||
25 | /* TODO: not finished */ | ||||
26 | } | ||||
27 | if (width == 0 || height == 0 || bpp == 0) | ||||
28 | return; | ||||
29 | ccv_dense_matrix_t* im = *x; | ||||
30 | if (im == 0) | ||||
31 | *x = im = ccv_dense_matrix_new(height, width, (type) ? type : CCV_8U | ((bpp > 8) ? CCV_C3 : CCV_C1), 0, 0); | ||||
32 | fseek(in, offset, SEEK_SET0); | ||||
33 | int i, j; | ||||
34 | unsigned char* ptr = im->data.u8 + (im->rows - 1) * im->step; | ||||
35 | if ((bpp == 8 && CCV_GET_CHANNEL(im->type)((im->type) & 0xFFF) == CCV_C1) || (bpp == 24 && CCV_GET_CHANNEL(im->type)((im->type) & 0xFFF) == CCV_C3)) | ||||
36 | { | ||||
37 | if (CCV_GET_CHANNEL(im->type)((im->type) & 0xFFF) == CCV_C1) | ||||
38 | { | ||||
39 | for (i = 0; i < im->rows; i++) | ||||
40 | { | ||||
41 | (void) fread(ptr, 1, im->step, in); | ||||
42 | ptr -= im->step; | ||||
43 | } | ||||
44 | } else { | ||||
45 | for (i = 0; i < im->rows; i++) | ||||
46 | { | ||||
47 | (void) fread(ptr, 1, im->step, in); | ||||
48 | for (j = 0; j < im->cols * 3; j += 3) | ||||
49 | { | ||||
50 | unsigned char t = ptr[j]; | ||||
51 | ptr[j] = ptr[j + 2]; | ||||
52 | ptr[j + 2] = t; | ||||
53 | } | ||||
54 | ptr -= im->step; | ||||
55 | } | ||||
56 | } | ||||
57 | } else { | ||||
58 | if (bpp
| ||||
59 | { | ||||
60 | int bufstep = (im->cols * 3 + 3) & -4; | ||||
61 | unsigned char* buffer = (unsigned char*)alloca(bufstep)__builtin_alloca (bufstep); | ||||
62 | for (i = 0; i < im->rows; i++) | ||||
63 | { | ||||
64 | (void) fread(buffer, 1, bufstep, in); | ||||
| |||||
65 | unsigned char* rgb = buffer; | ||||
66 | unsigned char* g = ptr; | ||||
67 | for(j = 0; j < im->cols; j++, rgb += 3, g++) | ||||
68 | *g = (unsigned char)((rgb[2] * 6969 + rgb[1] * 23434 + rgb[0] * 2365) >> 15); | ||||
69 | ptr -= im->step; | ||||
70 | } | ||||
71 | } else if (bpp == 8 && CCV_GET_CHANNEL(im->type)((im->type) & 0xFFF) == CCV_C3) { | ||||
72 | int bufstep = (im->cols + 3) & -4; | ||||
73 | unsigned char* buffer = (unsigned char*)alloca(bufstep)__builtin_alloca (bufstep); | ||||
74 | for (i = 0; i < im->rows; i++) | ||||
75 | { | ||||
76 | (void) fread(buffer, 1, bufstep, in); | ||||
77 | unsigned char* g = buffer; | ||||
78 | unsigned char* rgb = ptr; | ||||
79 | for(j = 0; j < im->cols; j++, rgb += 3, g++) | ||||
80 | rgb[2] = rgb[1] = rgb[0] = *g; | ||||
81 | ptr -= im->step; | ||||
82 | } | ||||
83 | } | ||||
84 | } | ||||
85 | } |