/src/libraw/src/decoders/sonycc.cpp
Line | Count | Source |
1 | | /* -*- C++ -*- |
2 | | * File: sonycc.cpp |
3 | | * Copyright (C) 2024-2025 Alex Tutubalin, LibRaw LLC |
4 | | * |
5 | | Sony YCC (small/medium lossy compressed) decoder |
6 | | |
7 | | Code partially backported from DNGLab's rust code |
8 | | DNGLab was originally created in 2021 by Daniel Vogelbacher. |
9 | | |
10 | | LibRaw is free software; you can redistribute it and/or modify |
11 | | it under the terms of the one of two licenses as you choose: |
12 | | |
13 | | 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 |
14 | | (See file LICENSE.LGPL provided in LibRaw distribution archive for details). |
15 | | |
16 | | 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 |
17 | | (See file LICENSE.CDDL provided in LibRaw distribution archive for details). |
18 | | |
19 | | */ |
20 | | |
21 | | #include "../../internal/libraw_cxx_defs.h" |
22 | | #include "../../internal/losslessjpeg.h" |
23 | | #include <vector> |
24 | | #include <algorithm> |
25 | | |
26 | 16 | #define ifp libraw_internal_data.internal_data.input |
27 | 64 | #define UD libraw_internal_data.unpacker_data |
28 | 28 | #define S imgdata.sizes |
29 | | |
30 | | struct LibRaw_SonyYCC_Decompressor : public LibRaw_LjpegDecompressor |
31 | | { |
32 | 2 | LibRaw_SonyYCC_Decompressor(uint8_t *b, unsigned s): LibRaw_LjpegDecompressor(b,s){} |
33 | | bool decode_sony(std::vector<uint16_t> &dest, int width, int height); |
34 | | bool decode_sony_ljpeg_420(std::vector<uint16_t> &dest, int width, int height); |
35 | | |
36 | | }; |
37 | | |
38 | | static |
39 | | #ifdef _MSC_VER |
40 | | __forceinline |
41 | | #else |
42 | | inline |
43 | | #endif |
44 | | void copy_yuv_420(uint16_t *out, uint32_t row, uint32_t col, uint32_t width, |
45 | | int32_t y1, int32_t y2, int32_t y3, int32_t y4, int32_t cb, int32_t cr) |
46 | 0 | { |
47 | 0 | uint32_t pix1 = row * width + col; |
48 | 0 | uint32_t pix2 = pix1 + 3; |
49 | 0 | uint32_t pix3 = (row + 1) * width + col; |
50 | 0 | uint32_t pix4 = pix3 + 3; |
51 | |
|
52 | 0 | out[pix1 + 0] = uint16_t(y1); |
53 | 0 | out[pix1 + 1] = uint16_t(cb); |
54 | 0 | out[pix1 + 2] = uint16_t(cr); |
55 | 0 | out[pix2 + 0] = uint16_t(y2); |
56 | 0 | out[pix2 + 1] = uint16_t(cb); |
57 | 0 | out[pix2 + 2] = uint16_t(cr); |
58 | 0 | out[pix3 + 0] = uint16_t(y3); |
59 | 0 | out[pix3 + 1] = uint16_t(cb); |
60 | 0 | out[pix3 + 2] = uint16_t(cr); |
61 | 0 | out[pix4 + 0] = uint16_t(y4); |
62 | 0 | out[pix4 + 1] = uint16_t(cb); |
63 | 0 | out[pix4 + 2] = uint16_t(cr); |
64 | 0 | } |
65 | | |
66 | | |
67 | | bool LibRaw_SonyYCC_Decompressor::decode_sony_ljpeg_420(std::vector<uint16_t> &_dest, int width, int height) |
68 | 0 | { |
69 | 0 | if (sof.width * 3 != unsigned(width) || sof.height != unsigned(height)) |
70 | 0 | return false; |
71 | 0 | if (width % 2 || width % 6 || height % 2) |
72 | 0 | return false; |
73 | 0 | if (_dest.size() < size_t(width*height)) |
74 | 0 | return false; |
75 | | |
76 | 0 | HuffTable &huff1 = dhts[sof.components[0].dc_tbl]; |
77 | 0 | HuffTable &huff2 = dhts[sof.components[1].dc_tbl]; |
78 | 0 | HuffTable &huff3 = dhts[sof.components[2].dc_tbl]; |
79 | |
|
80 | 0 | if (!huff1.initialized || !huff2.initialized || !huff3.initialized) |
81 | 0 | return false; |
82 | | |
83 | 0 | BitPumpJpeg pump(buffer); |
84 | |
|
85 | 0 | int32_t base = 1 << (sof.precision - point_transform - 1); |
86 | 0 | int32_t y1 = base + huff1.decode(pump); |
87 | 0 | int32_t y2 = y1 + huff1.decode(pump); |
88 | 0 | int32_t y3 = y1 + huff1.decode(pump); |
89 | 0 | int32_t y4 = y3 + huff1.decode(pump); |
90 | |
|
91 | 0 | int32_t cb = base + huff2.decode(pump); |
92 | 0 | int32_t cr = base + huff3.decode(pump); |
93 | |
|
94 | 0 | uint16_t *dest = _dest.data(); |
95 | 0 | copy_yuv_420(dest, 0, 0, width, y1, y2, y3, y4, cb, cr); |
96 | |
|
97 | 0 | for (int32_t row = 0; row < height; row += 2) |
98 | 0 | { |
99 | 0 | int32_t startcol = row == 0 ? 6 : 0; |
100 | 0 | for (int32_t col = startcol; col < width; col += 6) |
101 | 0 | { |
102 | 0 | int32_t py1, py3, pcb, pcr; |
103 | 0 | if (col == 0) |
104 | 0 | { |
105 | 0 | uint32_t pos = (row - 2) * width; |
106 | 0 | py1 = dest[pos]; |
107 | 0 | py3 = 0; |
108 | 0 | pcb = dest[pos + 1]; |
109 | 0 | pcr = dest[pos + 2]; |
110 | 0 | } |
111 | 0 | else |
112 | 0 | { |
113 | 0 | uint32_t pos1 = row * width + col - 3; |
114 | 0 | uint32_t pos3 = (row + 1) * width + col - 3; |
115 | 0 | py1 = dest[pos1]; |
116 | 0 | py3 = dest[pos3]; |
117 | 0 | pcb = dest[pos1 + 1]; |
118 | 0 | pcr = dest[pos1 + 2]; |
119 | 0 | }; |
120 | 0 | y1 = py1 + huff1.decode(pump); |
121 | 0 | y2 = y1 + huff1.decode(pump); |
122 | 0 | y3 = ((col == 0) ? y1 : py3) + huff1.decode(pump); |
123 | 0 | y4 = y3 + huff1.decode(pump); |
124 | 0 | cb = pcb + huff2.decode(pump); |
125 | 0 | cr = pcr + huff3.decode(pump); |
126 | 0 | copy_yuv_420(dest, row, col, width, y1, y2, y3, y4, cb, cr); |
127 | 0 | } |
128 | 0 | } |
129 | 0 | return true; |
130 | 0 | } |
131 | | |
132 | | bool LibRaw_SonyYCC_Decompressor::decode_sony(std::vector<uint16_t> &dest, int width, int height) |
133 | 0 | { |
134 | 0 | if (sof.components[0].subsample_h == 2 && sof.components[0].subsample_v == 2) |
135 | 0 | { |
136 | 0 | return decode_sony_ljpeg_420(dest, width, height); |
137 | 0 | } |
138 | 0 | else if (sof.components[0].subsample_h == 2 && sof.components[0].subsample_v == 1) |
139 | 0 | return decode_ljpeg_422(dest, width, height); |
140 | 0 | else |
141 | 0 | return false; |
142 | 0 | } |
143 | | |
144 | | static |
145 | | #ifdef _MSC_VER |
146 | | __forceinline |
147 | | #else |
148 | | inline |
149 | | #endif |
150 | | void copy_ycc(ushort dst[][4], int rawwidth, int rawheight, int destrow0, int destcol0, ushort *src, |
151 | | int srcwidth, // full array width is 3x |
152 | | int srcheight, int steph, int stepv) |
153 | 0 | { |
154 | 0 | if (steph < 2 && stepv < 2) |
155 | 0 | { |
156 | 0 | for (int tilerow = 0; tilerow < srcheight && destrow0 + tilerow < rawheight; tilerow++) |
157 | 0 | { |
158 | 0 | ushort(*destrow)[4] = &dst[(destrow0 + tilerow) * rawwidth + destcol0]; |
159 | 0 | for (int tilecol = 0; tilecol < srcwidth && tilecol + destcol0 < rawwidth; tilecol++) |
160 | 0 | { |
161 | 0 | int pix = (tilerow * srcwidth + tilecol) * 3; |
162 | 0 | destrow[tilecol][0] = src[pix]; |
163 | 0 | destrow[tilecol][1] = src[pix + 1] > 8192 ? src[pix + 1] - 8192 : 0; |
164 | 0 | destrow[tilecol][2] = src[pix + 2] > 8192 ? src[pix + 2] - 8192 : 0; |
165 | 0 | } |
166 | 0 | } |
167 | 0 | } |
168 | 0 | else |
169 | 0 | { |
170 | 0 | for (int tilerow = 0; tilerow < srcheight && destrow0 + tilerow < rawheight; tilerow++) |
171 | 0 | { |
172 | 0 | int destrow = destrow0 + tilerow; |
173 | 0 | ushort(*dest)[4] = &dst[destrow * rawwidth + destcol0]; |
174 | 0 | for (int tilecol = 0; tilecol < srcwidth && tilecol + destcol0 < rawwidth; tilecol++) |
175 | 0 | { |
176 | 0 | int pix = (tilerow * srcwidth + tilecol) * 3; |
177 | 0 | int destcol = destcol0 + tilecol; |
178 | 0 | dest[tilecol][0] = src[pix]; |
179 | 0 | if((destrow%stepv) == 0 && (destcol%steph)==0) |
180 | 0 | { |
181 | 0 | dest[tilecol][1] = src[pix + 1] > 8192 ? src[pix + 1] - 8192 : 0; |
182 | 0 | dest[tilecol][2] = src[pix + 2] > 8192 ? src[pix + 2] - 8192 : 0; |
183 | 0 | } |
184 | 0 | } |
185 | 0 | } |
186 | |
|
187 | 0 | } |
188 | 0 | } |
189 | | |
190 | | static |
191 | | #ifdef _MSC_VER |
192 | | __forceinline |
193 | | #else |
194 | | inline |
195 | | #endif |
196 | | uint16_t _lim16bit(float q) |
197 | 0 | { |
198 | 0 | if (q < 0.f) |
199 | 0 | q = 0.f; |
200 | 0 | else if (q > 65535.f) |
201 | 0 | q = 65535.f; |
202 | 0 | return uint16_t(uint32_t(q)); |
203 | 0 | } |
204 | | |
205 | | static |
206 | | #ifdef _MSC_VER |
207 | | __forceinline |
208 | | #else |
209 | | inline |
210 | | #endif |
211 | | void ycc2rgb(uint16_t dst[][4], int rawwidth, int rawheight, int destrow0, int destcol0, ushort *src, |
212 | | int srcwidth, // full array width is 3x |
213 | | int srcheight) |
214 | 0 | { |
215 | 0 | const ushort cdelta = 16383; |
216 | 0 | for (int tilerow = 0; tilerow < srcheight && destrow0 + tilerow < rawheight; tilerow++) |
217 | 0 | { |
218 | 0 | ushort(*destrow)[4] = &dst[(destrow0 + tilerow) * rawwidth + destcol0]; |
219 | 0 | for (int tilecol = 0; tilecol < srcwidth && tilecol + destcol0 < rawwidth; tilecol++) |
220 | 0 | { |
221 | 0 | int pix = (tilerow * srcwidth + tilecol) * 3; |
222 | 0 | float Y = float(src[pix]); |
223 | 0 | float Cb = float(src[pix + 1] - cdelta); |
224 | 0 | float Cr = float(src[pix + 2] - cdelta); |
225 | 0 | float R = Y + 1.40200f * Cr; |
226 | 0 | float G = Y - 0.34414f * Cb - 0.71414f * Cr; |
227 | 0 | float B = Y + 1.77200f * Cb; |
228 | 0 | destrow[tilecol][0] = _lim16bit(R); |
229 | 0 | destrow[tilecol][1] = _lim16bit(G); |
230 | 0 | destrow[tilecol][2] = _lim16bit(B); |
231 | 0 | } |
232 | 0 | } |
233 | 0 | } |
234 | | |
235 | | void LibRaw::sony_ycbcr_load_raw() |
236 | 10 | { |
237 | 10 | if (!imgdata.image) |
238 | 1 | throw LIBRAW_EXCEPTION_IO_CORRUPT; |
239 | | // Sony YCC RAWs are always tiled |
240 | 9 | if (UD.tile_width < 1 || UD.tile_width > S.raw_width) |
241 | 2 | throw LIBRAW_EXCEPTION_IO_CORRUPT; |
242 | 7 | if (UD.tile_length < 1 || UD.tile_length > S.raw_height) |
243 | 1 | throw LIBRAW_EXCEPTION_IO_CORRUPT; |
244 | | |
245 | | // calculate tile count |
246 | 6 | int tile_w = (S.raw_width + UD.tile_width - 1) / UD.tile_width; |
247 | 6 | int tile_h = (S.raw_height + UD.tile_length - 1) / UD.tile_length; |
248 | 6 | int tiles = tile_w * tile_h; |
249 | 6 | if (tiles < 1 || tiles > 1024) |
250 | 2 | throw LIBRAW_EXCEPTION_IO_CORRUPT; |
251 | | |
252 | 4 | INT64 fsize = ifp->size(); |
253 | 4 | std::vector<INT64> toffsets(tiles); |
254 | 4 | ifp->seek(UD.data_offset, SEEK_SET); // We're already here, but to make sure |
255 | 19 | for (int i = 0; i < tiles; i++) |
256 | 15 | toffsets[i] = get4(); |
257 | | |
258 | 4 | std::vector<unsigned> tlengths(tiles); |
259 | 4 | ifp->seek(UD.data_size, SEEK_SET); |
260 | 10 | for (int i = 0; i < tiles; i++) |
261 | 8 | { |
262 | 8 | tlengths[i] = get4(); |
263 | 8 | if(toffsets[i]+tlengths[i] > fsize) |
264 | 2 | throw LIBRAW_EXCEPTION_IO_CORRUPT; |
265 | 8 | } |
266 | 2 | unsigned maxcomprlen = *std::max_element(tlengths.begin(), tlengths.end()); |
267 | | |
268 | 2 | std::vector<uint8_t> iobuffer(maxcomprlen+1); // Extra byte to ensure LJPEG byte stream marker search is ok |
269 | 2 | std::vector<uint16_t> tilebuffer; |
270 | 2 | for (int tile = 0; tile < tiles; tile++) |
271 | 2 | { |
272 | 2 | ifp->seek(toffsets[tile],SEEK_SET); |
273 | 2 | int readed = ifp->read(iobuffer.data(), 1, tlengths[tile]); |
274 | 2 | if(unsigned(readed) != tlengths[tile]) |
275 | 0 | throw LIBRAW_EXCEPTION_IO_EOF; |
276 | 2 | LibRaw_SonyYCC_Decompressor dec(iobuffer.data(), readed); |
277 | 2 | if(dec.sof.cps != 3) // !YUV |
278 | 2 | throw LIBRAW_EXCEPTION_IO_CORRUPT; |
279 | 0 | if(dec.state != LibRaw_LjpegDecompressor::State::OK) |
280 | 0 | throw LIBRAW_EXCEPTION_IO_CORRUPT; |
281 | | |
282 | 0 | unsigned tiledatatsize = UD.tile_width * UD.tile_length * 3; |
283 | 0 | if (tilebuffer.size() < tiledatatsize) |
284 | 0 | tilebuffer.resize(tiledatatsize); |
285 | |
|
286 | 0 | if(!dec.decode_sony(tilebuffer, UD.tile_width * 3, UD.tile_length)) |
287 | 0 | throw LIBRAW_EXCEPTION_IO_CORRUPT; |
288 | | |
289 | 0 | int tilerow = tile / tile_w; |
290 | 0 | int tilecol = tile % tile_w; |
291 | 0 | if (imgdata.rawparams.specials & LIBRAW_RAWSPECIAL_SRAW_NO_RGB) |
292 | 0 | { |
293 | 0 | if(imgdata.rawparams.specials & LIBRAW_RAWSPECIAL_SRAW_NO_INTERPOLATE) |
294 | 0 | copy_ycc(imgdata.image, S.raw_width, S.raw_height, tilerow * UD.tile_length, tilecol * UD.tile_width, |
295 | 0 | tilebuffer.data(), UD.tile_width, UD.tile_length, dec.sof.components[0].subsample_h, dec.sof.components[0].subsample_v); |
296 | 0 | else |
297 | 0 | copy_ycc(imgdata.image, S.raw_width, S.raw_height, tilerow * UD.tile_length, tilecol * UD.tile_width, |
298 | 0 | tilebuffer.data(), UD.tile_width, UD.tile_length, 1, 1); |
299 | 0 | } |
300 | 0 | else |
301 | 0 | ycc2rgb(imgdata.image, S.raw_width, S.raw_height, tilerow * UD.tile_length, tilecol * UD.tile_width, |
302 | 0 | tilebuffer.data(), UD.tile_width, UD.tile_length); |
303 | 0 | } |
304 | | |
305 | 0 | for (int i = 0; i < 6; i++) |
306 | 0 | imgdata.color.cblack[i] = 0; |
307 | |
|
308 | 0 | if (imgdata.rawparams.specials & LIBRAW_RAWSPECIAL_SRAW_NO_RGB) |
309 | 0 | { |
310 | 0 | imgdata.color.maximum = 18091; // estimated on over-exposed ISO100 frame |
311 | 0 | imgdata.color.black = 0; |
312 | 0 | } |
313 | 0 | else |
314 | 0 | { |
315 | 0 | imgdata.color.maximum = 17536; // estimated on over-exposed ISO100 frame |
316 | 0 | imgdata.color.black = 1024; |
317 | 0 | } |
318 | 0 | } |