/src/LibRaw/src/metadata/misc_parsers.cpp
Line | Count | Source |
1 | | /* -*- C++ -*- |
2 | | * Copyright 2019-2025 LibRaw LLC (info@libraw.org) |
3 | | * |
4 | | LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, |
5 | | dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. |
6 | | LibRaw do not use RESTRICTED code from dcraw.c |
7 | | |
8 | | LibRaw is free software; you can redistribute it and/or modify |
9 | | it under the terms of the one of two licenses as you choose: |
10 | | |
11 | | 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 |
12 | | (See file LICENSE.LGPL provided in LibRaw distribution archive for details). |
13 | | |
14 | | 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 |
15 | | (See file LICENSE.CDDL provided in LibRaw distribution archive for details). |
16 | | |
17 | | */ |
18 | | |
19 | | #include "../../internal/dcraw_defs.h" |
20 | | |
21 | | /* |
22 | | Returns 1 for a Coolpix 2100, 0 for anything else. |
23 | | */ |
24 | | int LibRaw::nikon_e2100() |
25 | 0 | { |
26 | 0 | uchar t[12]; |
27 | 0 | int i; |
28 | |
|
29 | 0 | fseek(ifp, 0, SEEK_SET); |
30 | 0 | for (i = 0; i < 1024; i++) |
31 | 0 | { |
32 | 0 | fread(t, 1, 12, ifp); |
33 | 0 | if (((t[2] & t[4] & t[7] & t[9]) >> 4 & t[1] & t[6] & t[8] & t[11] & 3) != |
34 | 0 | 3) |
35 | 0 | return 0; |
36 | 0 | } |
37 | 0 | return 1; |
38 | 0 | } |
39 | | |
40 | | void LibRaw::nikon_3700() |
41 | 0 | { |
42 | 0 | int bits, i; |
43 | 0 | uchar dp[24]; |
44 | 0 | static const struct |
45 | 0 | { |
46 | 0 | int bits; |
47 | 0 | char t_make[12], t_model[15]; |
48 | 0 | int t_maker_idx; |
49 | 0 | } table[] = {{0x00, "Pentax", "Optio 33WR", LIBRAW_CAMERAMAKER_Pentax}, |
50 | 0 | {0x03, "Nikon", "E3200", LIBRAW_CAMERAMAKER_Nikon}, |
51 | 0 | {0x32, "Nikon", "E3700", LIBRAW_CAMERAMAKER_Nikon}, |
52 | 0 | {0x33, "Olympus", "C-740UZ", LIBRAW_CAMERAMAKER_Olympus}}; |
53 | |
|
54 | 0 | fseek(ifp, 3072, SEEK_SET); |
55 | 0 | fread(dp, 1, 24, ifp); |
56 | 0 | bits = (dp[8] & 3) << 4 | (dp[20] & 3); |
57 | 0 | for (i = 0; i < int(sizeof table / sizeof *table); i++) |
58 | 0 | if (bits == table[i].bits) |
59 | 0 | { |
60 | 0 | strcpy(make, table[i].t_make); |
61 | 0 | maker_index = table[i].t_maker_idx; |
62 | 0 | strcpy(model, table[i].t_model); |
63 | 0 | } |
64 | 0 | } |
65 | | |
66 | | /* |
67 | | Separates a Minolta DiMAGE Z2 from a Nikon E4300. |
68 | | */ |
69 | | int LibRaw::minolta_z2() |
70 | 0 | { |
71 | 0 | int i, nz; |
72 | 0 | char tail[424]; |
73 | 0 | memset(tail,0,sizeof(tail)); |
74 | 0 | fseek(ifp, -int(sizeof tail), SEEK_END); |
75 | 0 | fread(tail, 1, sizeof tail, ifp); |
76 | 0 | for (nz = i = 0; i < int(sizeof tail); i++) |
77 | 0 | if (tail[i]) |
78 | 0 | nz++; |
79 | 0 | return nz > 20; |
80 | 0 | } |
81 | | |
82 | | int LibRaw::canon_s2is() |
83 | 0 | { |
84 | 0 | unsigned row; |
85 | |
|
86 | 0 | for (row = 0; row < 100; row++) |
87 | 0 | { |
88 | 0 | fseek(ifp, row * 3340 + 3284, SEEK_SET); |
89 | 0 | if (getc(ifp) > 15) |
90 | 0 | return 1; |
91 | 0 | } |
92 | 0 | return 0; |
93 | 0 | } |
94 | | |
95 | | void LibRaw::parse_cine() |
96 | 0 | { |
97 | 0 | unsigned off_head, off_setup, off_image, i, temp; |
98 | |
|
99 | 0 | order = 0x4949; |
100 | 0 | fseek(ifp, 4, SEEK_SET); |
101 | 0 | is_raw = get2() == 2; |
102 | 0 | fseek(ifp, 14, SEEK_CUR); |
103 | 0 | is_raw *= get4(); |
104 | 0 | off_head = get4(); |
105 | 0 | off_setup = get4(); |
106 | 0 | off_image = get4(); |
107 | 0 | timestamp = get4(); |
108 | 0 | if ((i = get4())) |
109 | 0 | timestamp = i; |
110 | 0 | fseek(ifp, off_head + 4, SEEK_SET); |
111 | 0 | raw_width = get4(); |
112 | 0 | raw_height = get4(); |
113 | 0 | switch (get2(), get2()) |
114 | 0 | { |
115 | 0 | case 8: |
116 | 0 | load_raw = &LibRaw::eight_bit_load_raw; |
117 | 0 | break; |
118 | 0 | case 16: |
119 | 0 | load_raw = &LibRaw::unpacked_load_raw; |
120 | 0 | } |
121 | 0 | fseek(ifp, off_setup + 792, SEEK_SET); |
122 | 0 | strcpy(make, "CINE"); |
123 | 0 | sprintf(model, "%d", get4()); |
124 | 0 | fseek(ifp, 12, SEEK_CUR); |
125 | 0 | switch ((i = get4()) & 0xffffff) |
126 | 0 | { |
127 | 0 | case 3: |
128 | 0 | filters = 0x94949494; |
129 | 0 | break; |
130 | 0 | case 4: |
131 | 0 | filters = 0x49494949; |
132 | 0 | break; |
133 | 0 | default: |
134 | 0 | is_raw = 0; |
135 | 0 | } |
136 | 0 | fseek(ifp, 72, SEEK_CUR); |
137 | 0 | switch ((get4() + 3600) % 360) |
138 | 0 | { |
139 | 0 | case 270: |
140 | 0 | flip = 4; |
141 | 0 | break; |
142 | 0 | case 180: |
143 | 0 | flip = 1; |
144 | 0 | break; |
145 | 0 | case 90: |
146 | 0 | flip = 7; |
147 | 0 | break; |
148 | 0 | case 0: |
149 | 0 | flip = 2; |
150 | 0 | } |
151 | 0 | cam_mul[0] = getrealf(LIBRAW_EXIFTAG_TYPE_FLOAT); |
152 | 0 | cam_mul[2] = getrealf(LIBRAW_EXIFTAG_TYPE_FLOAT); |
153 | 0 | temp = get4(); |
154 | 0 | maximum = ~((~0u) << LIM(temp, 1, 31)); |
155 | 0 | fseek(ifp, 668, SEEK_CUR); |
156 | 0 | shutter = float(get4()) / 1000000000.f; |
157 | 0 | fseek(ifp, off_image, SEEK_SET); |
158 | 0 | if (shot_select < is_raw) |
159 | 0 | fseek(ifp, shot_select * 8, SEEK_CUR); |
160 | 0 | data_offset = (INT64)get4() + 8; |
161 | 0 | data_offset += (INT64)get4() << 32; |
162 | 0 | } |
163 | | |
164 | | void LibRaw::parse_qt(INT64 end) |
165 | 0 | { |
166 | 0 | unsigned size; |
167 | 0 | INT64 save; |
168 | 0 | char tag[4]; |
169 | |
|
170 | 0 | order = 0x4d4d; |
171 | 0 | while (ftell(ifp) + 7 < end) |
172 | 0 | { |
173 | 0 | save = ftell(ifp); |
174 | 0 | if ((size = get4()) < 8) |
175 | 0 | return; |
176 | 0 | if ((int)size < 0) |
177 | 0 | return; // 2+GB is too much |
178 | 0 | if (save + size < save) |
179 | 0 | return; // 32bit overflow |
180 | 0 | memset(tag,0,sizeof(tag)); |
181 | 0 | fread(tag, 4, 1, ifp); |
182 | 0 | if (!memcmp(tag, "moov", 4) || !memcmp(tag, "udta", 4) || |
183 | 0 | !memcmp(tag, "CNTH", 4)) |
184 | 0 | parse_qt(save + size); |
185 | 0 | if (!memcmp(tag, "CNDA", 4)) |
186 | 0 | parse_jpeg(ftell(ifp)); |
187 | 0 | fseek(ifp, save + INT64(size), SEEK_SET); |
188 | 0 | } |
189 | 0 | } |
190 | | |
191 | | void LibRaw::parse_smal(INT64 offset, INT64 fsize) |
192 | 0 | { |
193 | 0 | int ver; |
194 | |
|
195 | 0 | fseek(ifp, offset + 2LL, SEEK_SET); |
196 | 0 | order = 0x4949; |
197 | 0 | ver = fgetc(ifp); |
198 | 0 | if (ver == 6) |
199 | 0 | fseek(ifp, 5, SEEK_CUR); |
200 | 0 | if (INT64(get4()) != fsize) |
201 | 0 | return; |
202 | 0 | if (ver > 6) |
203 | 0 | data_offset = get4(); |
204 | 0 | raw_height = height = get2(); |
205 | 0 | raw_width = width = get2(); |
206 | 0 | strcpy(make, "SMaL"); |
207 | 0 | sprintf(model, "v%d %dx%d", ver, width, height); |
208 | 0 | if (ver == 6) |
209 | 0 | load_raw = &LibRaw::smal_v6_load_raw; |
210 | 0 | if (ver == 9) |
211 | 0 | load_raw = &LibRaw::smal_v9_load_raw; |
212 | 0 | } |
213 | | |
214 | | void LibRaw::parse_riff(int maxdepth) |
215 | 0 | { |
216 | 0 | unsigned i, size; |
217 | 0 | INT64 end; |
218 | 0 | char tag[4] = {0, 0, 0, 0}, date[64], month[64]; |
219 | 0 | static const char mon[12][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", |
220 | 0 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; |
221 | 0 | struct tm t; |
222 | 0 | if (maxdepth < 1) |
223 | 0 | throw LIBRAW_EXCEPTION_IO_CORRUPT; |
224 | | |
225 | 0 | order = 0x4949; |
226 | 0 | fread(tag, 4, 1, ifp); |
227 | 0 | size = get4(); |
228 | 0 | end = ftell(ifp) + size; |
229 | 0 | if (!memcmp(tag, "RIFF", 4) || !memcmp(tag, "LIST", 4)) |
230 | 0 | { |
231 | 0 | int maxloop = 1000; |
232 | 0 | get4(); |
233 | 0 | while (ftell(ifp) + 7 < end && !feof(ifp) && maxloop--) |
234 | 0 | parse_riff(maxdepth-1); |
235 | 0 | } |
236 | 0 | else if (!memcmp(tag, "nctg", 4)) |
237 | 0 | { |
238 | 0 | while (ftell(ifp) + 7 < end) |
239 | 0 | { |
240 | 0 | if (feof(ifp)) |
241 | 0 | break; |
242 | 0 | i = get2(); |
243 | 0 | size = get2(); |
244 | 0 | if ((i + 1) >> 1 == 10 && size == 20) |
245 | 0 | get_timestamp(0); |
246 | 0 | else |
247 | 0 | fseek(ifp, size, SEEK_CUR); |
248 | 0 | } |
249 | 0 | } |
250 | 0 | else if (!memcmp(tag, "IDIT", 4) && size < 64) |
251 | 0 | { |
252 | 0 | memset(date,0,sizeof(date)); |
253 | 0 | fread(date, 64, 1, ifp); |
254 | 0 | date[size] = 0; |
255 | 0 | memset(&t, 0, sizeof t); |
256 | 0 | if (sscanf(date, "%*s %s %d %d:%d:%d %d", month, &t.tm_mday, &t.tm_hour, |
257 | 0 | &t.tm_min, &t.tm_sec, &t.tm_year) == 6) |
258 | 0 | { |
259 | 0 | for (i = 0; i < 12 && strcasecmp(mon[i], month); i++) |
260 | 0 | ; |
261 | 0 | t.tm_mon = i; |
262 | 0 | t.tm_year -= 1900; |
263 | 0 | if (mktime(&t) > 0) |
264 | 0 | timestamp = mktime(&t); |
265 | 0 | } |
266 | 0 | } |
267 | 0 | else |
268 | 0 | fseek(ifp, size, SEEK_CUR); |
269 | 0 | } |
270 | | |
271 | | void LibRaw::parse_rollei() |
272 | 0 | { |
273 | 0 | char line[128], *val; |
274 | 0 | struct tm t; |
275 | |
|
276 | 0 | fseek(ifp, 0, SEEK_SET); |
277 | 0 | memset(&t, 0, sizeof t); |
278 | 0 | do |
279 | 0 | { |
280 | 0 | line[0] = 0; |
281 | 0 | if (!fgets(line, 128, ifp)) |
282 | 0 | break; |
283 | 0 | line[127] = 0; |
284 | 0 | if(!line[0]) break; // zero-length |
285 | 0 | if ((val = strchr(line, '='))) |
286 | 0 | *val++ = 0; |
287 | 0 | else |
288 | 0 | val = line + strbuflen(line); |
289 | 0 | if (!strcmp(line, "DAT")) |
290 | 0 | sscanf(val, "%d.%d.%d", &t.tm_mday, &t.tm_mon, &t.tm_year); |
291 | 0 | if (!strcmp(line, "TIM")) |
292 | 0 | sscanf(val, "%d:%d:%d", &t.tm_hour, &t.tm_min, &t.tm_sec); |
293 | 0 | if (!strcmp(line, "HDR")) |
294 | 0 | thumb_offset = atoi(val); |
295 | 0 | if (!strcmp(line, "X ")) |
296 | 0 | raw_width = atoi(val); |
297 | 0 | if (!strcmp(line, "Y ")) |
298 | 0 | raw_height = atoi(val); |
299 | 0 | if (!strcmp(line, "TX ")) |
300 | 0 | thumb_width = atoi(val); |
301 | 0 | if (!strcmp(line, "TY ")) |
302 | 0 | thumb_height = atoi(val); |
303 | 0 | if (!strcmp(line, "APT")) |
304 | 0 | aperture = float(atof(val)); |
305 | 0 | if (!strcmp(line, "SPE")) |
306 | 0 | shutter = float(atof(val)); |
307 | 0 | if (!strcmp(line, "FOCLEN")) |
308 | 0 | focal_len = float(atof(val)); |
309 | 0 | if (!strcmp(line, "BLKOFS")) |
310 | 0 | black = atoi(val) +1; |
311 | 0 | if (!strcmp(line, "ORI")) |
312 | 0 | switch (atoi(val)) { |
313 | 0 | case 1: |
314 | 0 | flip = 6; |
315 | 0 | break; |
316 | 0 | case 2: |
317 | 0 | flip = 3; |
318 | 0 | break; |
319 | 0 | case 3: |
320 | 0 | flip = 5; |
321 | 0 | break; |
322 | 0 | } |
323 | 0 | if (!strcmp(line, "CUTRECT")) { |
324 | 0 | sscanf(val, "%hu %hu %hu %hu", |
325 | 0 | &imgdata.sizes.raw_inset_crops[0].cleft, |
326 | 0 | &imgdata.sizes.raw_inset_crops[0].ctop, |
327 | 0 | &imgdata.sizes.raw_inset_crops[0].cwidth, |
328 | 0 | &imgdata.sizes.raw_inset_crops[0].cheight); |
329 | 0 | } |
330 | 0 | } while (strncmp(line, "EOHD", 4)); |
331 | 0 | data_offset = thumb_offset + thumb_width * thumb_height * 2; |
332 | 0 | t.tm_year -= 1900; |
333 | 0 | t.tm_mon -= 1; |
334 | 0 | if (mktime(&t) > 0) |
335 | 0 | timestamp = mktime(&t); |
336 | 0 | strcpy(make, "Rollei"); |
337 | 0 | strcpy(model, "d530flex"); |
338 | 0 | thumb_format = LIBRAW_INTERNAL_THUMBNAIL_ROLLEI; |
339 | 0 | } |
340 | | |
341 | | void LibRaw::parse_sinar_ia() |
342 | 0 | { |
343 | 0 | int entries, off; |
344 | 0 | char str[8], *cp; |
345 | |
|
346 | 0 | order = 0x4949; |
347 | 0 | fseek(ifp, 4, SEEK_SET); |
348 | 0 | entries = get4(); |
349 | 0 | if (entries < 1 || entries > 8192) |
350 | 0 | return; |
351 | 0 | fseek(ifp, get4(), SEEK_SET); |
352 | 0 | while (entries--) |
353 | 0 | { |
354 | 0 | off = get4(); |
355 | 0 | get4(); |
356 | 0 | memset(str, 0, sizeof(str)); |
357 | 0 | fread(str, 8, 1, ifp); |
358 | 0 | str[7] = 0; // Ensure end of string |
359 | 0 | if (!strcmp(str, "META")) |
360 | 0 | meta_offset = off; |
361 | 0 | if (!strcmp(str, "THUMB")) |
362 | 0 | thumb_offset = off; |
363 | 0 | if (!strcmp(str, "RAW0")) |
364 | 0 | data_offset = off; |
365 | 0 | } |
366 | 0 | fseek(ifp, meta_offset + 20, SEEK_SET); |
367 | 0 | fread(make, 64, 1, ifp); |
368 | 0 | make[63] = 0; |
369 | 0 | if ((cp = strchr(make, ' '))) |
370 | 0 | { |
371 | 0 | strcpy(model, cp + 1); |
372 | 0 | *cp = 0; |
373 | 0 | } |
374 | 0 | raw_width = get2(); |
375 | 0 | raw_height = get2(); |
376 | 0 | load_raw = &LibRaw::unpacked_load_raw; |
377 | 0 | thumb_width = (get4(), get2()); |
378 | 0 | thumb_height = get2(); |
379 | 0 | thumb_format = LIBRAW_INTERNAL_THUMBNAIL_PPM; |
380 | 0 | maximum = 0x3fff; |
381 | 0 | } |
382 | | |
383 | | void LibRaw::parse_kyocera() |
384 | 0 | { |
385 | |
|
386 | 0 | int c; |
387 | 0 | static const ushort table[13] = {25, 32, 40, 50, 64, 80, 100, |
388 | 0 | 125, 160, 200, 250, 320, 400}; |
389 | |
|
390 | 0 | fseek(ifp, 33, SEEK_SET); |
391 | 0 | get_timestamp(1); |
392 | 0 | fseek(ifp, 52, SEEK_SET); |
393 | 0 | c = get4(); |
394 | 0 | if ((c > 6) && (c < 20)) |
395 | 0 | iso_speed = table[c - 7]; |
396 | 0 | shutter = libraw_powf64l(2.0f, (((float)get4()) / 8.0f)) / 16000.0f; |
397 | 0 | FORC4 cam_mul[RGGB_2_RGBG(c)] = float(get4()); |
398 | 0 | fseek(ifp, 88, SEEK_SET); |
399 | 0 | aperture = libraw_powf64l(2.0f, ((float)get4()) / 16.0f); |
400 | 0 | fseek(ifp, 112, SEEK_SET); |
401 | 0 | focal_len = float(get4()); |
402 | |
|
403 | 0 | fseek(ifp, 104, SEEK_SET); |
404 | 0 | ilm.MaxAp4CurFocal = libraw_powf64l(2.0f, ((float)get4()) / 16.0f); |
405 | 0 | fseek(ifp, 124, SEEK_SET); |
406 | 0 | stmread(ilm.Lens, 32, ifp); |
407 | 0 | ilm.CameraMount = LIBRAW_MOUNT_Contax_N; |
408 | 0 | ilm.CameraFormat = LIBRAW_FORMAT_FF; |
409 | 0 | if (ilm.Lens[0]) |
410 | 0 | { |
411 | 0 | ilm.LensMount = LIBRAW_MOUNT_Contax_N; |
412 | 0 | ilm.LensFormat = LIBRAW_FORMAT_FF; |
413 | 0 | } |
414 | 0 | } |
415 | | |
416 | | int LibRaw::parse_jpeg(INT64 offset) |
417 | 0 | { |
418 | 0 | int len, hlen, mark; |
419 | 0 | INT64 save; |
420 | |
|
421 | 0 | fseek(ifp, offset, SEEK_SET); |
422 | 0 | if (fgetc(ifp) != 0xff || fgetc(ifp) != 0xd8) |
423 | 0 | return 0; |
424 | | |
425 | 0 | while (fgetc(ifp) == 0xff && (mark = fgetc(ifp)) != 0xda) |
426 | 0 | { |
427 | 0 | order = 0x4d4d; |
428 | 0 | len = get2() - 2; |
429 | 0 | save = ftell(ifp); |
430 | 0 | if (mark == 0xc0 || mark == 0xc3 || mark == 0xc9) |
431 | 0 | { |
432 | 0 | fgetc(ifp); |
433 | 0 | raw_height = get2(); |
434 | 0 | raw_width = get2(); |
435 | 0 | } |
436 | 0 | order = get2(); |
437 | 0 | hlen = get4(); |
438 | 0 | if (get4() == 0x48454150 && (save + INT64(hlen)) >= 0 && |
439 | 0 | (save + INT64(hlen)) <= ifp->size()) /* "HEAP" */ |
440 | 0 | { |
441 | 0 | parse_ciff(save + hlen, len - hlen, 0); |
442 | 0 | } |
443 | 0 | if (parse_tiff(save + 6)) |
444 | 0 | apply_tiff(); |
445 | 0 | fseek(ifp, save + INT64(len), SEEK_SET); |
446 | 0 | } |
447 | 0 | return 1; |
448 | 0 | } |
449 | | |
450 | | void LibRaw::parse_thumb_note(INT64 base, unsigned toff, unsigned tlen) |
451 | 0 | { |
452 | 0 | unsigned entries, tag, type, len; |
453 | 0 | INT64 save; |
454 | |
|
455 | 0 | entries = get2(); |
456 | 0 | while (entries--) |
457 | 0 | { |
458 | 0 | tiff_get(base, &tag, &type, &len, &save); |
459 | 0 | if (tag == toff) |
460 | 0 | thumb_offset = get4() + base; |
461 | 0 | if (tag == tlen) |
462 | 0 | thumb_length = get4(); |
463 | 0 | fseek(ifp, save, SEEK_SET); |
464 | 0 | } |
465 | 0 | } |
466 | | |
467 | | void LibRaw::parse_broadcom() |
468 | 0 | { |
469 | | |
470 | | /* This structure is at offset 0xb0 from the 'BRCM' ident. */ |
471 | 0 | struct |
472 | 0 | { |
473 | 0 | uint8_t umode[32]; |
474 | 0 | uint16_t uwidth; |
475 | 0 | uint16_t uheight; |
476 | 0 | uint16_t padding_right; |
477 | 0 | uint16_t padding_down; |
478 | 0 | uint32_t unknown_block[6]; |
479 | 0 | uint16_t transform; |
480 | 0 | uint16_t format; |
481 | 0 | uint8_t bayer_order; |
482 | 0 | uint8_t bayer_format; |
483 | 0 | } header; |
484 | |
|
485 | 0 | header.bayer_order = 0; |
486 | 0 | fseek(ifp, 0xb0 - 0x20, SEEK_CUR); |
487 | 0 | fread(&header, 1, sizeof(header), ifp); |
488 | 0 | raw_stride = |
489 | 0 | ((((((header.uwidth + header.padding_right) * 5) + 3) >> 2) + 0x1f) & |
490 | 0 | (~0x1f)); |
491 | 0 | raw_width = width = header.uwidth; |
492 | 0 | raw_height = height = header.uheight; |
493 | 0 | filters = 0x16161616; /* default Bayer order is 2, BGGR */ |
494 | |
|
495 | 0 | switch (header.bayer_order) |
496 | 0 | { |
497 | 0 | case 0: /* RGGB */ |
498 | 0 | filters = 0x94949494; |
499 | 0 | break; |
500 | 0 | case 1: /* GBRG */ |
501 | 0 | filters = 0x49494949; |
502 | 0 | break; |
503 | 0 | case 3: /* GRBG */ |
504 | 0 | filters = 0x61616161; |
505 | 0 | break; |
506 | 0 | } |
507 | 0 | } |
508 | | |
509 | | /* |
510 | | Returns 1 for a Coolpix 995, 0 for anything else. |
511 | | */ |
512 | | int LibRaw::nikon_e995() |
513 | 0 | { |
514 | 0 | int i, histo[256]; |
515 | 0 | const uchar often[] = {0x00, 0x55, 0xaa, 0xff}; |
516 | |
|
517 | 0 | memset(histo, 0, sizeof histo); |
518 | 0 | fseek(ifp, -2000, SEEK_END); |
519 | 0 | for (i = 0; i < 2000; i++) |
520 | 0 | histo[fgetc(ifp)]++; |
521 | 0 | for (i = 0; i < 4; i++) |
522 | 0 | if (histo[often[i]] < 200) |
523 | 0 | return 0; |
524 | 0 | return 1; |
525 | 0 | } |
526 | | |
527 | | /* |
528 | | Since the TIFF DateTime string has no timezone information, |
529 | | assume that the camera's clock was set to Universal Time. |
530 | | */ |
531 | | void LibRaw::get_timestamp(int reversed) |
532 | 0 | { |
533 | 0 | struct tm t; |
534 | 0 | char str[20]; |
535 | 0 | int i; |
536 | |
|
537 | 0 | str[19] = 0; |
538 | 0 | if (reversed) |
539 | 0 | for (i = 19; i--;) |
540 | 0 | str[i] = fgetc(ifp); |
541 | 0 | else |
542 | 0 | fread(str, 19, 1, ifp); |
543 | 0 | memset(&t, 0, sizeof t); |
544 | 0 | if (sscanf(str, "%d:%d:%d %d:%d:%d", &t.tm_year, &t.tm_mon, &t.tm_mday, |
545 | 0 | &t.tm_hour, &t.tm_min, &t.tm_sec) != 6) |
546 | 0 | return; |
547 | 0 | t.tm_year -= 1900; |
548 | 0 | t.tm_mon -= 1; |
549 | 0 | t.tm_isdst = -1; |
550 | 0 | if (mktime(&t) > 0) |
551 | 0 | timestamp = mktime(&t); |
552 | 0 | } |
553 | | |
554 | | #ifdef USE_6BY9RPI |
555 | | void LibRaw::parse_raspberrypi() |
556 | | { |
557 | | //This structure is at offset 0xB0 from the 'BRCM' ident. |
558 | | struct brcm_raw_header { |
559 | | uint8_t name[32]; |
560 | | uint16_t h_width; |
561 | | uint16_t h_height; |
562 | | uint16_t padding_right; |
563 | | uint16_t padding_down; |
564 | | uint32_t dummy[6]; |
565 | | uint16_t transform; |
566 | | uint16_t format; |
567 | | uint8_t bayer_order; |
568 | | uint8_t bayer_format; |
569 | | }; |
570 | | //Values taken from https://github.com/raspberrypi/userland/blob/master/interface/vctypes/vc_image_types.h |
571 | | #define BRCM_FORMAT_BAYER 33 |
572 | | #define BRCM_BAYER_RAW8 2 |
573 | | #define BRCM_BAYER_RAW10 3 |
574 | | #define BRCM_BAYER_RAW12 4 |
575 | | #define BRCM_BAYER_RAW14 5 |
576 | | #define BRCM_BAYER_RAW16 6 |
577 | | |
578 | | struct brcm_raw_header header; |
579 | | uint8_t brcm_tag[4]; |
580 | | |
581 | | if (ftell(ifp) > 22LL) // 22 bytes is minimum jpeg size |
582 | | { |
583 | | thumb_length = unsigned(ftell(ifp)); |
584 | | thumb_offset = 0; |
585 | | thumb_width = thumb_height = 0; |
586 | | load_flags |= 0x4000; // flag: we have JPEG from beginning to meta_offset |
587 | | } |
588 | | |
589 | | // Sanity check that the caller has found a BRCM header |
590 | | if (!fread(brcm_tag, 1, sizeof(brcm_tag), ifp) || |
591 | | memcmp(brcm_tag, "BRCM", sizeof(brcm_tag))) |
592 | | return; |
593 | | |
594 | | width = raw_width; |
595 | | data_offset = ftell(ifp) + 0x8000 - sizeof(brcm_tag); |
596 | | |
597 | | if (!fseek(ifp, 0xB0 - int(sizeof(brcm_tag)), SEEK_CUR) && |
598 | | fread(&header, 1, sizeof(header), ifp)) { |
599 | | switch (header.bayer_order) { |
600 | | case 0: //RGGB |
601 | | filters = 0x94949494; |
602 | | break; |
603 | | case 1: //GBRG |
604 | | filters = 0x49494949; |
605 | | break; |
606 | | default: |
607 | | case 2: //BGGR |
608 | | filters = 0x16161616; |
609 | | break; |
610 | | case 3: //GRBG |
611 | | filters = 0x61616161; |
612 | | break; |
613 | | } |
614 | | |
615 | | if (header.format == BRCM_FORMAT_BAYER) { |
616 | | switch (header.bayer_format) { |
617 | | case BRCM_BAYER_RAW8: |
618 | | load_raw = &LibRaw::rpi_load_raw8; |
619 | | //1 pixel per byte |
620 | | raw_stride = ((header.h_width + header.padding_right) + 31)&(~31); |
621 | | width = header.h_width; |
622 | | raw_height = height = header.h_height; |
623 | | is_raw = 1; |
624 | | order = 0x4d4d; |
625 | | break; |
626 | | case BRCM_BAYER_RAW10: |
627 | | load_raw = &LibRaw::nokia_load_raw; |
628 | | //4 pixels per 5 bytes |
629 | | raw_stride = (((((header.h_width + header.padding_right) * 5) + 3) >> 2) + 31)&(~31); |
630 | | width = header.h_width; |
631 | | raw_height = height = header.h_height; |
632 | | is_raw = 1; |
633 | | order = 0x4d4d; |
634 | | break; |
635 | | case BRCM_BAYER_RAW12: |
636 | | load_raw = &LibRaw::rpi_load_raw12; |
637 | | //2 pixels per 3 bytes |
638 | | raw_stride = (((((header.h_width + header.padding_right) * 3) + 1) >> 1) + 31)&(~31); |
639 | | width = header.h_width; |
640 | | raw_height = height = header.h_height; |
641 | | is_raw = 1; |
642 | | order = 0x4d4d; |
643 | | break; |
644 | | case BRCM_BAYER_RAW14: |
645 | | load_raw = &LibRaw::rpi_load_raw14; |
646 | | //4 pixels per 7 bytes |
647 | | raw_stride = (((((header.h_width + header.padding_right) * 7) + 3) >> 2) + 31)&(~31); |
648 | | width = header.h_width; |
649 | | raw_height = height = header.h_height; |
650 | | is_raw = 1; |
651 | | order = 0x4d4d; |
652 | | break; |
653 | | case BRCM_BAYER_RAW16: |
654 | | load_raw = &LibRaw::rpi_load_raw16; |
655 | | //1 pixel per 2 bytes |
656 | | raw_stride = (((header.h_width + header.padding_right) << 1) + 31)&(~31); |
657 | | width = header.h_width; |
658 | | raw_height = height = header.h_height; |
659 | | is_raw = 1; |
660 | | order = 0x4d4d; |
661 | | break; |
662 | | default: |
663 | | break; |
664 | | } |
665 | | } |
666 | | } |
667 | | } |
668 | | #endif |