22
22
#include " jpeg-parser.h"
23
23
24
24
#include < cstring>
25
+ #include < functional>
25
26
26
27
27
28
gboolean is_jpeg_container (const guchar *data, guint size)
@@ -108,69 +109,65 @@ static guint32 tiff_byte_get_int32(const guchar *f, TiffByteOrder bo)
108
109
return GUINT32_FROM_BE (align_buf); // NOLINT
109
110
}
110
111
111
- static gint tiff_directory_offset (const guchar *data, const guint len,
112
- guint * offset, TiffByteOrder * bo)
112
+ static gboolean tiff_directory_offset (const guchar *data, const guint len,
113
+ guint & offset, TiffByteOrder & bo)
113
114
{
114
115
if (len < 8 ) return FALSE ;
115
116
116
117
if (memcmp (data, " II" , 2 ) == 0 )
117
118
{
118
- * bo = TIFF_BYTE_ORDER_INTEL;
119
+ bo = TIFF_BYTE_ORDER_INTEL;
119
120
}
120
121
else if (memcmp (data, " MM" , 2 ) == 0 )
121
122
{
122
- * bo = TIFF_BYTE_ORDER_MOTOROLA;
123
+ bo = TIFF_BYTE_ORDER_MOTOROLA;
123
124
}
124
125
else
125
126
{
126
127
return FALSE ;
127
128
}
128
129
129
- if (tiff_byte_get_int16 (data + 2 , * bo) != 0x002A )
130
+ if (tiff_byte_get_int16 (data + 2 , bo) != 0x002A )
130
131
{
131
132
return FALSE ;
132
133
}
133
134
134
- * offset = tiff_byte_get_int32 (data + 4 , * bo);
135
+ offset = tiff_byte_get_int32 (data + 4 , bo);
135
136
136
- return (* offset < len) ;
137
+ return offset < len;
137
138
}
138
139
139
- using FuncParseIFDEntry = gint (*)(const guchar *, guint, guint, TiffByteOrder, gpointer);
140
-
140
+ using FuncParseIFDEntry = std::function<gint(const guchar *, guint, TiffByteOrder)>;
141
141
142
142
static gint tiff_parse_IFD_table (const guchar *tiff, guint offset,
143
143
guint size, TiffByteOrder bo,
144
- guint *next_offset ,
145
- FuncParseIFDEntry parse_entry, gpointer data )
144
+ const FuncParseIFDEntry &parse_entry ,
145
+ guint *next_offset = nullptr )
146
146
{
147
- guint count;
148
- guint i;
149
- guint next;
150
-
151
-
152
147
/* We should be able to read number of entries in IFD0) */
153
148
if (size < offset + 2 ) return -1 ;
154
149
155
- count = tiff_byte_get_int16 (tiff + offset, bo);
150
+ guint count = tiff_byte_get_int16 (tiff + offset, bo);
156
151
offset += 2 ;
157
152
/* Entries and next IFD offset must be readable */
158
153
if (size < offset + count * TIFF_TIFD_SIZE + 4 ) return -1 ;
159
154
160
- for (i = 0 ; i < count; i++)
155
+ for (guint i = 0 ; i < count; i++)
161
156
{
162
- parse_entry (tiff, offset + (i * TIFF_TIFD_SIZE), size, bo, data );
157
+ parse_entry (tiff, offset + (i * TIFF_TIFD_SIZE), bo );
163
158
}
164
159
165
- next = tiff_byte_get_int32 (tiff + offset + (count * TIFF_TIFD_SIZE), bo);
166
- if (next_offset) *next_offset = next;
160
+ if (next_offset)
161
+ {
162
+ *next_offset = tiff_byte_get_int32 (tiff + offset + (count * TIFF_TIFD_SIZE), bo);
163
+ }
167
164
168
165
return 0 ;
169
166
}
170
167
171
168
static gint mpo_parse_Index_IFD_entry (const guchar *tiff, guint offset,
172
- guint size, TiffByteOrder bo,
173
- gpointer data )
169
+ guint size, TiffByteOrder bo,
170
+ MPOData &mpo )
174
171
{
175
172
guint tag;
176
173
guint format;
@@ -179,8 +176,6 @@ static gint mpo_parse_Index_IFD_entry(const guchar *tiff, guint offset,
179
176
guint data_offset;
180
177
guint data_length;
181
178
182
- auto mpo = static_cast <MPOData *>(data);
183
-
184
179
tag = tiff_byte_get_int16 (tiff + offset + TIFF_TIFD_OFFSET_TAG, bo);
185
180
format = tiff_byte_get_int16 (tiff + offset + TIFF_TIFD_OFFSET_FORMAT, bo);
186
181
count = tiff_byte_get_int32 (tiff + offset + TIFF_TIFD_OFFSET_COUNT, bo);
@@ -189,68 +184,66 @@ static gint mpo_parse_Index_IFD_entry(const guchar *tiff, guint offset,
189
184
190
185
if (tag == 0xb000 )
191
186
{
192
- mpo-> version = data_val;
193
- DEBUG_1 (" mpo version %x" , mpo-> version );
187
+ mpo. version = data_val;
188
+ DEBUG_1 (" mpo version %x" , mpo. version );
194
189
}
195
190
else if (tag == 0xb001 )
196
191
{
197
- mpo-> num_images = data_val;
198
- DEBUG_1 (" num images %x" , mpo-> num_images );
192
+ mpo. num_images = data_val;
193
+ DEBUG_1 (" num images %x" , mpo. num_images );
199
194
}
200
195
else if (tag == 0xb002 )
201
196
{
202
- guint i;
203
197
data_offset = data_val;
204
198
data_length = count;
205
199
if (size < data_offset || size < data_offset + data_length)
206
200
{
207
201
return -1 ;
208
202
}
209
- if (count != mpo-> num_images * 16 )
203
+ if (count != mpo. num_images * 16 )
210
204
{
211
205
return -1 ;
212
206
}
213
207
214
- mpo-> images = g_new0 (MPOEntry, mpo-> num_images );
208
+ mpo. images = g_new0 (MPOEntry, mpo. num_images );
215
209
216
- for (i = 0 ; i < mpo->num_images ; i++) {
210
+ for (guint i = 0 ; i < mpo.num_images ; i++)
211
+ {
217
212
guint image_attr = tiff_byte_get_int32 (tiff + data_offset + (i * 16 ), bo);
218
- mpo-> images [i].type_code = image_attr & 0xffffff ;
219
- mpo-> images [i].representative = !!(image_attr & 0x20000000 );
220
- mpo-> images [i].dependent_child = !!(image_attr & 0x40000000 );
221
- mpo-> images [i].dependent_parent = !!(image_attr & 0x80000000 );
222
- mpo-> images [i].length = tiff_byte_get_int32 (tiff + data_offset + (i * 16 ) + 4 , bo);
223
- mpo-> images [i].offset = tiff_byte_get_int32 (tiff + data_offset + (i * 16 ) + 8 , bo);
224
- mpo-> images [i].dep1 = tiff_byte_get_int16 (tiff + data_offset + (i * 16 ) + 12 , bo);
225
- mpo-> images [i].dep2 = tiff_byte_get_int16 (tiff + data_offset + (i * 16 ) + 14 , bo);
213
+ mpo. images [i].type_code = image_attr & 0xffffff ;
214
+ mpo. images [i].representative = !!(image_attr & 0x20000000 );
215
+ mpo. images [i].dependent_child = !!(image_attr & 0x40000000 );
216
+ mpo. images [i].dependent_parent = !!(image_attr & 0x80000000 );
217
+ mpo. images [i].length = tiff_byte_get_int32 (tiff + data_offset + (i * 16 ) + 4 , bo);
218
+ mpo. images [i].offset = tiff_byte_get_int32 (tiff + data_offset + (i * 16 ) + 8 , bo);
219
+ mpo. images [i].dep1 = tiff_byte_get_int16 (tiff + data_offset + (i * 16 ) + 12 , bo);
220
+ mpo. images [i].dep2 = tiff_byte_get_int16 (tiff + data_offset + (i * 16 ) + 14 , bo);
226
221
227
222
if (i == 0 )
228
223
{
229
- mpo-> images [i].offset = 0 ;
224
+ mpo. images [i].offset = 0 ;
230
225
}
231
226
else
232
227
{
233
- mpo-> images [i].offset += mpo-> mpo_offset ;
228
+ mpo. images [i].offset += mpo. mpo_offset ;
234
229
}
235
230
236
- DEBUG_1 (" image %x %x %x" , image_attr, mpo-> images [i].length , mpo-> images [i].offset );
231
+ DEBUG_1 (" image %x %x %x" , image_attr, mpo. images [i].length , mpo. images [i].offset );
237
232
}
238
233
}
239
234
240
235
return 0 ;
241
236
}
242
237
243
238
static gint mpo_parse_Attributes_IFD_entry (const guchar *tiff, guint offset,
244
- guint, TiffByteOrder bo,
245
- gpointer data )
239
+ TiffByteOrder bo,
240
+ MPOEntry &mpe )
246
241
{
247
242
guint tag;
248
243
guint format;
249
244
guint count;
250
245
guint data_val;
251
246
252
- auto mpe = static_cast <MPOEntry *>(data);
253
-
254
247
tag = tiff_byte_get_int16 (tiff + offset + TIFF_TIFD_OFFSET_TAG, bo);
255
248
format = tiff_byte_get_int16 (tiff + offset + TIFF_TIFD_OFFSET_FORMAT, bo);
256
249
count = tiff_byte_get_int32 (tiff + offset + TIFF_TIFD_OFFSET_COUNT, bo);
@@ -260,33 +253,34 @@ static gint mpo_parse_Attributes_IFD_entry(const guchar *tiff, guint offset,
260
253
switch (tag)
261
254
{
262
255
case 0xb000 :
263
- mpe-> MPFVersion = data_val;
256
+ mpe. MPFVersion = data_val;
264
257
DEBUG_1 (" mpo version %x" , data_val);
265
258
break ;
266
259
case 0xb101 :
267
- mpe-> MPIndividualNum = data_val;
268
- DEBUG_1 (" Individual Image Number %x" , mpe-> MPIndividualNum );
260
+ mpe. MPIndividualNum = data_val;
261
+ DEBUG_1 (" Individual Image Number %x" , mpe. MPIndividualNum );
269
262
break ;
270
263
case 0xb201 :
271
- mpe-> PanOrientation = data_val;
264
+ mpe. PanOrientation = data_val;
272
265
break ;
273
- /* *
274
-
275
- @FIXME
276
- Panorama Scanning Orientation PanOrientation 45569 B201 LONG 1 \n
277
- Panorama Horizontal Overlap PanOverlap_H 45570 B202 RATIONAL 1 \n
278
- Panorama Vertical Overlap PanOverlap_V 45571 B203 RATIONAL 1 \n
279
- Base Viewpoint Number BaseViewpointNum 45572 B204 LONG 1 \n
280
- Convergence Angle ConvergenceAngle 45573 B205 SRATIONAL 1 \n
281
- Baseline Length BaselineLength 45574 B206 RATIONAL 1 \n
282
- Divergence Angle VerticalDivergence 45575 B207 SRATIONAL 1 \n
283
- Horizontal Axis Distance AxisDistance_X 45576 B208 SRATIONAL 1 \n
284
- Vertical Axis Distance AxisDistance_Y 45577 B209 SRATIONAL 1 \n
285
- Collimation Axis Distance AxisDistance_Z 45578 B20A SRATIONAL 1 \n
286
- Yaw Angle YawAngle 45579 B20B SRATIONAL 1 \n
287
- Pitch Angle PitchAngle 45580 B20C SRATIONAL 1 \n
288
- Roll Angle RollAngle 45581 B20D
289
- */
266
+ /* *
267
+ @FIXME See section 5.2.4. MP Attribute IFD of
268
+ CIPA DC-007-Translation-2021 Multi-Picture Format
269
+ https://www.cipa.jp/std/documents/download_e.html?CIPA_DC-007-2021_E
270
+ Tag Name Field Name Tag ID (Dec/Hex) Type Count
271
+ Panorama Horizontal Overlap PanOverlap_H 45570 B202 RATIONAL 1
272
+ Panorama Vertical Overlap PanOverlap_V 45571 B203 RATIONAL 1
273
+ Base Viewpoint Number BaseViewpointNum 45572 B204 LONG 1
274
+ Convergence Angle ConvergenceAngle 45573 B205 SRATIONAL 1
275
+ Baseline Length BaselineLength 45574 B206 RATIONAL 1
276
+ Divergence Angle VerticalDivergence 45575 B207 SRATIONAL 1
277
+ Horizontal Axis Distance AxisDistance_X 45576 B208 SRATIONAL 1
278
+ Vertical Axis Distance AxisDistance_Y 45577 B209 SRATIONAL 1
279
+ Collimation Axis Distance AxisDistance_Z 45578 B20A SRATIONAL 1
280
+ Yaw Angle YawAngle 45579 B20B SRATIONAL 1
281
+ Pitch Angle PitchAngle 45580 B20C SRATIONAL 1
282
+ Roll Angle RollAngle 45581 B20D SRATIONAL 1
283
+ */
290
284
default :
291
285
break ;
292
286
}
@@ -298,66 +292,70 @@ MPOData *jpeg_get_mpo_data(const guchar *data, guint size)
298
292
{
299
293
guint seg_offset;
300
294
guint seg_size;
301
- if (jpeg_segment_find (data, size, JPEG_MARKER_APP2, " MPF\x00 " , 4 , &seg_offset, &seg_size) && seg_size >16 )
302
- {
303
- guint offset;
304
- guint next_offset = 0 ;
305
- TiffByteOrder bo;
306
- MPOData *mpo;
307
- guint i;
295
+ if (!jpeg_segment_find (data, size, JPEG_MARKER_APP2, " MPF\x00 " , 4 , &seg_offset, &seg_size) || seg_size <= 16 ) return nullptr ;
308
296
309
- DEBUG_1 (" mpo signature found at %x" , seg_offset);
310
- seg_offset += 4 ;
311
- seg_size -= 4 ;
297
+ DEBUG_1 (" mpo signature found at %x" , seg_offset);
298
+ seg_offset += 4 ;
299
+ seg_size -= 4 ;
312
300
313
- if (!tiff_directory_offset (data + seg_offset, seg_size, &offset, &bo)) return nullptr ;
301
+ guint offset;
302
+ TiffByteOrder bo;
303
+ if (!tiff_directory_offset (data + seg_offset, seg_size, offset, bo)) return nullptr ;
314
304
315
- mpo = g_new0 (MPOData, 1 );
316
- mpo->mpo_offset = seg_offset;
305
+ auto * mpo = g_new0 (MPOData, 1 );
306
+ mpo->mpo_offset = seg_offset;
317
307
318
- tiff_parse_IFD_table (data + seg_offset, offset , seg_size, bo, &next_offset, mpo_parse_Index_IFD_entry, mpo);
319
- if (!mpo->images ) mpo->num_images = 0 ;
308
+ guint next_offset = 0 ;
309
+ const auto parse_mpo_data = [seg_size, mpo](const guchar *tiff, guint offset, TiffByteOrder bo)
310
+ {
311
+ return mpo_parse_Index_IFD_entry (tiff, offset, seg_size, bo, *mpo);
312
+ };
313
+ tiff_parse_IFD_table (data + seg_offset, offset, seg_size, bo, parse_mpo_data, &next_offset);
320
314
315
+ if (!mpo->images ) mpo->num_images = 0 ;
321
316
322
- for (i = 0 ; i < mpo->num_images ; i++)
317
+ for (guint i = 0 ; i < mpo->num_images ; i++)
318
+ {
319
+ if (mpo->images [i].offset + mpo->images [i].length > size)
323
320
{
324
- if (mpo->images [i].offset + mpo->images [i].length > size)
325
- {
326
- mpo->num_images = i;
327
- DEBUG_1 (" MPO file truncated to %u valid images, %u %u" , i, mpo->images [i].offset + mpo->images [i].length , size);
328
- break ;
329
- }
321
+ mpo->num_images = i;
322
+ DEBUG_1 (" MPO file truncated to %u valid images, %u %u" , i, mpo->images [i].offset + mpo->images [i].length , size);
323
+ break ;
330
324
}
325
+ }
331
326
332
- for (i = 0 ; i < mpo->num_images ; i++)
327
+ for (guint i = 0 ; i < mpo->num_images ; i++)
328
+ {
329
+ if (i == 0 )
333
330
{
334
- if (i == 0 )
331
+ offset = next_offset;
332
+ }
333
+ else
334
+ {
335
+ if (!jpeg_segment_find (data + mpo->images [i].offset , mpo->images [i].length , JPEG_MARKER_APP2, " MPF\x00 " , 4 , &seg_offset, &seg_size) || seg_size <=16 )
335
336
{
336
- offset = next_offset;
337
+ DEBUG_1 (" MPO image %u: MPO signature not found" , i);
338
+ continue ;
337
339
}
338
- else
339
- {
340
- if (!jpeg_segment_find (data + mpo->images [i].offset , mpo->images [i].length , JPEG_MARKER_APP2, " MPF\x00 " , 4 , &seg_offset, &seg_size) || seg_size <=16 )
341
- {
342
- DEBUG_1 (" MPO image %u: MPO signature not found" , i);
343
- continue ;
344
- }
345
-
346
- seg_offset += 4 ;
347
- seg_size -= 4 ;
348
- if (!tiff_directory_offset (data + mpo->images [i].offset + seg_offset, seg_size, &offset, &bo))
349
- {
350
- DEBUG_1 (" MPO image %u: invalid directory offset" , i);
351
- continue ;
352
- }
353
340
341
+ seg_offset += 4 ;
342
+ seg_size -= 4 ;
343
+ if (!tiff_directory_offset (data + mpo->images [i].offset + seg_offset, seg_size, offset, bo))
344
+ {
345
+ DEBUG_1 (" MPO image %u: invalid directory offset" , i);
346
+ continue ;
354
347
}
355
- tiff_parse_IFD_table (data + mpo-> images [i]. offset + seg_offset, offset , seg_size, bo, nullptr , mpo_parse_Attributes_IFD_entry, &mpo-> images [i]);
348
+
356
349
}
357
350
358
- return mpo;
351
+ const auto parse_mpo_entry = [&mpe = mpo->images [i]](const guchar *tiff, guint offset, TiffByteOrder bo)
352
+ {
353
+ return mpo_parse_Attributes_IFD_entry (tiff, offset, bo, mpe);
354
+ };
355
+ tiff_parse_IFD_table (data + mpo->images [i].offset + seg_offset, offset, seg_size, bo, parse_mpo_entry);
359
356
}
360
- return nullptr ;
357
+
358
+ return mpo;
361
359
}
362
360
363
361
void jpeg_mpo_data_free (MPOData *mpo)
0 commit comments