⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 exif.c

📁 Gqview,Linux下基于GTK+库写成的轻量级而能丰富的图像浏览程序。
💻 C
📖 第 1 页 / 共 3 页
字号:
				}			}		else			{			spacer = "";			}		g_string_append_printf(string, "%s%02x", spacer, ((char *)data)[i]);		}	if (i >= UNDEFINED_TEXT_BYTE_COUNT) g_string_append_printf(string, " (%d bytes)", ne);	return string;}gchar *exif_text_list_find_value(ExifTextList *list, guint value){	gchar *result = NULL;	gint i;	i = 0;	while (!result && list[i].value >= 0)		{		if (value == list[i].value) result = g_strdup(_(list[i].description));		i++;		}	if (!result) result = g_strdup_printf("%d (%s)", value, _("unknown"));	return result;}/* *------------------------------------------------------------------- * byte size utils *------------------------------------------------------------------- */guint16 exif_byte_get_int16(unsigned char *f, ExifByteOrder bo){	if (bo == EXIF_BYTE_ORDER_INTEL)		return GUINT16_FROM_LE(*(guint16*)f);	else		return GUINT16_FROM_BE(*(guint16*)f);}guint32 exif_byte_get_int32(unsigned char *f, ExifByteOrder bo){	if (bo == EXIF_BYTE_ORDER_INTEL)		return GUINT32_FROM_LE(*(guint32*)f);	else		return GUINT32_FROM_BE(*(guint32*)f);}guint16 exif_byte_swab_int16(guint16 n, ExifByteOrder bo){#if G_BYTE_ORDER == G_LITTLE_ENDIAN	if (bo == EXIF_BYTE_ORDER_MOTOROLA)#else	if (bo == EXIF_BYTE_ORDER_INTEL)#endif		return GUINT16_SWAP_LE_BE(n);	else		return n;}guint32 exif_byte_swab_int32(guint32 n, ExifByteOrder bo){#if G_BYTE_ORDER == G_LITTLE_ENDIAN	if (bo == EXIF_BYTE_ORDER_MOTOROLA)#else	if (bo == EXIF_BYTE_ORDER_INTEL)#endif		return GUINT32_SWAP_LE_BE(n);	else		return n;}/* *------------------------------------------------------------------- * IFD utils *------------------------------------------------------------------- */static const ExifMarker *exif_marker_from_tag(guint16 tag, const ExifMarker *list){	gint i = 0;	if (!list) return NULL;	while (list[i].tag != 0 && list[i].tag != tag)		{		i++;		}	return (list[i].tag == 0 ? NULL : &list[i]);}static void rational_from_data(ExifRational *r, void *src, ExifByteOrder bo){	r->num = exif_byte_get_int32(src, bo);	r->den = exif_byte_get_int32(src + sizeof(guint32), bo);}/* src_format and item->format must be compatible * and not overrun src or item->data. */void exif_item_copy_data(ExifItem *item, void *src, guint len,			 ExifFormatType src_format, ExifByteOrder bo){	gint bs;	gint ne;	gpointer dest;	gint i;	bs = ExifFormatList[item->format].size;	ne = item->elements;	dest = item->data;	if (!dest ||	    ExifFormatList[src_format].size * ne > len)		{		printf("exif tag %s data size mismatch\n", exif_item_get_tag_name(item));		return;		}	switch (item->format)		{		case EXIF_FORMAT_UNKNOWN:			break;		case EXIF_FORMAT_BYTE_UNSIGNED:		case EXIF_FORMAT_BYTE:		case EXIF_FORMAT_UNDEFINED:			memcpy(dest, src, len);			break;		case EXIF_FORMAT_STRING:			memcpy(dest, src, len);			/* string is NULL terminated, make sure this is true */			if (((char *)dest)[len - 1] != '\0') ((char *)dest)[len - 1] = '\0';			break;		case EXIF_FORMAT_SHORT_UNSIGNED:		case EXIF_FORMAT_SHORT:			for (i = 0; i < ne; i++)				{				((guint16 *)dest)[i] = exif_byte_get_int16(src + i * bs, bo);				}			break;		case EXIF_FORMAT_LONG_UNSIGNED:		case EXIF_FORMAT_LONG:			if (src_format == EXIF_FORMAT_SHORT_UNSIGNED ||			    src_format == EXIF_FORMAT_SHORT)				{				/* a short fits into a long, so allow it */				gint ss;				ss = ExifFormatList[src_format].size;				for (i = 0; i < ne; i++)					{					((gint32 *)dest)[i] =						(gint32)exif_byte_get_int16(src + i * ss, bo);					}				}			else				{				for (i = 0; i < ne; i++)					{					((gint32 *)dest)[i] =						exif_byte_get_int32(src + i * bs, bo);					}				}			break;		case EXIF_FORMAT_RATIONAL_UNSIGNED:		case EXIF_FORMAT_RATIONAL:			for (i = 0; i < ne; i++)				{				rational_from_data(&((ExifRational *)dest)[i], src + i * bs, bo);				}			break;		case EXIF_FORMAT_FLOAT:			for (i = 0; i < ne; i++)				{				((float *)dest)[i] = exif_byte_get_int32(src + i * bs, bo);				}			break;		case EXIF_FORMAT_DOUBLE:			for (i = 0; i < ne; i++)				{				ExifRational r;				rational_from_data(&r, src + i * bs, bo);				if (r.den) ((double *)dest)[i] = (double)r.num / r.den;				}			break;		}}static gint exif_parse_IFD_entry(ExifData *exif, unsigned char *tiff, guint offset,				 guint size, ExifByteOrder bo,				 gint level,				 const ExifMarker *list){	guint tag;	guint format;	guint count;	guint data_val;	guint data_offset;	guint data_length;	const ExifMarker *marker;	ExifItem *item;	tag = exif_byte_get_int16(tiff + offset + EXIF_TIFD_OFFSET_TAG, bo);	format = exif_byte_get_int16(tiff + offset + EXIF_TIFD_OFFSET_FORMAT, bo);	count = exif_byte_get_int32(tiff + offset + EXIF_TIFD_OFFSET_COUNT, bo);	data_val = exif_byte_get_int32(tiff + offset + EXIF_TIFD_OFFSET_DATA, bo);	/* Check tag type. If it does not match, either the format is wrong,	 * either it is a unknown tag; so it is not really an error.	 */	marker = exif_marker_from_tag(tag, list);	if (!marker)		{		if (format >= EXIF_FORMAT_COUNT)			{			printf("warning: exif tag 0x%4x has invalid format %d\n", tag, format);			return 0;			}		/* allow non recognized tags to be displayed */		marker = &ExifUnknownMarkersList[format];		}	if (marker->format != format)		{		/* Some cameras got mixed up signed/unsigned_rational		 * eg KODAK DC4800 on object_distance tag		 *		 * FIXME: what exactly is this test trying to do?		 * ok, so this test is to allow the case of swapped signed/unsigned mismatch to leak through?		 */		if (!(marker->format == EXIF_FORMAT_RATIONAL_UNSIGNED && format == EXIF_FORMAT_RATIONAL) &&		    !(marker->format == EXIF_FORMAT_RATIONAL && format == EXIF_FORMAT_RATIONAL_UNSIGNED) &&			/* short fits into a long so allow this mismatch			 * as well (some tags allowed to be unsigned short _or_ unsigned long)			 */		    !(marker->format == EXIF_FORMAT_LONG_UNSIGNED && format == EXIF_FORMAT_SHORT_UNSIGNED) )			{			if (format < EXIF_FORMAT_COUNT)				{				printf("warning: exif tag %s format mismatch, found %s exif spec requests %s\n",					marker->key, ExifFormatList[format].short_name,					ExifFormatList[marker->format].short_name);				}			else				{				printf("warning: exif tag %s format mismatch, found unknown id %d exif spec requests %d (%s)\n",					marker->key, format, marker->format,					ExifFormatList[marker->format].short_name);				}			return 0;			}		}	/* Where is the data, is it available?	 */	if (marker->components > 0 && marker->components != count)		{		printf("warning: exif tag %s has %d elements, exif spec requests %d\n",			marker->key, count, marker->components);		}	data_length = ExifFormatList[marker->format].size * count;	if (data_length > 4)		{		data_offset = data_val;		if (size < data_offset + data_length)			{			printf("warning: exif tag %s data will overrun end of file, ignored.\n", marker->key);			return -1;			}		}	else		{		data_offset = offset + EXIF_TIFD_OFFSET_DATA;		}	item = exif_item_new(marker->format, tag, count, marker);	exif_item_copy_data(item, tiff + data_offset, data_length, format, bo);	exif->items = g_list_prepend(exif->items, item);	if (list == ExifKnownMarkersList)		{		switch (item->tag)			{			case TAG_EXIFOFFSET:				exif_parse_IFD_table(exif, tiff, data_val, size, bo, level + 1, list);				break;			case TAG_EXIFMAKERNOTE:				format_exif_makernote_parse(exif, tiff, data_val, size, bo);				break;			}		}	return 0;}gint exif_parse_IFD_table(ExifData *exif,			  unsigned char *tiff, guint offset,			  guint size, ExifByteOrder bo,			  gint level,			  const ExifMarker *list){	guint count;	guint i;	/* limit damage from infinite loops */	if (level > EXIF_TIFF_MAX_LEVELS) return -1;	/* We should be able to read number of entries in IFD0) */	if (size < offset + 2) return -1;	count = exif_byte_get_int16(tiff + offset, bo);	offset += 2;	/* Entries and next IFD offset must be readable */	if (size < offset + count * EXIF_TIFD_SIZE + 4) return -1;	for (i = 0; i < count; i++)		{		exif_parse_IFD_entry(exif, tiff, offset + i * EXIF_TIFD_SIZE, size, bo, level, list);		}	return 0;}/* *------------------------------------------------------------------- * file formats *------------------------------------------------------------------- */gint exif_tiff_directory_offset(unsigned char *data, const guint len,				guint *offset, ExifByteOrder *bo){	if (len < 8) return FALSE;	if (memcmp(data, "II", 2) == 0)		{		*bo = EXIF_BYTE_ORDER_INTEL;		}	else if (memcmp(data, "MM", 2) == 0)		{		*bo = EXIF_BYTE_ORDER_MOTOROLA;		}	else		{		return FALSE;		}	if (exif_byte_get_int16(data + 2, *bo) != 0x002A)		{		return FALSE;		}	*offset = exif_byte_get_int32(data + 4, *bo);	return (*offset < len);}gint exif_tiff_parse(ExifData *exif, unsigned char *tiff, guint size, ExifMarker *list){	ExifByteOrder bo;	guint offset;	if (!exif_tiff_directory_offset(tiff, size, &offset, &bo)) return -1;	return exif_parse_IFD_table(exif, tiff, offset, size, bo, 0, list);}/* *------------------------------------------------------------------- * jpeg marker utils *------------------------------------------------------------------- */#define MARKER_UNKNOWN		0x00#define MARKER_SOI		0xD8#define MARKER_APP1		0xE1static gint jpeg_get_marker_size(unsigned char *data){	/* Size is always in Motorola byte order */	return exif_byte_get_int16(data + 2, EXIF_BYTE_ORDER_MOTOROLA);}static gint jpeg_goto_next_marker(unsigned char **data, gint *size, gint *marker){	gint marker_size = 2;	*marker = MARKER_UNKNOWN;	/* It is safe to access the marker and its size since we have checked	 * the SOI and this function guaranties the whole next marker is	 * available	 */	if (*(*data + 1) != MARKER_SOI)		{		marker_size += jpeg_get_marker_size(*data);		}	*size -= marker_size;	/* size should be at least 4, so we can read the marker and its size	 * and check data are actually available	 */	if (*size < 4) return -1;	/* Jump to the next marker and be sure it begins with 0xFF	 */	*data += marker_size;	if (**data != 0xFF) return -1;	if (jpeg_get_marker_size(*data) + 2 > *size) return -1;	*marker = *(*data + 1);	return 0;}static gint exif_parse_JPEG(ExifData *exif, unsigned char *data, guint size, ExifMarker *list){	guint marker;	guint marker_size;	if (size < 4 || *data != 0xFF || *(data + 1) != MARKER_SOI)		{		return -2;		}	do {		if (jpeg_goto_next_marker(&data, &size, &marker) == -1)			{			break;			}	} while (marker != MARKER_APP1);	if (marker != MARKER_APP1)		{		return -2;		}	marker_size = jpeg_get_marker_size(data) - 2;			if (marker_size < 6 || memcmp(data + 4, "Exif\x00\x00", 6) != 0)		{		return -2;		}	return exif_tiff_parse(exif, data + 10, marker_size - 6, list);}/* *------------------------------------------------------------------- * misc *------------------------------------------------------------------- */static gint map_file(const gchar *path, void **mapping, int *size){	int fd;	struct stat fs;	if ((fd = open(path, O_RDONLY)) == -1)		{		perror(path);		return -1;		}	if (fstat(fd, &fs) == -1)		{		perror(path);		close(fd);		return -1;		}	*size = fs.st_size;	if ((*mapping = mmap(0, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0)) == MAP_FAILED)		{		perror(path);		close(fd);		return -1;		}	close(fd);	return 0;}static gint unmap_file(void *mapping, int size){	if (munmap(mapping, size) == -1)		{		perror("munmap");		return -1;		}	return 0;}void exif_free(ExifData *exif){	GList *work;	if (!exif) return;	work = exif->items;	while (work)		{		ExifItem *item = work->data;		work = work->next;		exif_item_free(item);		}	g_list_free(exif->items);	g_free(exif);}ExifData *exif_read(const gchar *path){	ExifData *exif;	void *f;	int size, res;	gchar *pathl;	if (!path) return NULL;	pathl = path_from_utf8(path);	if (map_file(pathl, &f, &size) == -1)		{		g_free(pathl);		return NULL;		}	g_free(pathl);	exif = g_new0(ExifData, 1);	exif->items = NULL;	if ((res = exif_parse_JPEG(exif, (unsigned char *)f, size, ExifKnownMarkersList)) == -2)		{		res = exif_tiff_parse(exif, (unsigned char *)f, size, ExifKnownMarkersList);		}	if (res != 0)		{		guint32 offset = 0;		

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -