Skip to content

Commit f7c23e1

Browse files
committed
gpujpeg_decoder_get_image_info2: add orientation
and more in general metadata (now just the orientation) - print it with gpujpegtool - add struct for that (value def/interpretation as in SPIFF)
1 parent c0f8ffa commit f7c23e1

File tree

8 files changed

+74
-31
lines changed

8 files changed

+74
-31
lines changed

libgpujpeg/gpujpeg_common.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,9 @@ gpujpeg_pixel_format_is_planar(enum gpujpeg_pixel_format pixel_format);
686686
GPUJPEG_API void
687687
gpujpeg_device_reset(void);
688688

689+
GPUJPEG_API const char*
690+
gpujpeg_orientation_get_name(struct gpujpeg_orientation orientation);
691+
689692
#ifdef __cplusplus
690693
}
691694
#endif

libgpujpeg/gpujpeg_decoder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ struct gpujpeg_image_info {
273273
int segment_count;
274274
enum gpujpeg_header_type header_type;
275275
const char* comment; ///< NULL-terminated COM marker, ptr to img buffer
276+
struct gpujpeg_image_metadata metadata;
276277
};
277278
char reserved[512]; // for further extensions
278279
};

libgpujpeg/gpujpeg_type.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,17 @@ struct gpujpeg_component_sampling_factor
142142
uint8_t vertical;
143143
};
144144

145+
struct gpujpeg_orientation /// as defined in SPIFF
146+
{
147+
unsigned rotation : 2; ///< in multiples of 90° clock-wise
148+
unsigned flip : 1; ///< 1 - left-to-right orientation flipped after rotation applied
149+
};
150+
151+
struct gpujpeg_image_metadata
152+
{
153+
struct gpujpeg_orientation orientation;
154+
};
155+
145156
#ifdef __cplusplus
146157
}
147158
#endif

src/gpujpeg_common.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2368,4 +2368,20 @@ gpujpeg_header_type_get_name(enum gpujpeg_header_type header_type) {
23682368
abort();
23692369
}
23702370

2371+
GPUJPEG_API const char*
2372+
gpujpeg_orientation_get_name(struct gpujpeg_orientation orientation)
2373+
{
2374+
switch (orientation.rotation << 1 | orientation.flip) {
2375+
case 0<<1 | 0: return "normal";
2376+
case 0<<1 | 1: return "mirror horizontal";
2377+
case 1<<1 | 0: return "rotated CW 90 deg";
2378+
case 1<<1 | 1: return "rotated CW 90 and mirrored horizontal";
2379+
case 2<<1 | 0: return "rotated 180 deg";
2380+
case 2<<1 | 1: return "flipped vertical";
2381+
case 3<<1 | 0: return "rotated CW 270 deg";
2382+
case 3<<1 | 1: return "rotated CW 270 deg and mirrored horizontal";
2383+
}
2384+
abort();
2385+
}
2386+
23712387
/* vi: set expandtab sw=4 : */

src/gpujpeg_exif.c

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ const struct exif_tiff_tag_info_t {
144144
// misc constants
145145
enum {
146146
ETIFF_CENTER = 1,
147+
ETIFF_ORIENTATION_VERTICAL = 1,
147148
ETIFF_SRGB = 1,
148149
ETIFF_INCHES = 2,
149150
NEXT_IFD_PTR_SZ = 4,
@@ -324,7 +325,7 @@ gpujpeg_write_0th(struct gpujpeg_writer* writer, const uint8_t* start,
324325
struct tm buf;
325326
(void) strftime(date_time, sizeof date_time, "%Y:%m:%d %H:%M:%S", localtime_s(&now, &buf));
326327
struct tag_value tags[] = {
327-
{ETIFF_ORIENTATION, {.uvalue = (uint32_t[]){EXIF_ORIENTATION_HORIZONTAL}}},
328+
{ETIFF_ORIENTATION, {.uvalue = (uint32_t[]){ETIFF_ORIENTATION_VERTICAL}}},
328329
{ETIFF_XRESOLUTION, {.uvalue = (uint32_t[]){DPI_DEFAULT, 1}} },
329330
{ETIFF_YRESOLUTION, {.uvalue = (uint32_t[]){DPI_DEFAULT, 1}} },
330331
{ETIFF_RESOLUTION_UNIT, {.uvalue = (uint32_t[]){ETIFF_INCHES}} },
@@ -611,9 +612,31 @@ read_4byte_le(uint8_t** image) {
611612
return ret;
612613
}
613614

615+
static void
616+
exif_orieintation_to_metadata(unsigned val, struct gpujpeg_image_metadata* parsed)
617+
{
618+
if (val == 0 || val > 8) {
619+
WARN_MSG(MOD_NAME "Flawed orientation value %d! Should be 1-8...\n", val);
620+
return;
621+
}
622+
// clang-format off
623+
struct gpujpeg_orientation map[] = {
624+
{0, 0}, // 1 = The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side.
625+
{0, 1}, // 2 = The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side.
626+
{2, 0}, // 3 = The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side.
627+
{2, 1}, // 4 = The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side.
628+
{1, 1}, // 5 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual top.
629+
{1, 0}, // 6 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual top.
630+
{3, 1}, // 7 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom.
631+
{3, 0}, // 8 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom.
632+
};
633+
// clang-format on
634+
parsed->orientation = map[val - 1];
635+
}
636+
614637
static void
615638
read_0th_ifd(uint8_t** image, const uint8_t* image_end, int verbose, uint16_t (*read_2byte)(uint8_t**),
616-
uint32_t (*read_4byte)(uint8_t**), struct gpujpeg_exif_parameters* parsed)
639+
uint32_t (*read_4byte)(uint8_t**), struct gpujpeg_image_metadata* parsed)
617640
{
618641
if ( *image + 2 > image_end ) {
619642
WARN_MSG("Unexpected end of file!\n");
@@ -646,7 +669,7 @@ read_0th_ifd(uint8_t** image, const uint8_t* image_end, int verbose, uint16_t (*
646669
DEBUG_MSG(verbose, MOD_NAME "Found IFD0 tag %s (%#x) type %s: count=%u, %s=%#x\n", exif_tiff_tag_info[tag].name,
647670
tag_id, type_name, count, count * size <= 4 ? "value" : "offset", val);
648671
if ( tag == ETIFF_ORIENTATION ) {
649-
parsed->orientation = val;
672+
exif_orieintation_to_metadata(val, parsed);
650673
}
651674
}
652675

@@ -663,7 +686,7 @@ read_0th_ifd(uint8_t** image, const uint8_t* image_end, int verbose, uint16_t (*
663686
* JPEG Orientation is checked and of not horizontal, warning is issued.
664687
*/
665688
void
666-
gpujpeg_exif_parse(uint8_t** image, const uint8_t* image_end, int verbose, struct gpujpeg_exif_parameters* parsed)
689+
gpujpeg_exif_parse(uint8_t** image, const uint8_t* image_end, int verbose, struct gpujpeg_image_metadata* metadata)
667690
{
668691
#define HANDLE_ERROR(...) \
669692
WARN_MSG(__VA_ARGS__); \
@@ -713,7 +736,7 @@ gpujpeg_exif_parse(uint8_t** image, const uint8_t* image_end, int verbose, struc
713736

714737
uint32_t offset = read_4byte(image); // 0th IFD offset
715738
*image = base + offset;
716-
read_0th_ifd(image, image_end, verbose, read_2byte, read_4byte, parsed);
739+
read_0th_ifd(image, image_end, verbose, read_2byte, read_4byte, metadata);
717740

718741
*image = image_start + length;
719742
#undef HANDLE_ERROR

src/gpujpeg_exif.h

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,11 @@
3434
#include <stdint.h>
3535

3636
struct gpujpeg_exif_tags;
37+
struct gpujpeg_image_metadata;
3738
struct gpujpeg_image_parameters;
3839
struct gpujpeg_parameters;
3940
struct gpujpeg_writer;
4041

41-
enum {
42-
EXIF_ORIENTATION_HORIZONTAL = 1, // normal
43-
};
44-
4542
void
4643
gpujpeg_writer_write_exif(struct gpujpeg_writer* writer, const struct gpujpeg_parameters* param,
4744
const struct gpujpeg_image_parameters* param_image,
@@ -52,12 +49,7 @@ gpujpeg_exif_add_tag(struct gpujpeg_exif_tags** exif_tags, const char *cfg);
5249
void
5350
gpujpeg_exif_tags_destroy(struct gpujpeg_exif_tags* exif_tags);
5451

55-
struct gpujpeg_exif_parameters
56-
{
57-
unsigned orientation; ///< EXIF_ORIENTATION_HORIZONTAL or a different value
58-
};
59-
6052
void
61-
gpujpeg_exif_parse(uint8_t** image, const uint8_t* image_end, int verbose, struct gpujpeg_exif_parameters* parsed);
53+
gpujpeg_exif_parse(uint8_t** image, const uint8_t* image_end, int verbose, struct gpujpeg_image_metadata* metadata);
6254

6355
#endif // defined GPUJPEG_EXIF_H_6755D546_2A90_46DF_9ECA_22F575C3E7E3

src/gpujpeg_reader.c

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ struct gpujpeg_reader
9494
enum gpujpeg_color_space header_color_space;
9595
enum gpujpeg_header_type header_type;
9696
bool in_spiff;
97-
struct gpujpeg_exif_parameters exif_metadata;
97+
struct gpujpeg_image_metadata metadata;
9898
const char *comment;
9999
};
100100

@@ -309,31 +309,28 @@ gpujpeg_reader_read_app0(uint8_t** image, const uint8_t* image_end, enum gpujpeg
309309
}
310310

311311
static void
312-
gpujpeg_reader_read_app1(uint8_t** image, const uint8_t* image_end, enum gpujpeg_header_type* header_type,
313-
enum gpujpeg_color_space* color_space, int verbose,
314-
struct gpujpeg_exif_parameters* exif_metadata)
312+
gpujpeg_reader_read_app1(uint8_t** image, struct gpujpeg_reader *reader)
315313
{
316-
if ( image_end - *image < 2 ) {
314+
if ( reader->image_end - *image < 2 ) {
317315
ERROR_MSG("Unexpected end of APP1 marker!\n");
318316
return;
319317
}
320318

321319
uint8_t type_tag[50];
322320
unsigned i = 0;
323321
const uint8_t* ptr = *image + 2;
324-
while ( *ptr != '\0' && ptr < image_end && i < sizeof type_tag - 1 ) {
322+
while ( *ptr != '\0' && ptr < reader->image_end && i < sizeof type_tag - 1 ) {
325323
type_tag[i++] = *ptr++;
326324
}
327325
type_tag[i] = '\0';
328326
if ( strcmp((char *) type_tag, "Exif") == 0 ) {
329-
*color_space = GPUJPEG_YCBCR_BT601_256LVLS;
330-
*header_type = GPUJPEG_HEADER_EXIF;
331-
memset(exif_metadata, 0, sizeof *exif_metadata);
332-
gpujpeg_exif_parse(image, image_end, verbose, exif_metadata);
327+
reader->header_color_space = GPUJPEG_YCBCR_BT601_256LVLS;
328+
reader->header_type = GPUJPEG_HEADER_EXIF;
329+
gpujpeg_exif_parse(image, reader->image_end, reader->param.verbose, &reader->metadata);
333330
return;
334331
}
335332
WARN_MSG("Skipping unsupported APP1 marker \"%s\"!\n", type_tag);
336-
gpujpeg_reader_skip_marker_content(image, image_end);
333+
gpujpeg_reader_skip_marker_content(image, reader->image_end);
337334
}
338335

339336
/**
@@ -1386,8 +1383,7 @@ gpujpeg_reader_read_common_markers(uint8_t** image, int marker, struct gpujpeg_r
13861383
}
13871384
break;
13881385
case GPUJPEG_MARKER_APP1:
1389-
gpujpeg_reader_read_app1(image, reader->image_end, &reader->header_type, &reader->header_color_space,
1390-
reader->param.verbose, &reader->exif_metadata);
1386+
gpujpeg_reader_read_app1(image, reader);
13911387
break;
13921388
case GPUJPEG_MARKER_APP8:
13931389
if ( gpujpeg_reader_read_app8(image, reader->image_end, &reader->header_color_space, &reader->header_type,
@@ -1642,9 +1638,8 @@ gpujpeg_reader_read_image(struct gpujpeg_decoder* decoder, uint8_t* image, size_
16421638
return -1;
16431639
}
16441640

1645-
if ( reader.header_type == GPUJPEG_HEADER_EXIF &&
1646-
reader.exif_metadata.orientation != EXIF_ORIENTATION_HORIZONTAL ) {
1647-
WARN_MSG("Exif %d not handled!\n", reader.exif_metadata.orientation);
1641+
if ( reader.metadata.orientation.rotation != 0 || reader.metadata.orientation.flip != 0 ) {
1642+
WARN_MSG("Orientation %s not handled!\n", gpujpeg_orientation_get_name(reader.metadata.orientation));
16481643
}
16491644

16501645
return 0;
@@ -1793,6 +1788,7 @@ gpujpeg_reader_get_image_info(uint8_t *image, size_t image_size, struct gpujpeg_
17931788
info->segment_count = segments;
17941789
info->header_type = reader.header_type;
17951790
info->comment = reader.comment;
1791+
info->metadata = reader.metadata;
17961792

17971793
if ( info->param.comp_count == 1 ) {
17981794
info->param_image.pixel_format = GPUJPEG_U8;

src/main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ static int print_image_info_jpeg(const char *filename, int verbose) {
206206
gpujpeg_subsampling_get_name(info.param.comp_count, info.param.sampling_factor));
207207
printf("interleaved: %d\n", info.param.interleaved);
208208
printf("header type: %s\n", gpujpeg_header_type_get_name(info.header_type));
209+
printf("orientation: %s\n", gpujpeg_orientation_get_name(info.metadata.orientation));
209210
if ( info.segment_count ) {
210211
printf("segment count: %d (DRI = %d)\n", info.segment_count, info.param.restart_interval);
211212
}

0 commit comments

Comments
 (0)