/src/LibRaw/src/decoders/smal.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- C++ -*- |
2 | | * Copyright 2019-2024 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 | 7.68M | #define HOLE(row) ((holes >> (((row)-raw_height) & 7)) & 1) |
22 | | |
23 | | /* Kudos to Rich Taylor for figuring out SMaL's compression algorithm. */ |
24 | | void LibRaw::smal_decode_segment(unsigned seg[2][2], int holes) |
25 | 437 | { |
26 | 437 | uchar hist[3][13] = {{7, 7, 0, 0, 63, 55, 47, 39, 31, 23, 15, 7, 0}, |
27 | 437 | {7, 7, 0, 0, 63, 55, 47, 39, 31, 23, 15, 7, 0}, |
28 | 437 | {3, 3, 0, 0, 63, 47, 31, 15, 0}}; |
29 | 437 | int low, high = 0xff, carry = 0, nbits = 8; |
30 | 437 | int s, count, bin, next, i, sym[3]; |
31 | 437 | unsigned pix; |
32 | 437 | uchar diff, pred[] = {0, 0}; |
33 | 437 | ushort data = 0, range = 0; |
34 | | |
35 | 437 | fseek(ifp, seg[0][1] + 1, SEEK_SET); |
36 | 437 | getbits(-1); |
37 | 437 | if (seg[1][0] > unsigned(raw_width * raw_height)) |
38 | 214 | seg[1][0] = raw_width * raw_height; |
39 | 125k | for (pix = seg[0][0]; pix < seg[1][0]; pix++) |
40 | 125k | { |
41 | 501k | for (s = 0; s < 3; s++) |
42 | 376k | { |
43 | 376k | data = data << nbits | getbits(nbits); |
44 | 376k | if (carry < 0) |
45 | 65.9k | carry = (nbits += carry + 1) < 1 ? nbits - 1 : 0; |
46 | 476k | while (--nbits >= 0) |
47 | 102k | if ((data >> nbits & 0xff) == 0xff) |
48 | 2.26k | break; |
49 | 376k | if (nbits > 0) |
50 | 596 | data = |
51 | 596 | ((data & ((1 << (nbits - 1)) - 1)) << 1) | |
52 | 596 | ((data + (((data & (1 << (nbits - 1)))) << 1)) & ((~0u) << nbits)); |
53 | 376k | if (nbits >= 0) |
54 | 2.26k | { |
55 | 2.26k | data += getbits(1); |
56 | 2.26k | carry = nbits - 8; |
57 | 2.26k | } |
58 | 376k | count = ((((data - range + 1) & 0xffff) << 2) - 1) / (high >> 4); |
59 | 477k | for (bin = 0; hist[s][bin + 5] > count; bin++) |
60 | 100k | ; |
61 | 376k | low = hist[s][bin + 5] * (high >> 4) >> 2; |
62 | 376k | if (bin) |
63 | 21.1k | high = hist[s][bin + 4] * (high >> 4) >> 2; |
64 | 376k | high -= low; |
65 | 493k | for (nbits = 0; high << nbits < 128; nbits++) |
66 | 117k | ; |
67 | 376k | range = (range + low) << nbits; |
68 | 376k | high <<= nbits; |
69 | 376k | next = hist[s][1]; |
70 | 376k | if (++hist[s][2] > hist[s][3]) |
71 | 128k | { |
72 | 128k | next = (next + 1) & hist[s][0]; |
73 | 128k | hist[s][3] = (hist[s][next + 4] - hist[s][next + 5]) >> 2; |
74 | 128k | hist[s][2] = 1; |
75 | 128k | } |
76 | 376k | if (hist[s][hist[s][1] + 4] - hist[s][hist[s][1] + 5] > 1) |
77 | 284k | { |
78 | 284k | if (bin < hist[s][1]) |
79 | 87.2k | for (i = bin; i < hist[s][1]; i++) |
80 | 68.0k | hist[s][i + 5]--; |
81 | 265k | else if (next <= bin) |
82 | 279k | for (i = hist[s][1]; i < bin; i++) |
83 | 32.6k | hist[s][i + 5]++; |
84 | 284k | } |
85 | 376k | hist[s][1] = next; |
86 | 376k | sym[s] = bin; |
87 | 376k | } |
88 | 125k | diff = sym[2] << 5 | sym[1] << 2 | (sym[0] & 3); |
89 | 125k | if (sym[0] & 4) |
90 | 6.21k | diff = diff ? -diff : 0x80; |
91 | 125k | if (ftell(ifp) + 12 >= seg[1][1]) |
92 | 22.1k | diff = 0; |
93 | 125k | if (pix >= unsigned(raw_width * raw_height)) |
94 | 0 | throw LIBRAW_EXCEPTION_IO_CORRUPT; |
95 | 125k | raw_image[pix] = pred[pix & 1] += diff; |
96 | 125k | if (!(pix & 1) && HOLE(pix / raw_width)) |
97 | 30.7k | pix += 2; |
98 | 125k | } |
99 | 437 | maximum = 0xff; |
100 | 437 | } |
101 | | |
102 | | void LibRaw::smal_v6_load_raw() |
103 | 34 | { |
104 | 34 | unsigned seg[2][2]; |
105 | | |
106 | 34 | fseek(ifp, 16, SEEK_SET); |
107 | 34 | seg[0][0] = 0; |
108 | 34 | seg[0][1] = get2(); |
109 | 34 | seg[1][0] = raw_width * raw_height; |
110 | 34 | seg[1][1] = INT_MAX; |
111 | 34 | smal_decode_segment(seg, 0); |
112 | 34 | } |
113 | | |
114 | | int LibRaw::median4(int *p) |
115 | 3.58M | { |
116 | 3.58M | int min, max, sum, i; |
117 | | |
118 | 3.58M | min = max = sum = p[0]; |
119 | 14.3M | for (i = 1; i < 4; i++) |
120 | 10.7M | { |
121 | 10.7M | sum += p[i]; |
122 | 10.7M | if (min > p[i]) |
123 | 8.07k | min = p[i]; |
124 | 10.7M | if (max < p[i]) |
125 | 7.64k | max = p[i]; |
126 | 10.7M | } |
127 | 3.58M | return (sum - min - max) >> 1; |
128 | 3.58M | } |
129 | | |
130 | | void LibRaw::fill_holes(int holes) |
131 | 65 | { |
132 | 65 | int row, col, val[4]; |
133 | | |
134 | 84.9k | for (row = 2; row < height - 2; row++) |
135 | 84.9k | { |
136 | 84.9k | if (!HOLE(row)) |
137 | 48.2k | continue; |
138 | 3.16M | for (col = 1; col < width - 1; col += 4) |
139 | 3.12M | { |
140 | 3.12M | val[0] = RAW(row - 1, col - 1); |
141 | 3.12M | val[1] = RAW(row - 1, col + 1); |
142 | 3.12M | val[2] = RAW(row + 1, col - 1); |
143 | 3.12M | val[3] = RAW(row + 1, col + 1); |
144 | 3.12M | RAW(row, col) = median4(val); |
145 | 3.12M | } |
146 | 3.14M | for (col = 2; col < width - 2; col += 4) |
147 | 3.11M | if (HOLE(row - 2) || HOLE(row + 2)) |
148 | 3.11M | RAW(row, col) = (RAW(row, col - 2) + RAW(row, col + 2)) >> 1; |
149 | 450k | else |
150 | 450k | { |
151 | 450k | val[0] = RAW(row, col - 2); |
152 | 450k | val[1] = RAW(row, col + 2); |
153 | 450k | val[2] = RAW(row - 2, col); |
154 | 450k | val[3] = RAW(row + 2, col); |
155 | 450k | RAW(row, col) = median4(val); |
156 | 450k | } |
157 | 36.6k | } |
158 | 65 | } |
159 | | |
160 | | void LibRaw::smal_v9_load_raw() |
161 | 117 | { |
162 | 117 | unsigned seg[256][2], offset, nseg, holes, i; |
163 | | |
164 | 117 | fseek(ifp, 67, SEEK_SET); |
165 | 117 | offset = get4(); |
166 | 117 | nseg = (uchar)fgetc(ifp); |
167 | 117 | fseek(ifp, offset, SEEK_SET); |
168 | 1.86k | for (i = 0; i < nseg * 2; i++) |
169 | 1.74k | ((unsigned *)seg)[i] = get4() + unsigned(data_offset & 0xffffffff) * (i & 1); |
170 | 117 | fseek(ifp, 78, SEEK_SET); |
171 | 117 | holes = fgetc(ifp); |
172 | 117 | fseek(ifp, 88, SEEK_SET); |
173 | 117 | seg[nseg][0] = raw_height * raw_width; |
174 | 117 | seg[nseg][1] = get4() + unsigned(data_offset & 0xffffffff); |
175 | 520 | for (i = 0; i < nseg; i++) |
176 | 403 | smal_decode_segment(seg + i, holes); |
177 | 117 | if (holes) |
178 | 65 | fill_holes(holes); |
179 | 117 | } |
180 | | |
181 | | #undef HOLE |