view src/format_olympus.c @ 1783:b0352818977b

Allow to switch to fullscreen mode using LIRC. Imagine the following situation (which happened to me several times) : you want to see photos from your bed or your sofa so you launch geeqie and go to the right directory, then you take your remote control and sit comfortably far from your keyboard and mouse. And when you want to begin to watch photos, you realize you forgot to enable full screen! You have to stand up and to go until your computer and come back, whereas you could have done it with your remote control. Patch by Bernard Massot.
author zas_
date Tue, 05 Jan 2010 17:49:50 +0000
parents bc3f5c0432f6
children 956aab097ea7
line wrap: on
line source

/*
 * Geeqie
 * (C) 2005 John Ellis
 * Copyright (C) 2008 - 2009 The Geeqie Team
 *
 * This software is released under the GNU General Public License (GNU GPL).
 * Please read the included file COPYING for more information.
 * This software comes with no warranty of any kind, use at your own risk!
 */

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

#ifndef HAVE_EXIV2

#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include <glib.h>

#include "intl.h"

#include "main.h"
#include "format_olympus.h"
#include "format_raw.h"

#include "exif.h"


/*
 *-----------------------------------------------------------------------------
 * Raw ORF embedded jpeg extraction for Olympus
 *-----------------------------------------------------------------------------
 */

static guint olympus_tiff_table(guchar *data, const guint len, guint offset, ExifByteOrder bo,
				gint level,
				guint *image_offset, guint *exif_offset);


static void olympus_tiff_entry(guchar *data, const guint len, guint offset, ExifByteOrder bo,
			       gint level,
			       guint *image_offset, guint *exif_offset)
{
	guint tag;
	guint type;
	guint count;
	guint segment;
	guint seg_len;

	tag = exif_byte_get_int16(data + offset + EXIF_TIFD_OFFSET_TAG, bo);
	type = exif_byte_get_int16(data + offset + EXIF_TIFD_OFFSET_FORMAT, bo);
	count = exif_byte_get_int32(data + offset + EXIF_TIFD_OFFSET_COUNT, bo);

	/* so far, we only care about tags with type long */
	if (type != EXIF_FORMAT_LONG_UNSIGNED && type != EXIF_FORMAT_LONG) return;

	seg_len = ExifFormatList[type].size * count;
	if (seg_len > 4)
		{
		segment = exif_byte_get_int32(data + offset + EXIF_TIFD_OFFSET_DATA, bo);
		if (segment + seg_len > len) return;
		}
	else
		{
		segment = offset + EXIF_TIFD_OFFSET_DATA;
		}

	if (tag == 0x201)
		{
		/* start of embedded jpeg, not all olympus cameras embed a jpeg */
		*image_offset = exif_byte_get_int32(data + segment, bo);
		}

	if (tag == 0x8769)
		{
		/* This is the Exif info */
		*exif_offset = exif_byte_get_int32(data + segment, bo);
		}
}

static guint olympus_tiff_table(guchar *data, const guint len, guint offset, ExifByteOrder bo,
				gint level,
				guint *image_offset, guint *exif_offset)
{
	guint count;
	guint i;

	if (level > EXIF_TIFF_MAX_LEVELS) return 0;

	if (len < offset + 2) return FALSE;

	count = exif_byte_get_int16(data + offset, bo);
	offset += 2;
	if (len < offset + count * EXIF_TIFD_SIZE + 4) return 0;

	for (i = 0; i < count; i++)
		{
		olympus_tiff_entry(data, len, offset + i * EXIF_TIFD_SIZE, bo, level,
				   image_offset, exif_offset);
		}

	return exif_byte_get_int32(data + offset + count * EXIF_TIFD_SIZE, bo);
}

gboolean format_olympus_raw(guchar *data, const guint len,
			    guint *image_offset, guint *exif_offset)
{
	guint i_off = 0;
	guint e_off = 0;
	guint offset;
	gint level;

	if (len < 8) return FALSE;

	/* these are in tiff file format with a different magick header */
	if (memcmp(data, "IIR", 3) != 0) return FALSE;

	offset = exif_byte_get_int32(data + 4, EXIF_BYTE_ORDER_INTEL);

	level = 0;
	while (offset && level < EXIF_TIFF_MAX_LEVELS)
		{
		offset = olympus_tiff_table(data, len, offset, EXIF_BYTE_ORDER_INTEL, 0, &i_off, &e_off);
		level++;
		}

	if (i_off != 0 || e_off != 0)
		{
		if (image_offset) *image_offset = i_off;
		if (exif_offset) *exif_offset = e_off;
		return TRUE;
		}

	return FALSE;
}


/*
 *-----------------------------------------------------------------------------
 * EXIF Makernote for Olympus
 *-----------------------------------------------------------------------------
 */

static ExifTextList KonMinTagColorMode[]= {
	{ 0,	"natural" },
	{ 1,	"black and white" },
	{ 2,	"vivid" },
	{ 3,	"solarization" },
	{ 4,	"Adobe RGB" },
	EXIF_TEXT_LIST_END
};

static ExifTextList KonMinTagQuality[]= {
	{ 0,	"raw" },
	{ 1,	"super fine" },
	{ 2,	"find" },
	{ 3,	"standard" },
	{ 4,	"extra fine" },
	EXIF_TEXT_LIST_END
};

static ExifTextList OlympusTagJpegQuality[]= {
	{ 1,	"standard" },
	{ 2,	"high" },
	{ 3,	"super high" },
	EXIF_TEXT_LIST_END
};

static ExifTextList OlympusTagMacro[]= {
	{ 0,	"off" },
	{ 1,	"on" },
	{ 2,	"view" },
	{ 3,	"manual" },
	EXIF_TEXT_LIST_END
};

static ExifTextList OlympusTagFlashMode[]= {
	{ 0,	"auto" },
	{ 1,	"red-eye reduction" },
	{ 2,	"fill" },
	{ 3,	"off" },
	EXIF_TEXT_LIST_END
};

static ExifTextList OlympusTagFocusMode[]= {
	{ 0,	"auto" },
	{ 1,	"manual" },
	EXIF_TEXT_LIST_END
};

static ExifTextList OlympusTagSharpness[]= {
	{ 0,	"normal" },
	{ 1,	"hard" },
	{ 2,	"soft" },
	EXIF_TEXT_LIST_END
};

static ExifTextList OlympusTagContrast[]= {
	{ 0,	"hard" },
	{ 1,	"normal" },
	{ 2,	"soft" },
	EXIF_TEXT_LIST_END
};

#if 0
static ExifTextList OlympusTag[]= {
	{ ,	"" },
	{ ,	"" },
	EXIF_TEXT_LIST_END
};
#endif


static ExifMarker OlympusExifMarkersList[] = {
{ 0x0001, EXIF_FORMAT_LONG_UNSIGNED, -1, "Konica/MinoltaSettings", "Konica / Minolta settings", NULL },
{ 0x0003, EXIF_FORMAT_LONG_UNSIGNED, -1, "Konica/MinoltaSettings", "Konica / Minolta settings", NULL },
{ 0x0040, EXIF_FORMAT_LONG_UNSIGNED, -1, "CompressedImageSize",	"Compressed image size", NULL },
{ 0x0081, EXIF_FORMAT_LONG_UNSIGNED, 1,  "ThumbnailOffset",	"Thumbnail offset",	NULL },
{ 0x0088, EXIF_FORMAT_LONG_UNSIGNED, 1,  "ThumbnailOffset",	"Thumbnail offset",	NULL },
{ 0x0089, EXIF_FORMAT_LONG_UNSIGNED, 1,  "ThumbnailLength",	"Thumbnail length",	NULL },
{ 0x0101, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Konica/Minolta.ColorMode", "Color mode",	KonMinTagColorMode },
{ 0x0102, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Konica/Minolta.Quality", "Quality",		KonMinTagQuality },
{ 0x0103, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Konica/Minolta.Quality", "Quality",		KonMinTagQuality },
{ 0x0200, EXIF_FORMAT_LONG_UNSIGNED, 3,  "Olympus.SpecialMode",	"Special mode",		NULL },
{ 0x0201, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.JpegQuality",	"Jpeg quality",		OlympusTagJpegQuality },
{ 0x0202, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.Macro",	"Macro",		OlympusTagMacro },
{ 0x0204, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "Olympus.DigitalZoom", "Digital zoom",	NULL },
{ 0x0207, EXIF_FORMAT_STRING, -1,	 "Olympus.Firmware",	"Firmware version",	NULL },
{ 0x0208, EXIF_FORMAT_STRING, -1,	 "Olympus.PictureInfo",	"Picture info",		NULL },
{ 0x0209, EXIF_FORMAT_UNDEFINED, -1,	 "Olympus.CameraID",	"Camera ID",		NULL },
{ 0x020b, EXIF_FORMAT_LONG_UNSIGNED, 1,	 "Epson.ImageWidth",	"Image width",		NULL },
{ 0x020c, EXIF_FORMAT_LONG_UNSIGNED, 1,  "Epson.ImageHeight",	"Image height",		NULL },
{ 0x020d, EXIF_FORMAT_STRING, -1,	 "Epson.Manufacturer",	"Manufacturer",		NULL },
{ 0x0e00, EXIF_FORMAT_BYTE, -1,		 "Olympus.PrintImageMatching", "Print image matching", NULL },
{ 0x1004, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.FlashMode",	"Flash mode",		OlympusTagFlashMode },
{ 0x1006, EXIF_FORMAT_RATIONAL, 1,	 "Olympus.Bracket",	"Bracket",		NULL },
{ 0x100b, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.FocusMode",	"Focus mode",		OlympusTagFocusMode },
{ 0x100c, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "Olympus.FocusDistance", "Focus distance",	NULL },
{ 0x100d, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.Zoom",	"Zoom",			NULL },
{ 0x1006, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.MacroFocus",	"Macro focus",		NULL },
{ 0x100f, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.Sharpness",	"Sharpness",		OlympusTagSharpness },
{ 0x1011, EXIF_FORMAT_SHORT_UNSIGNED, 9, "Olympus.ColorMatrix",	"Color matrix",		NULL },
{ 0x1012, EXIF_FORMAT_SHORT_UNSIGNED, 4, "Olympus.BlackLevel",	"Black level",		NULL },
{ 0x1015, EXIF_FORMAT_SHORT_UNSIGNED, 2, "Olympus.WhiteBalance", "White balance",	NULL },
{ 0x1017, EXIF_FORMAT_SHORT_UNSIGNED, 2, "Olympus.RedBias",	"Red bias",		NULL },
{ 0x1018, EXIF_FORMAT_SHORT_UNSIGNED, 2, "Olympus.BlueBias",	"Blue bias",		NULL },
{ 0x101a, EXIF_FORMAT_STRING, -1,	 "Olympus.SerialNumber", "Serial number",	NULL },
{ 0x1023, EXIF_FORMAT_RATIONAL, 1,	 "Olympus.FlashBias",	"Flash bias",		NULL },
{ 0x1029, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.Contrast",	"Contrast",		OlympusTagContrast },
{ 0x102a, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.SharpnessFactor", "Sharpness factor",	NULL },
{ 0x102b, EXIF_FORMAT_SHORT_UNSIGNED, 6, "Olympus.ColorControl", "Color control",	NULL },
{ 0x102c, EXIF_FORMAT_SHORT_UNSIGNED, 2, "Olympus.ValidBits",	"Valid bits",		NULL },
{ 0x102d, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.CoringFilter", "Coring filter",	NULL },
{ 0x102e, EXIF_FORMAT_LONG_UNSIGNED, 1,  "Olympus.FinalWidth",	"Final width",		NULL },
{ 0x102f, EXIF_FORMAT_LONG_UNSIGNED, 1,  "Olympus.FinalHeight",	"Final height",		NULL },
{ 0x1034, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Olympus.CompressionRatio", "Compression ratio", NULL },
EXIF_MARKER_LIST_END
};

static ExifTextList OlympusShootingMode[]= {
	{ 0,	"normal" },
	{ 1,	"unknown" },
	{ 2,	"fast" },
	{ 3,	"panorama" },
	EXIF_TEXT_LIST_END
};

static ExifTextList OlympusPanoramaDirection[]= {
	{ 1,	"left to right" },
	{ 2,	"right to left" },
	{ 3,	"bottom to top" },
	{ 4,	"top to bottom" },
	EXIF_TEXT_LIST_END
};

static ExifTextList OlympusWB[]= {
	{ 1,	"auto" },
	{ 2,	"manual" },
	{ 3,	"one-touch" },
	EXIF_TEXT_LIST_END
};

static ExifTextList OlympusWBColorTemp[]= {
	{ 2,	"3000" },
	{ 3,	"3700" },
	{ 4,	"4000" },
	{ 5,	"4500" },
	{ 6,	"5500" },
	{ 7,	"6500" },
	{ 8,	"7500" },
	EXIF_TEXT_LIST_END
};

gboolean format_olympus_makernote(ExifData *exif, guchar *tiff, guint offset,
			          guint size, ExifByteOrder bo)
{
	guchar *data;
	ExifItem *item;

	if (offset + 8 + 4 >= size) return FALSE;

	data = tiff + offset;

	/* Olympus tag format starts with "OLYMP\x00\x01" or "OLYMP\x00\x02",
	 * plus an unknown byte,
	 * followed by IFD data using Olympus tags.
	 */
	if (memcmp(data, "OLYMP\x00\x01", 7) != 0 &&
	    memcmp(data, "OLYMP\x00\x02", 7) != 0) return FALSE;

	if (exif_parse_IFD_table(exif, tiff, offset + 8, size,
				 bo, 0, OlympusExifMarkersList) != 0)
		{
		return FALSE;
		}

	item = exif_get_item(exif, "Olympus.SpecialMode");
	if (item && item->data_len == 3 * sizeof(guint32))
		{
		static ExifMarker marker = { 0x0200, EXIF_FORMAT_STRING, -1,
					     "Olympus.ShootingMode", "Shooting mode", NULL };
		guint32 *array = item->data;
		gchar *mode;
		gchar *pdir = NULL;
		gchar *text;
		gint l;

		mode = exif_text_list_find_value(OlympusShootingMode, array[0]);
		if (array[0] == 3)
			{
			pdir = exif_text_list_find_value(OlympusPanoramaDirection, array[2]);
			}

		text = g_strdup_printf("%s%s%s, seq %d", mode,
				       (pdir) ? " " : "", (pdir) ? pdir : "",
				       array[1] + 1);
		l = strlen(text) + 1;
		item = exif_item_new(marker.format, marker.tag, l, &marker);
		memcpy(item->data, text, l);

		g_free(text);
		g_free(pdir);
		g_free(mode);

		exif->items = g_list_prepend(exif->items, item);
		}

	item = exif_get_item(exif, "Olympus.WhiteBalance");
	if (item && item->data_len == 2 * sizeof(guint16))
		{
		static ExifMarker marker = { 0x1015, EXIF_FORMAT_STRING, -1,
					     "Olympus.WhiteBalance", "White balance", NULL };
		guint16 *array = item->data;
		gchar *mode;
		gchar *color = NULL;
		gchar *text;
		gint l;

		mode = exif_text_list_find_value(OlympusWB, array[0]);
		if (array[0] == 2)
			{
			color = exif_text_list_find_value(OlympusWBColorTemp, array[1]);
			}

		text = g_strdup_printf("%s%s%s", mode,
				       (color) ? " " : "", (color) ? color : "");
		l = strlen(text) + 1;
		item = exif_item_new(marker.format, marker.tag, l, &marker);
		memcpy(item->data, text, l);

		g_free(text);
		g_free(color);
		g_free(mode);

		exif->items = g_list_prepend(exif->items, item);
		}

	return TRUE;
}


#endif
/* not HAVE_EXIV2 */
/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */