3434#include <stdlib.h>
3535#include <string.h>
3636
37+ #ifdef _WIN32
38+ #define strncasecmp _strnicmp
39+ #endif
40+
3741#include "compat/endian.h"
3842#include "gpujpeg_common_internal.h"
3943#include "gpujpeg_encoder_internal.h"
4044#include "gpujpeg_marker.h"
4145#include "gpujpeg_writer.h"
4246
4347enum exif_tag_type {
48+ ET_NONE = 0 ,
4449 ET_BYTE = 1 , ///< 8-bit unsigned integer
4550 ET_ASCII = 2 , ///< NULL-terminated ASCII string
4651 ET_SHORT = 3 , ///< 16-bit unsigned integer
@@ -49,13 +54,29 @@ enum exif_tag_type {
4954 ET_UNDEFINED = 7 , ///< An 8-bit byte that may take any value depending on the field definition.
5055 ET_SLONG = 9 , ///< 32-bit signed integer
5156 ET_SRATIONAL = 10 , ///< two SLONGs - first numerator, second denominator
57+ ET_END ,
58+ };
59+
60+ enum {
61+ T_NUMERIC = 1 << 0 ,
62+ T_UNSIGNED = 1 << 1 ,
5263};
5364
54- const struct exif_tag_type_info_t
65+ static const struct exif_tag_type_info_t
5566{
5667 unsigned size ;
57- } exif_tag_type_info [] = {[ET_BYTE ] = {1 }, [ET_ASCII ] = {0 }, [ET_SHORT ] = {2 }, [ET_LONG ] = {4 },
58- [ET_RATIONAL ] = {8 }, [ET_UNDEFINED ] = {4 }, [ET_SLONG ] = {4 }, [ET_SRATIONAL ] = {8 }};
68+ const char * name ;
69+ unsigned type_flags ;
70+ } exif_tag_type_info [] = {
71+ [ET_BYTE ] = {1 , "BYTE" , T_NUMERIC |T_UNSIGNED },
72+ [ET_ASCII ] = {0 , "ASCII" , 0 },
73+ [ET_SHORT ] = {2 , "SHORT" , T_NUMERIC |T_UNSIGNED },
74+ [ET_LONG ] = {4 , "LONG" , T_NUMERIC |T_UNSIGNED },
75+ [ET_RATIONAL ] = {8 , "RATIONAL" , T_UNSIGNED },
76+ [ET_UNDEFINED ] = {4 , "UNDEFINED" , },
77+ [ET_SLONG ] = {4 , "SLONG" , T_NUMERIC },
78+ [ET_SRATIONAL ] = {8 , "SRATIONAL" , 0 }
79+ };
5980
6081enum exif_tiff_tag {
6182 // 0th IFD TIFF Tags
@@ -100,6 +121,7 @@ enum {
100121 ETIFF_INCHES = 2 ,
101122 NEXT_IFD_PTR_SZ = 4 ,
102123 IFD_ITEM_SZ = 12 ,
124+ EEXIF_FIRST = 0x827A , // (Exposure time) first tag id of Exif Private Tags
103125};
104126
105127union value_u {
@@ -167,34 +189,33 @@ write_exif_emit_lt_4b_tag(struct gpujpeg_writer* writer, uint16_t tag, enum exif
167189}
168190
169191static void
170- write_exif_tag (struct gpujpeg_writer * writer , enum exif_tiff_tag tag , union value_u val , const uint8_t * start ,
171- uint8_t * * end )
192+ write_exif_tag (struct gpujpeg_writer * writer , enum exif_tag_type type , uint16_t tag_id , union value_u val ,
193+ const uint8_t * start , uint8_t * * end )
172194{
173-
174- const struct exif_tiff_tag_info_t * t = & exif_tiff_tag_info [tag ];
175- const unsigned size = exif_tag_type_info [t -> type ].size ;
195+ assert (type < ET_END );
196+ const unsigned size = exif_tag_type_info [type ].size ;
176197
177198 // size for string is computed
178- assert (size > 0 || t -> type == ET_ASCII );
199+ assert (size > 0 || type == ET_ASCII );
179200
180- if ( t -> type == ET_ASCII ) {
181- write_exif_emit_string_tag (writer , t -> id , val .csvalue , start , end );
201+ if ( type == ET_ASCII ) {
202+ write_exif_emit_string_tag (writer , tag_id , val .csvalue , start , end );
182203 return ;
183204 }
184- if ( t -> type == ET_UNDEFINED ) {
205+ if ( type == ET_UNDEFINED ) {
185206 assert (size == 4 );
186- gpujpeg_writer_emit_2byte (writer , t -> id );
187- gpujpeg_writer_emit_2byte (writer , t -> type );
207+ gpujpeg_writer_emit_2byte (writer , tag_id );
208+ gpujpeg_writer_emit_2byte (writer , type );
188209 gpujpeg_writer_emit_4byte (writer , 4 ); // count - we have all 4 B, unsure if defined otherwise for other
189210 memcpy (writer -> buffer_current , val .csvalue , 4 );
190211 writer -> buffer_current += 4 ;
191212 return ;
192213 }
193214 if (size <= 4 ) {
194- write_exif_emit_4bytes_tag (writer , t -> id , t -> type , size , val .uvalue );
215+ write_exif_emit_4bytes_tag (writer , tag_id , type , size , val .uvalue );
195216 return ;
196217 }
197- write_exif_emit_lt_4b_tag (writer , t -> id , t -> type , size , val , start , end );
218+ write_exif_emit_lt_4b_tag (writer , tag_id , type , size , val , start , end );
198219}
199220
200221struct tag_value
@@ -203,26 +224,67 @@ struct tag_value
203224 union value_u value ;
204225};
205226
227+ /// custom exif tag values
228+ struct custom_tag_value
229+ {
230+ uint16_t tag_id ;
231+ enum exif_tag_type type ;
232+ union value_u value ;
233+ };
234+ enum { CT_TIFF , CT_EXIF , CT_NUM };
235+ /// custom exif tags given by user
236+ struct gpujpeg_exif_tags {
237+ struct custom_exif_tags
238+ {
239+ struct custom_tag_value * vals ;
240+ size_t count ;
241+ } tags [CT_NUM ];
242+ };
243+
244+ static int
245+ ifd_sort (const void * a , const void * b )
246+ {
247+ const uint8_t * aa = a ;
248+ const uint8_t * bb = b ;
249+ int a_tag_id = aa [0 ] << 8 | aa [1 ];
250+ int b_tag_id = bb [0 ] << 8 | bb [1 ];
251+ return a_tag_id - b_tag_id ;
252+ }
253+
206254/**
207255 * @param tags array of tags, should be ordered awcending according to exif_tiff_tag_info_t.id
208256 */
209257static void
210258gpujpeg_write_ifd (struct gpujpeg_writer * writer , const uint8_t * start , size_t count ,
211- const struct tag_value tags [])
259+ const struct tag_value tags [], const struct custom_exif_tags * custom_tags )
212260{
213261 enum {
214262 EXIF_IFD_NUM_SZ = 2 ,
215263 };
216- uint8_t * end = writer -> buffer_current + EXIF_IFD_NUM_SZ + (count * IFD_ITEM_SZ ) + NEXT_IFD_PTR_SZ ;
217- gpujpeg_writer_emit_2byte (writer , count ); // IFD Item Count
264+ size_t count_all = count + custom_tags -> count ;
265+ uint8_t * end = writer -> buffer_current + EXIF_IFD_NUM_SZ + (count_all * IFD_ITEM_SZ ) + NEXT_IFD_PTR_SZ ;
266+ gpujpeg_writer_emit_2byte (writer , count_all ); // IFD Item Count
218267
268+ uint8_t * first_rec = writer -> buffer_current ;
269+ unsigned last_tag_id = 0 ;
219270 for ( unsigned i = 0 ; i < count ; ++ i ) {
220271 const struct tag_value * info = & tags [i ];
221272 union value_u value = info -> value ;
222273 if ( info -> tag == ETIFF_EXIF_IFD_POINTER ) {
223274 value .uvalue = end - start ;
224275 }
225- write_exif_tag (writer , info -> tag , value , start , & end );
276+ const struct exif_tiff_tag_info_t * t = & exif_tiff_tag_info [info -> tag ];
277+ assert (t -> id >= last_tag_id );
278+ last_tag_id = t -> id ;
279+ write_exif_tag (writer , t -> type , t -> id , value , start , & end );
280+ }
281+ if ( custom_tags != NULL ) { // add user custom tags
282+ for ( unsigned i = 0 ; i < custom_tags -> count ; ++ i ) {
283+ write_exif_tag (writer , custom_tags -> vals [i ].type , custom_tags -> vals [i ].tag_id , custom_tags -> vals [i ].value ,
284+ start , & end );
285+ }
286+ // ensure custom_tags are in-ordered
287+ qsort (first_rec , (writer -> buffer_current - first_rec ) / IFD_ITEM_SZ , IFD_ITEM_SZ , ifd_sort );
226288 }
227289 gpujpeg_writer_emit_4byte (writer , 0 ); // Next IFD Offset (none)
228290 writer -> buffer_current = end ; // jump after the section Value longer than 4Byte of 0th IFD
@@ -239,8 +301,10 @@ gpujpeg_write_0th(struct gpujpeg_encoder* encoder, const uint8_t* start)
239301 {ETIFF_YCBCR_POSITIONING , {.uvalue = ETIFF_CENTER }}, // center
240302 {ETIFF_EXIF_IFD_POINTER , {0 } }, // value later; should be last
241303 };
304+ const struct custom_exif_tags * custom_tags =
305+ encoder -> writer -> exif_tags != NULL ? & encoder -> writer -> exif_tags -> tags [CT_TIFF ] : NULL ;
242306
243- gpujpeg_write_ifd (encoder -> writer , start , ARR_SIZE (tags ), tags );
307+ gpujpeg_write_ifd (encoder -> writer , start , ARR_SIZE (tags ), tags , custom_tags );
244308}
245309
246310static void gpujpeg_write_exif_ifd (struct gpujpeg_encoder * encoder , const uint8_t * start )
@@ -253,7 +317,10 @@ static void gpujpeg_write_exif_ifd(struct gpujpeg_encoder* encoder, const uint8_
253317 {EEXIF_PIXEL_X_DIMENSION , {encoder -> coder .param_image .width } },
254318 {EEXIF_PIXEL_Y_DIMENSION , {encoder -> coder .param_image .height }},
255319 };
256- gpujpeg_write_ifd (encoder -> writer , start , ARR_SIZE (tags ), tags );
320+ const struct custom_exif_tags * custom_tags =
321+ encoder -> writer -> exif_tags != NULL ? & encoder -> writer -> exif_tags -> tags [CT_EXIF ] : NULL ;
322+
323+ gpujpeg_write_ifd (encoder -> writer , start , ARR_SIZE (tags ), tags , custom_tags );
257324}
258325
259326
@@ -300,3 +367,73 @@ gpujpeg_writer_write_exif(struct gpujpeg_encoder* encoder)
300367 length_p [1 ] = length ;
301368}
302369
370+ /**
371+ * add user-provided Exif tag
372+ */
373+ bool
374+ gpujpeg_exif_add_tag (struct gpujpeg_exif_tags * * exif_tags , const char * cfg )
375+ {
376+ char * endptr = (char * ) cfg ;
377+ long tag_id = strtol (cfg , & endptr , 0 );
378+ if (* endptr != ':' ) {
379+ ERROR_MSG ("Error parsing Exif tag ID or missing type!\n" );
380+ return false;
381+ }
382+ endptr += 1 ;
383+
384+ enum exif_tag_type type = ET_NONE ;
385+ for (unsigned i = ET_NONE + 1 ; i < ET_END ; ++ i ) {
386+ if ( exif_tag_type_info [i ].name == NULL ) { // unset/invalid type
387+ continue ;
388+ }
389+ size_t len = strlen (exif_tag_type_info [i ].name );
390+ if (strncasecmp (endptr , exif_tag_type_info [i ].name , len ) == 0 ) {
391+ type = i ;
392+ endptr += len ;
393+ break ;
394+ }
395+ }
396+ if (type == ET_NONE ) {
397+ ERROR_MSG ("Error parsing Exif tag type!\n" );
398+ return false;
399+ }
400+ if (* endptr != '=' ) {
401+ ERROR_MSG ("Error parsing Exif - missing value!\n" );
402+ return false;
403+ }
404+ unsigned numeric_unsigned = T_NUMERIC | T_UNSIGNED ;
405+ if ((exif_tag_type_info [type ].type_flags & numeric_unsigned ) != numeric_unsigned ) {
406+ ERROR_MSG ("Only unsigned integers currently supported!\n" );
407+ return false;
408+ }
409+ endptr += 1 ;
410+ unsigned long long val = strtoull (endptr , & endptr , 0 );
411+ if (* endptr != '\0' ) {
412+ ERROR_MSG ("Trainling data in Exif value!\n" );
413+ return false;
414+ }
415+
416+ if (* exif_tags == NULL ) {
417+ * exif_tags = calloc (1 , sizeof * * exif_tags );
418+ }
419+
420+ int table_idx = tag_id < EEXIF_FIRST ? CT_TIFF : CT_EXIF ;
421+ size_t new_size = (* exif_tags )-> tags [table_idx ].count += 1 ;
422+ (* exif_tags )-> tags [table_idx ].vals = realloc ((* exif_tags )-> tags [table_idx ].vals ,
423+ new_size * sizeof (* exif_tags )-> tags [table_idx ].vals [0 ]);
424+ (* exif_tags )-> tags [table_idx ].vals [new_size - 1 ].tag_id = tag_id ;
425+ (* exif_tags )-> tags [table_idx ].vals [new_size - 1 ].type = type ;
426+ (* exif_tags )-> tags [table_idx ].vals [new_size - 1 ].value .uvalue = val ;
427+
428+ return true;
429+ }
430+
431+ void
432+ gpujpeg_exif_tags_destroy (struct gpujpeg_exif_tags * exif_tags )
433+ {
434+ if (exif_tags == NULL ) {
435+ return ;
436+ }
437+ free (exif_tags -> tags [0 ].vals );
438+ free (exif_tags -> tags [1 ].vals );
439+ }
0 commit comments