Beispiel #1
0
static gboolean
get_coordinates (EogImage *image,
		 gdouble *latitude,
		 gdouble *longitude)
{
	ExifData *exif_data;
	gchar buffer[32];
	gdouble lon, lat;

	exif_data = (ExifData *) eog_image_get_exif_info (image);

	if (exif_data) {
		ExifEntry *entry;
		ExifByteOrder byte_order;

		byte_order = exif_data_get_byte_order (exif_data);
		entry = exif_data_get_entry (exif_data,
					     EXIF_TAG_GPS_LONGITUDE);

		if (!parse_exif_gps_coordinate (entry, &lon, byte_order)
		    || (lon > 180.0)) {
			exif_data_unref (exif_data);
			return FALSE;
		}


		eog_exif_data_get_value (exif_data,
					 EXIF_TAG_GPS_LONGITUDE_REF,
					 buffer,
					 32);
		if (strcmp (buffer, "W") == 0)
			lon *= -1;

		entry = exif_data_get_entry (exif_data,
					     EXIF_TAG_GPS_LATITUDE);

		if (!parse_exif_gps_coordinate (entry, &lat, byte_order)
		    || (lat > 90.0)) {
			exif_data_unref (exif_data);
			return FALSE;
		}

		eog_exif_data_get_value (exif_data,
					 EXIF_TAG_GPS_LATITUDE_REF,
					 buffer,
					 32);
		if (strcmp (buffer, "S") == 0)
			lat *= -1;

		*longitude = lon;
		*latitude = lat;

		exif_data_unref (exif_data);
		return TRUE;
	}
	return FALSE;
}
static ExifDataTypeMakerNote
exif_data_get_type_maker_note (ExifData *d)
{
	ExifEntry *e, *em;
	char value[1024];

	if (!d) 
		return EXIF_DATA_TYPE_MAKER_NOTE_NONE;
	
	e = exif_data_get_entry (d, EXIF_TAG_MAKER_NOTE);
	if (!e) 
		return EXIF_DATA_TYPE_MAKER_NOTE_NONE;

	/* Olympus & Nikon & Sanyo */
	if ((e->size >= 8) && ( !memcmp (e->data, "OLYMP", 6) ||
				!memcmp (e->data, "OLYMPUS", 8) ||
				!memcmp (e->data, "SANYO", 6) ||
				!memcmp (e->data, "Nikon", 6)))
		return EXIF_DATA_TYPE_MAKER_NOTE_OLYMPUS;

	em = exif_data_get_entry (d, EXIF_TAG_MAKE);
	if (!em) 
		return EXIF_DATA_TYPE_MAKER_NOTE_NONE;

	/* Canon */
	if (!strcmp (exif_entry_get_value (em, value, sizeof (value)), "Canon"))
		return EXIF_DATA_TYPE_MAKER_NOTE_CANON;

	/* Pentax & some variant of Nikon */
	if ((e->size >= 2) && (e->data[0] == 0x00) && (e->data[1] == 0x1b)) {
		if (!strncasecmp (
			    exif_entry_get_value (em, value, sizeof(value)),
			    "Nikon", 5))
			return EXIF_DATA_TYPE_MAKER_NOTE_NIKON;
		else
			return EXIF_DATA_TYPE_MAKER_NOTE_PENTAX;
	}
	if ((e->size >= 8) && !memcmp (e->data, "AOC", 4)) {
		return EXIF_DATA_TYPE_MAKER_NOTE_PENTAX;
	}
	if ((e->size >= 8) && !memcmp (e->data, "QVC", 4)) {
		return EXIF_DATA_TYPE_MAKER_NOTE_CASIO;
	}
	if ((e->size >= 12) && !memcmp (e->data, "FUJIFILM", 8)) {
		return EXIF_DATA_TYPE_MAKER_NOTE_FUJI;
	}

	return EXIF_DATA_TYPE_MAKER_NOTE_NONE;
}
Beispiel #3
0
qint64 ImageSlideInfo::readExifIntValue(ExifData* pExifData, ExifTag exifTag)
{
    qint64 exifValue = 0;

    if (!pExifData)
        return exifValue;

    ExifByteOrder exifByteOrder = exif_data_get_byte_order(pExifData);

    ExifEntry* pExifEntry = exif_data_get_entry(pExifData, exifTag);
    if (pExifEntry) {
        // paranoic a bit
        if (pExifEntry->size <= sizeof(qint64)) {
            if (pExifEntry->format == EXIF_FORMAT_SBYTE)
                exifValue = static_cast<qint64>(*pExifEntry->data);

            if (pExifEntry->format == EXIF_FORMAT_SSHORT)
                exifValue = static_cast<qint64>(exif_get_sshort(pExifEntry->data, exifByteOrder));

            if (pExifEntry->format == EXIF_FORMAT_SLONG)
                exifValue = static_cast<qint64>(exif_get_slong(pExifEntry->data, exifByteOrder));
        }
    }

    return exifValue;
}
Beispiel #4
0
void JP4::readMakerNote() {

  if (_raw_app1)
    _ed = exif_data_new_from_data(_raw_app1, _raw_app1_length);

  if (!_ed)
    return;

  ExifEntry* makerNoteEntry = exif_data_get_entry(_ed, EXIF_TAG_MAKER_NOTE);

  if (!makerNoteEntry) {
    _makerNote.gain[0]  = _makerNote.gain[1]  = _makerNote.gain[2]  = _makerNote.gain[3] = 2.0;
    _makerNote.gamma[0] = _makerNote.gamma[1] = _makerNote.gamma[2] = _makerNote.gamma[3] = 0.57;
    _makerNote.gamma_scale[0] = _makerNote.gamma_scale[1] = _makerNote.gamma_scale[2] = _makerNote.gamma_scale[3] = 0xffff;

    _makerNote.black[0] = _makerNote.black[1] = _makerNote.black[2] = _makerNote.black[3] = 10/256.0;
    _makerNote.decim_hor = 1;
    _makerNote.decim_ver = 1;
    _makerNote.bin_hor = 1;
    _makerNote.bin_ver = 1;
    return;
  }

  int makerNoteLength = makerNoteEntry->size/4;
  long makerNote[makerNoteLength];

  for (int i = 0; i < makerNoteLength; i++) {
    makerNote[i] = get_long(makerNoteEntry->data + i*4);
  }

  for (int i = 0; i < 4; i++) {
    // channel gain  8.16 (0x10000 - 1.0). Combines both analog gain and digital scaling
    _makerNote.gain[i] = makerNote[i] / 65536.0;

    // (P_PIXEL_LOW<<24) | (P_GAMMA <<16) and 16-bit (6.10) scale for gamma tables,
    _makerNote.gamma_scale[i] = (makerNote[i+4] & 0xffff);
    _makerNote.gamma[i]       = ((makerNote[i+4]>>16) & 0xff) / 100.0;
    _makerNote.black[i]       =  (makerNote[i+4]>>24) / 256.0;
  }

  if (makerNoteLength >= 12) {
    _makerNote.woi_left   = (makerNote[8] & 0xffff);
    _makerNote.woi_width  = (makerNote[8]>>16) & 0xffff;
    _makerNote.woi_top    = (makerNote[9] & 0xffff);
    _makerNote.woi_height = (makerNote[9]>>16);

    _makerNote.flip_hor = (makerNote[10] & 0x1);
    _makerNote.flip_ver = (makerNote[10]>>1) & 0x1;

    _makerNote.bayer_mode = (makerNote[10]>>2) & 0x3;
    _makerNote.color_mode = (makerNote[10]>>4) & 0x0f;

    _makerNote.decim_hor = (makerNote[10]>> 8) & 0x0f;
    _makerNote.decim_ver = (makerNote[10]>>12) & 0x0f;

    _makerNote.bin_hor = (makerNote[10]>>16) & 0x0f;
    _makerNote.bin_ver = (makerNote[10]>>20) & 0x0f;
  }
Beispiel #5
0
QPixmap ExifPixmap::createPixmap(QString path)
{
    ExifData *exifData = exif_data_new_from_file(path.toStdString().c_str());
    int orientation = 0;
    if(exifData) {
        ExifByteOrder byteOrder = exif_data_get_byte_order(exifData);
        ExifEntry *exifEntry = exif_data_get_entry(exifData, EXIF_TAG_ORIENTATION);
        if(exifEntry) {
            orientation = exif_get_short(exifEntry->data, byteOrder);
        }
        exif_data_free(exifData);
    }
    QPixmap pic(path);
    /*
              0th Row      0th Column
           1  top          left side
           2  top          right side
           3  bottom       right side
           4  bottom       left side
           5  left side    top
           6  right side   top
           7  right side   bottom
           8  left side    bottom
        */
    QTransform t;
    switch(orientation) { // TODO : test flips
    case 1:
        break;
    case 2:
        t.scale(-1,1);
        break;
    case 3:
        t.rotate(180);
        break;
    case 4:
        t.rotate(180);
        t.scale(-1,1);
        break;
    case 5:
        t.rotate(90);
        t.scale(-1,1);
        break;
    case 6:
        t.rotate(90);
        break;
    case 7:
        t.rotate(-90);
        t.scale(-1,1);
        break;
    case 8:
        t.rotate(-90);
        break;
    default:
        break;
    }

    return pic.transformed(t);
}
int
exif_mnote_data_canon_identify (const ExifData *ed, const ExifEntry *e)
{
    char value[8];
    ExifEntry *em = exif_data_get_entry (ed, EXIF_TAG_MAKE);
    if (!em)
        return 0;
    return !strcmp (exif_entry_get_value (em, value, sizeof (value)), "Canon");
}
Beispiel #7
0
	std::string Exif::value(std::string tag_name) const {
		ExifEntry *entry;
		ExifTag tag;
		std::string value;
		char raw_value[1024];

		tag = exif_tag_from_name(tag_name.c_str());
		entry = exif_data_get_entry(m_data, tag);
		value = exif_entry_get_value(entry, raw_value, sizeof(raw_value));
		return value;
	}
Beispiel #8
0
/**
 * eog_exif_data_get_value:
 * @exif_data: pointer to an <structname>ExifData</structname> struct
 * @tag_id: the requested tag's id. See <filename>exif-tag.h</filename>
 * from the libexif package for possible values (e.g. %EXIF_TAG_EXPOSURE_MODE).
 * @buffer: a pre-allocated output buffer
 * @buf_size: size of @buffer
 *
 * Convenience function to extract a string representation of an Exif tag
 * directly from an <structname>ExifData</structname> struct. The string is
 * written into @buffer as far as @buf_size permits.
 *
 * Returns: a pointer to @buffer.
 */
const gchar *
eog_exif_data_get_value (EogExifData *exif_data, gint tag_id, gchar *buffer, guint buf_size)
{
	ExifEntry *exif_entry;
	const gchar *exif_value;

        exif_entry = exif_data_get_entry (exif_data, tag_id);

	buffer[0] = 0;

	exif_value = exif_entry_get_value (exif_entry, buffer, buf_size);

	return exif_value;
}
/*! If MakerNote is recognized, load it.
 *
 * \param[in,out] data #ExifData
 * \param[in] d pointer to raw EXIF data
 * \param[in] ds length of data at d
 */
static void
interpret_maker_note(ExifData *data, const unsigned char *d, unsigned int ds)
{
	int mnoteid;
	ExifEntry* e = exif_data_get_entry (data, EXIF_TAG_MAKER_NOTE);
	if (!e)
		return;
	
	if ((mnoteid = exif_mnote_data_olympus_identify (data, e)) != 0) {
		exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG,
			"ExifData", "Olympus MakerNote variant type %d", mnoteid);
		data->priv->md = exif_mnote_data_olympus_new (data->priv->mem);

	} else if ((mnoteid = exif_mnote_data_canon_identify (data, e)) != 0) {
		exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG,
			"ExifData", "Canon MakerNote variant type %d", mnoteid);
		data->priv->md = exif_mnote_data_canon_new (data->priv->mem, data->priv->options);

	} else if ((mnoteid = exif_mnote_data_fuji_identify (data, e)) != 0) {
		exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG,
			"ExifData", "Fuji MakerNote variant type %d", mnoteid);
		data->priv->md = exif_mnote_data_fuji_new (data->priv->mem);

	/* NOTE: Must do Pentax detection last because some of the
	 * heuristics are pretty general. */
	} else if ((mnoteid = exif_mnote_data_pentax_identify (data, e)) != 0) {
		exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG,
			"ExifData", "Pentax MakerNote variant type %d", mnoteid);
		data->priv->md = exif_mnote_data_pentax_new (data->priv->mem);
	}

	/* 
	 * If we are able to interpret the maker note, do so.
	 */
	if (data->priv->md) {
		exif_mnote_data_log (data->priv->md, data->priv->log);
		exif_mnote_data_set_byte_order (data->priv->md,
						data->priv->order);
		exif_mnote_data_set_offset (data->priv->md,
					    data->priv->offset_mnote);
		exif_mnote_data_load (data->priv->md, d, ds);
	}
}
static int getDouble(ExifData *ed, ExifByteOrder bo, ExifTag t, double *d) {
    ExifEntry * e = exif_data_get_entry(ed, t);
    if (!e)
        return 0;

    char *b = e->data;

    switch (e->format) {
        case EXIF_FORMAT_SHORT:
            *d = (double) exif_get_short(b, bo);
            return 1;

        case EXIF_FORMAT_SSHORT:
            *d = (double) exif_get_sshort(b, bo);
            return 1;

        case EXIF_FORMAT_LONG:
            *d = (double) exif_get_long(b, bo);
            return 1;

        case EXIF_FORMAT_SLONG:
            *d = (double) exif_get_slong(b, bo);
            return 1;

        case EXIF_FORMAT_RATIONAL:
        {
            ExifRational r = exif_get_rational(b, bo);
            *d = (double) r.numerator / (double) r.denominator;
            return 1;
        }

        case EXIF_FORMAT_SRATIONAL:
        {
            ExifSRational r = exif_get_srational(b, bo);
            *d = (double) r.numerator / (double) r.denominator;
            return 1;
        }

        default:
            return 0;
    }
}
Beispiel #11
0
ExifEntry *
rstto_file_get_exif ( RsttoFile *r_file, ExifTag id )
{
    /* If there is no exif-data object, try to create it */
    if ( NULL == r_file->priv->exif_data )
    {
        r_file->priv->exif_data = exif_data_new_from_file (
                rstto_file_get_path (r_file) );
    }

    if ( NULL != r_file->priv->exif_data )
    {
        return exif_data_get_entry (
                r_file->priv->exif_data,
                id );
    }

    /* If there is no exif-data, return NULL */
    return NULL;
}
Beispiel #12
0
QString ImageSlideInfo::readExifStringValue(ExifData* pExifData, ExifTag exifTag)
{
    QString exifValueStr;

    if (!pExifData)
        return exifValueStr;

    ExifEntry* pExifEntry = exif_data_get_entry(pExifData, exifTag);
    if (pExifEntry) {
        if (pExifEntry->format == EXIF_FORMAT_ASCII) {
            char* pBuffer = new char[pExifEntry->size];
            memset(pBuffer, '\0', pExifEntry->size);

            exif_entry_get_value(pExifEntry, pBuffer, pExifEntry->size);
            if (strlen(pBuffer) > 0)
                exifValueStr = pBuffer;

            delete[] pBuffer;
        }
    }

    return exifValueStr;
}
int
exif_mnote_data_olympus_identify (const ExifData *ed, const ExifEntry *e)
{
	int variant = exif_mnote_data_olympus_identify_variant(e->data, e->size);

	if (variant == nikonV0) {
		/* This variant needs some extra checking with the Make */
		char value[5];
		ExifEntry *em = exif_data_get_entry (ed, EXIF_TAG_MAKE);
		variant = unrecognized;

		if (em) {
			const char *v = exif_entry_get_value (em, value, sizeof(value));
			if (v && (!strncmp (v, "Nikon", sizeof(value)) || 
					  !strncmp (v, "NIKON", sizeof(value)) ))
				/* When saved, this variant will be written out like the
				 * alternative nikonV2 form above instead
				 */
				variant = nikonV0;
		}
	}

	return variant;
}
Beispiel #14
0
   bool
   getCalibrationFromEXIF(char const * fileName, int& width, int& height, double& focalLengthX, double& focalLengthY,
                          double const defaultWidth, double const defaultHeight)
   {
      width = defaultWidth;
      height = defaultHeight;

      focalLengthX = focalLengthY = -1;
      double fNative = -1, f35mm = -1;
      double fResX = -1, fResY = -1, fResUnits = -1;

      ExifData * ed = exif_data_new_from_file(fileName);
      if (!ed) return false;

      ExifByteOrder const byteOrder = exif_data_get_byte_order(ed);

      ExifEntry * entry;

      entry = exif_data_get_entry(ed, EXIF_TAG_PIXEL_X_DIMENSION);
      if (entry) width = getEXIF_DoubleVal(entry, byteOrder);

      entry = exif_data_get_entry(ed, EXIF_TAG_PIXEL_Y_DIMENSION);
      if (entry) height = getEXIF_DoubleVal(entry, byteOrder);

      entry = exif_data_get_entry(ed, EXIF_TAG_FOCAL_LENGTH);
      if (entry) fNative = getEXIF_DoubleVal(entry, byteOrder);

      entry = exif_data_get_entry(ed, EXIF_TAG_FOCAL_PLANE_X_RESOLUTION);
      if (entry) fResX = getEXIF_DoubleVal(entry, byteOrder);

      entry = exif_data_get_entry(ed, EXIF_TAG_FOCAL_PLANE_Y_RESOLUTION);
      if (entry) fResY = getEXIF_DoubleVal(entry, byteOrder);

      entry = exif_data_get_entry(ed, EXIF_TAG_FOCAL_PLANE_RESOLUTION_UNIT);
      if (entry) fResUnits = getEXIF_DoubleVal(entry, byteOrder);

      if (fResUnits == 1 || fResUnits == 2)
         fResUnits = 25.4;
      else if (fResUnits == 3)
         fResUnits = 10.0;
      else if (fResUnits == 4)
         fResUnits = 1.0;
      else if (fResUnits == 5)
         fResUnits = 0.001;
      else
         fResUnits = 25.4;

      if (fNative > 0 && fResX > 0 && fResY > 0 && fResUnits > 0)
      {
         focalLengthX = fNative * fResX / fResUnits;
         focalLengthY = fNative * fResY / fResUnits;
      }
      else
      {
         entry = exif_data_get_entry(ed, EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM);
         if (entry) f35mm = getEXIF_DoubleVal(entry, byteOrder);

         if (f35mm > 0) focalLengthX = focalLengthY = f35mm*width / 35.0;
      } // end if

      return focalLengthX > 0;
   } // getCalibrationFromEXIF()
Beispiel #15
0
void
eog_exif_util_set_focal_length_label_text (GtkLabel *label,
					   EogExifData *exif_data)
{
	ExifEntry *entry = NULL, *entry35mm = NULL;
	ExifByteOrder byte_order;
	gfloat f_val = 0.0;
	gchar *fl_text = NULL,*fl35_text = NULL;

	/* If no ExifData is supplied the label will be
	 * cleared later as fl35_text is NULL. */
	if (exif_data != NULL) {
		entry = exif_data_get_entry (exif_data, EXIF_TAG_FOCAL_LENGTH);
		entry35mm = exif_data_get_entry (exif_data,
					    EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM);
		byte_order = exif_data_get_byte_order (exif_data);
	}

	if (entry && G_LIKELY (entry->format == EXIF_FORMAT_RATIONAL)) {
		ExifRational value;

		/* Decode value by hand as libexif is not necessarily returning
		 * it in the format we want it to be.
		 */
		value = exif_get_rational (entry->data, byte_order);
		/* Guard against div by zero */
		if (G_LIKELY(value.denominator != 0))
			f_val = (gfloat)value.numerator/
				(gfloat)value.denominator;

		/* TRANSLATORS: This is the actual focal length used when
		   the image was taken.*/
		fl_text = g_strdup_printf (_("%.1f (lens)"), f_val);

	}
	if (entry35mm && G_LIKELY (entry35mm->format == EXIF_FORMAT_SHORT)) {
		ExifShort s_val;

		s_val = exif_get_short (entry35mm->data, byte_order);

		/* Print as float to get a similar look as above. */
		/* TRANSLATORS: This is the equivalent focal length assuming
		   a 35mm film camera. */
		fl35_text = g_strdup_printf(_("%.1f (35mm film)"),(float)s_val);
	}

	if (fl_text) {
		if (fl35_text) {
			gchar *merged_txt;

			merged_txt = g_strconcat (fl35_text,", ", fl_text, NULL);
			gtk_label_set_text (label, merged_txt);
			g_free (merged_txt);
		} else {
			gtk_label_set_text (label, fl_text);
		}
	} else {
		/* This will also clear the label if no ExifData was supplied */
		gtk_label_set_text (label, fl35_text);
	}

	g_free (fl35_text);
	g_free (fl_text);
}
Beispiel #16
0
static void
metadatamux_exif_for_each_tag_in_list (const GstTagList * list,
    const gchar * tag, gpointer user_data)
{
  ExifData *ed = (ExifData *) user_data;
  ExifTag exif_tag;
  GType type = G_TYPE_INVALID;
  ExifEntry *entry = NULL;
  ExifIfd ifd = EXIF_IFD_COUNT;
  const ExifByteOrder byte_order = exif_data_get_byte_order (ed);

  exif_tag = metadatamux_exif_get_exif_from_tag (tag, &type, &ifd);

  if (!exif_tag)
    goto done;

  entry = exif_data_get_entry (ed, exif_tag);

  if (entry)
    exif_entry_ref (entry);
  else {
    entry = exif_entry_new ();
    exif_content_add_entry (ed->ifd[ifd], entry);
    exif_entry_initialize (entry, exif_tag);
  }

  if (entry->data == NULL) {
    if (entry->tag == EXIF_TAG_GPS_ALTITUDE) {
      entry->format = EXIF_FORMAT_RATIONAL;
      entry->components = 1;
      entry->size = exif_format_get_size (entry->format) * entry->components;
      entry->data = g_malloc (entry->size);
    } else if (entry->tag == EXIF_TAG_GPS_LATITUDE
        || entry->tag == EXIF_TAG_GPS_LONGITUDE) {
      entry->format = EXIF_FORMAT_RATIONAL;
      entry->components = 3;
      entry->size = exif_format_get_size (entry->format) * entry->components;
      entry->data = g_malloc (entry->size);
    }
  }

  if (type == GST_TYPE_FRACTION) {
    const GValue *gvalue = gst_tag_list_get_value_index (list, tag, 0);
    gint numerator = gst_value_get_fraction_numerator (gvalue);
    gint denominator = gst_value_get_fraction_denominator (gvalue);

    switch (entry->format) {
      case EXIF_FORMAT_SRATIONAL:
      {
        ExifSRational sr = { numerator, denominator };

        exif_set_srational (entry->data, byte_order, sr);
      }
        break;
      case EXIF_FORMAT_RATIONAL:
      {
        ExifRational r;

        if (entry->tag == EXIF_TAG_X_RESOLUTION ||
            entry->tag == EXIF_TAG_Y_RESOLUTION) {
          ExifEntry *unit_entry = NULL;

          unit_entry = exif_data_get_entry (ed, EXIF_TAG_RESOLUTION_UNIT);

          if (unit_entry) {
            ExifShort vsh = exif_get_short (unit_entry->data, byte_order);

            if (vsh != 2)       /* inches */
              exif_set_short (unit_entry->data, byte_order, 2);
          }
        }
        r.numerator = numerator;
        r.denominator = denominator;
        if (numerator < 0)
          r.numerator = -numerator;
        if (denominator < 0)
          r.denominator = -denominator;
        exif_set_rational (entry->data, byte_order, r);
      }
        break;
      default:
        break;
    }
  } else if (type == GST_TYPE_BUFFER) {
    const GValue *val = NULL;
    GstBuffer *buf;

    val = gst_tag_list_get_value_index (list, tag, 0);
    buf = gst_value_get_buffer (val);
    entry->components = GST_BUFFER_SIZE (buf);
    entry->size = GST_BUFFER_SIZE (buf);
    entry->data = g_malloc (entry->size);
    memcpy (entry->data, GST_BUFFER_DATA (buf), entry->size);
  } else {
    switch (type) {
      case G_TYPE_STRING:
      {
        gchar *value = NULL;

        if (gst_tag_list_get_string (list, tag, &value)) {
          if (entry->tag == EXIF_TAG_DATE_TIME_DIGITIZED
              || entry->tag == EXIF_TAG_DATE_TIME
              || entry->tag == EXIF_TAG_DATE_TIME_ORIGINAL) {
            GString *datetime = g_string_new_len (value,
                20);            /* enough memory to hold "YYYY:MM:DD HH:MM:SS" */

            if (metadatamux_exif_convert_from_datetime (datetime)) {
            } else {
              GST_ERROR ("Unexpected date & time format for %s", tag);
            }
            g_free (value);
            value = datetime->str;
            g_string_free (datetime, FALSE);
          } else if (value) {
            entry->components = strlen (value) + 1;
            entry->size =
                exif_format_get_size (entry->format) * entry->components;
            entry->data = (guint8 *) value;
            value = NULL;
          }
        }
      }
        break;
      case G_TYPE_UINT:
      case G_TYPE_INT:
      {
        gint value;
        ExifShort v_short;

        if (G_TYPE_UINT == type) {
          gst_tag_list_get_uint (list, tag, (guint *) & value);
        } else {
          gst_tag_list_get_int (list, tag, &value);
        }

        switch (entry->format) {
          case EXIF_FORMAT_SHORT:
            if (entry->tag == EXIF_TAG_CONTRAST
                || entry->tag == EXIF_TAG_SATURATION) {
              if (value < -33)
                value = 1;      /* low */
              else if (value < 34)
                value = 0;      /* normal */
              else
                value = 2;      /* high */
            }
            v_short = value;
            exif_set_short (entry->data, byte_order, v_short);
            break;
          case EXIF_FORMAT_LONG:
            exif_set_long (entry->data, byte_order, value);
            break;
          default:
            break;
        }

      }
        break;
      case G_TYPE_DOUBLE:
      {
        gdouble value;

        gst_tag_list_get_double (list, tag, &value);
        if (entry->tag == EXIF_TAG_GPS_LATITUDE
            || entry->tag == EXIF_TAG_GPS_LONGITUDE) {
          ExifRational *rt = (ExifRational *) entry->data;
          gdouble v = fabs (value);
          ExifEntry *ref_entry = NULL;
          char ref;
          const ExifTag ref_tag = entry->tag == EXIF_TAG_GPS_LATITUDE ?
              EXIF_TAG_GPS_LATITUDE_REF : EXIF_TAG_GPS_LONGITUDE_REF;

          /* DDD - degrees */
          rt->numerator = (gulong) v;
          rt->denominator = 1;
          GST_DEBUG ("deg: %lf : %lu / %lu", v, (gulong) rt->numerator,
              (gulong) rt->denominator);
          v -= rt->numerator;
          rt++;

          /* MM - minutes */
          rt->numerator = (gulong) (v * 60.0);
          rt->denominator = 1;
          GST_DEBUG ("min: %lf : %lu / %lu", v, (gulong) rt->numerator,
              (gulong) rt->denominator);
          v -= ((gdouble) rt->numerator / 60.0);
          rt++;

          /* SS - seconds */
          rt->numerator = (gulong) (0.5 + v * 3600.0);
          rt->denominator = 1;
          GST_DEBUG ("sec: %lf : %lu / %lu", v, (gulong) rt->numerator,
              (gulong) rt->denominator);

          if (entry->tag == EXIF_TAG_GPS_LONGITUDE) {
            GST_DEBUG ("longitude : %lf", value);
            ref = (value < 0.0) ? 'W' : 'E';
          } else {
            GST_DEBUG ("latitude : %lf", value);
            ref = (value < 0.0) ? 'S' : 'N';
          }

          ref_entry = exif_data_get_entry (ed, ref_tag);
          if (ref_entry) {
            exif_entry_ref (ref_entry);
          } else {
            ref_entry = exif_entry_new ();
            exif_content_add_entry (ed->ifd[EXIF_IFD_GPS], ref_entry);
            exif_entry_initialize (ref_entry, ref_tag);
          }
          if (ref_entry->data == NULL) {
            ref_entry->format = EXIF_FORMAT_ASCII;
            ref_entry->components = 2;
            ref_entry->size = 2;
            ref_entry->data = g_malloc (2);
          }
          ref_entry->data[0] = ref;
          ref_entry->data[1] = 0;
          exif_entry_unref (ref_entry);
        } else if (entry->tag == EXIF_TAG_GPS_ALTITUDE) {
          ExifEntry *ref_entry = NULL;
          ExifRational *rt = (ExifRational *) entry->data;

          rt->numerator = (gulong) fabs (10.0 * value);
          rt->denominator = 10;

          GST_DEBUG ("altitude : %lf", value);

          ref_entry = exif_data_get_entry (ed, EXIF_TAG_GPS_ALTITUDE_REF);
          if (ref_entry) {
            exif_entry_ref (ref_entry);
          } else {
            ref_entry = exif_entry_new ();
            exif_content_add_entry (ed->ifd[EXIF_IFD_GPS], ref_entry);
            exif_entry_initialize (ref_entry, EXIF_TAG_GPS_ALTITUDE_REF);
          }
          if (ref_entry->data == NULL) {
            ref_entry->format = EXIF_FORMAT_BYTE;
            ref_entry->components = 1;
            ref_entry->size = 1;
            ref_entry->data = g_malloc (1);
          }
          if (value > 0.0) {
            ref_entry->data[0] = 0;
          } else {
            ref_entry->data[0] = 1;
          }
          exif_entry_unref (ref_entry);
        }
      }
        break;
      default:
        break;
    }
  }

done:

  if (entry)
    exif_entry_unref (entry);

}
static time_t
duf_exif_get_time( ExifData * edata, int *pdate_changed, char *stime_original, size_t stime_original_size, int *pr )
{
  int lr = 0;
  time_t timeepoch = 0;
  ExifEntry *entry = NULL;
  int changed = 0;

#if 0
  if ( ( entry = exif_content_get_entry( edata->ifd[EXIF_IFD_EXIF], EXIF_TAG_DATE_TIME_ORIGINAL ) )
/*                 || ( entry = exif_content_get_entry( edata->ifd[EXIF_IFD_EXIF], EXIF_TAG_DATE_TIME_DIGITIZED ) ) */
       || ( entry = exif_content_get_entry( edata->ifd[EXIF_IFD_0], EXIF_TAG_DATE_TIME ) ) )
#else
  if ( ( entry = exif_data_get_entry( edata, EXIF_TAG_DATE_TIME_ORIGINAL ) ) || ( entry = exif_data_get_entry( edata, EXIF_TAG_DATE_TIME ) ) )
#endif
  {
    memset( stime_original, stime_original_size, 0 );
    /* Get the contents of the tag in human-readable form */
    if ( lr >= 0 && !exif_entry_get_value( entry, stime_original, stime_original_size ) )
      DUF_MAKE_ERROR( lr, DUF_ERROR_EXIF );
    {
      char *corrected_time = NULL;

      for ( int i = 0; i < strlen( stime_original ); i++ )
      {
        char c;

        c = stime_original[i];
        if ( ( c < ' ' || c > 'z' ) && c != '?' && c != ':' && c != ' ' )
        {
          DUF_TRACE( exif, 0, ">>>>>>>>>>>>>> %s <<<<<<<<<<<<<", stime_original );
          DUF_MAKE_ERROR( lr, DUF_ERROR_EXIF_BROKEN_DATE );
          break;
        }
      }
      if ( lr >= 0 )
        corrected_time = mas_strdup( stime_original );
      /* DUF_SHOW_ERROR( "@@@@@@@@@@@@@@ %s", stime_original ); */
      DUF_TRACE( exif, 3, "stime_original:%s", stime_original );
      /* 2008:06:21 13:18:19 */
      /* 0123:56:89 12:45:78 */
      if ( lr >= 0 )
      {
        char *pq;

        while ( ( pq = strchr( corrected_time, '?' ) ) )
        {
          int n;

          n = pq - corrected_time;
          if ( n < 4 )
          {
            if ( n > 1 )
              *pq = '9';
          }
          else if ( n == 5 || n == 6 )
          {
            corrected_time[5] = '1';
            corrected_time[6] = '2';
          }
          else if ( n == 8 || n == 9 )
          {
            corrected_time[8] = '3';
            corrected_time[9] = '1';
          }
          else if ( n == 11 || n == 12 || n == 14 || n == 15 || n == 17 || n == 18 )
          {
            corrected_time[n] = '0';
          }
          changed++;
        }
      }
      if ( lr >= 0 && !*corrected_time )
        DUF_MAKE_ERROR( lr, DUF_ERROR_EXIF_NO_DATE );
      else if ( lr >= 0 && strchr( corrected_time, '?' ) )
      {
        DUF_SHOW_ERROR( "broken date %s", corrected_time );
        DUF_MAKE_ERROR( lr, DUF_ERROR_EXIF_BROKEN_DATE );
      }
      if ( lr >= 0 || lr == DUF_ERROR_EXIF_BROKEN_DATE )
      {
        if ( corrected_time && *corrected_time )
        {
          struct tm times = { 0 };

          strptime( corrected_time, "%Y:%m:%d %H:%M:%S", &times );

          /* timeepoch = mktime( &times ); */

          /* timeepoch = timelocal( &times ); */
          timeepoch = timegm( &times );

          /* strftime( buf1, sizeof( buf1 ), "%Y-%m-%d %H:%M:%S", &times ); */
          /* DUF_SHOW_ERROR( "!!!!! %lu : %lu", timeepoch, time(NULL) ); */
          /* Don't bother printing it if it's entirely blank */
          /* trim_spaces( corrected_time ); */
        }
      }
      mas_free( corrected_time );
    }
    /* ??? exif_entry_free( entry ); */
  }
  else if ( 0 )
  {
#if 0
#  define exif_data_get_entry(d, t) (
    exif_content_get_entry( d->ifd[EXIF_IFD_0], t ) ?
          exif_content_get_entry( d->ifd[EXIF_IFD_0], t ) :
          exif_content_get_entry( d->ifd[EXIF_IFD_1], t ) ?
          exif_content_get_entry( d->ifd[EXIF_IFD_1], t ) :
          exif_content_get_entry( d->ifd[EXIF_IFD_EXIF], t ) ?
          exif_content_get_entry( d->ifd[EXIF_IFD_EXIF], t ) :
          exif_content_get_entry( d->ifd[EXIF_IFD_GPS], t ) ?
          exif_content_get_entry( d->ifd[EXIF_IFD_GPS], t ) :
          exif_content_get_entry( d->ifd[EXIF_IFD_INTEROPERABILITY], t ) ? exif_content_get_entry( d->ifd[EXIF_IFD_INTEROPERABILITY], t ) : NULL )
#endif
          DUF_MAKE_ERROR( lr, DUF_ERROR_EXIF_NO_DATE );
#if 0
    if ( ( entry = exif_content_get_entry( edata->ifd[EXIF_IFD_0], EXIF_TAG_DATE_TIME_ORIGINAL ) ) )
      DUF_SHOW_ERROR( "NO DATE - HAS +1" );
    else if ( ( entry = exif_content_get_entry( edata->ifd[EXIF_IFD_1], EXIF_TAG_DATE_TIME_ORIGINAL ) ) )
      DUF_SHOW_ERROR( "NO DATE - HAS +2" );
    else if ( ( entry = exif_content_get_entry( edata->ifd[EXIF_IFD_EXIF], EXIF_TAG_DATE_TIME_ORIGINAL ) ) )
      DUF_SHOW_ERROR( "NO DATE - HAS +3" );
#else
    if ( ( entry = exif_data_get_entry( edata, EXIF_TAG_DATE_TIME_ORIGINAL ) ) )
      DUF_SHOW_ERROR( "NO DATE - HAS +123" );
#endif
#if 0
    else if ( ( entry = exif_content_get_entry( edata->ifd[EXIF_IFD_0], EXIF_TAG_DATE_TIME_DIGITIZED ) ) )
      DUF_SHOW_ERROR( "NO DATE - HAS +4" );
    else if ( ( entry = exif_content_get_entry( edata->ifd[EXIF_IFD_1], EXIF_TAG_DATE_TIME_DIGITIZED ) ) )
      DUF_SHOW_ERROR( "NO DATE - HAS +5" );
    else if ( ( entry = exif_content_get_entry( edata->ifd[EXIF_IFD_EXIF], EXIF_TAG_DATE_TIME_DIGITIZED ) ) )
      DUF_SHOW_ERROR( "NO DATE - HAS +6" );
#else
    else if ( ( entry = exif_data_get_entry( edata, EXIF_TAG_DATE_TIME_DIGITIZED ) ) )
      DUF_SHOW_ERROR( "NO DATE - HAS +456" );
#endif

#if 0
    else if ( ( entry = exif_content_get_entry( edata->ifd[EXIF_IFD_0], EXIF_TAG_DATE_TIME ) ) )
      DUF_SHOW_ERROR( "NO DATE - HAS +7" );
    else if ( ( entry = exif_content_get_entry( edata->ifd[EXIF_IFD_1], EXIF_TAG_DATE_TIME ) ) )
      DUF_SHOW_ERROR( "NO DATE - HAS +8" );
    else if ( ( entry = exif_content_get_entry( edata->ifd[EXIF_IFD_EXIF], EXIF_TAG_DATE_TIME ) ) )
      DUF_SHOW_ERROR( "NO DATE - HAS +9" );
#else
    else if ( ( entry = exif_data_get_entry( edata, EXIF_TAG_DATE_TIME ) ) )
      DUF_SHOW_ERROR( "NO DATE - HAS +789" );
#endif
    else
      DUF_SHOW_ERROR( "NO DATE" );
    /* ??? exif_entry_free( entry ); */
  }
    /* Function to populate TSK Blackboard exif related attributes */
    void extractExifData(ExifData * exifData, TskFile * pFile)
    {
        std::map<ExifTag, TSK_ATTRIBUTE_TYPE>::iterator it;
        std::vector<TskBlackboardAttribute> attrs;
        std::string datetime = "";
        int timezone = 0;

        for (it = tagMap.begin(); it != tagMap.end(); ++it)
        {
            ExifEntry * exifEntry = exif_data_get_entry(exifData, it->first);
            char tag_data[256];

            if (exifEntry == NULL)
                continue;

            if (it->first == EXIF_TAG_GPS_LATITUDE ||
                it->first == EXIF_TAG_GPS_LONGITUDE)
            {
                // Check for the EXIF_IFD_GPS image file directory to avoid interoperability value
                ExifIfd ifd = exif_entry_get_ifd(exifEntry);
                if (ifd != EXIF_IFD_GPS)
                    continue;

                exif_entry_get_value(exifEntry, tag_data, 256);

                float decDegrees = getDecimalDegrees(tag_data);

                char refValue[2];

                if (it->first == EXIF_TAG_GPS_LATITUDE)
                {
                    // Get the latitude reference value; used to determine if positive or negative decimal value
                    ExifEntry * latitudeRef = exif_data_get_entry(exifData, it->first);
                    exif_entry_get_value(latitudeRef, refValue,2);

                    if (strcmp(refValue, "S") == 0)
                        decDegrees *= -1;
                }
                else
                {
                    // Get the longitude reference value; used to determine if positive or negative decimal value
                    ExifEntry * longitudeRef = exif_data_get_entry(exifData, it->first);
                    exif_entry_get_value(longitudeRef, refValue,2);

                    if (strcmp(refValue, "W") == 0)
                        decDegrees *= -1;
                }
                
                TskBlackboardAttribute attr(it->second, name(), "", decDegrees);
                attrs.push_back(attr);                
            }
            else if (it->first == EXIF_TAG_GPS_SPEED)
            {
                // Check for the EXIF_IFD_GPS image file directory to avoid interoperability value
                ExifIfd ifd = exif_entry_get_ifd(exifEntry);
                if (ifd != EXIF_IFD_GPS)
                    continue;

                //Get the GPS speed value
                exif_entry_get_value(exifEntry, tag_data, 256);

                float speed = getGPSSpeed(tag_data);

                char refValue[2];

                //Get the GPS speed reference value
                ExifEntry * speedRef = exif_data_get_entry(exifData, it->first);
                exif_entry_get_value(speedRef, refValue,2);

                //Convert Kilometers per hour to meters per second 
                if (strcmp(refValue, "K") == 0)
                {
                     speed *= 0.277778;
                }
                //Convert Miles per hour to meters per second 
                if (strcmp(refValue, "M") == 0)
                {
                    speed *= 0.44704;
                }
                //Convert Knots to meters per second
                if (strcmp(refValue, "N") == 0)
                {
                    speed *= 0.514444;
                }
                
                TskBlackboardAttribute attr(it->second, name(), "", speed);
                attrs.push_back(attr);
            }
            else if (it->first == EXIF_TAG_DATE_TIME_ORIGINAL) 
            {
                exif_entry_get_value(exifEntry, tag_data, 256);
                datetime = std::string(tag_data);
            }
            else if(it->first == EXIF_TAG_TIME_ZONE_OFFSET){
                exif_entry_get_value(exifEntry, tag_data, 256);
                timezone = atoi(tag_data);
            }
            else
            {   
                // Get the tag's data
                exif_entry_get_value(exifEntry, tag_data, 256);

                // Add tag data to blackboard
                TskBlackboardAttribute attr(it->second, name(), "", tag_data);
                attrs.push_back(attr);
            }
        }
        if(!datetime.empty()){
            Poco::DateTime parsedDT;
            int tzd;
            Poco::DateTimeParser::tryParse(datetime, parsedDT, tzd);
            if(timezone)
                parsedDT.makeUTC(timezone);
            else
                parsedDT.makeUTC(tzd);
            TskBlackboardAttribute attr(TSK_DATETIME, name(), "", (uint64_t)parsedDT.utcTime());
            attrs.push_back(attr);
        }
        if(attrs.size() > 0){
            TskBlackboardArtifact art = pFile->createArtifact(TSK_METADATA_EXIF);
            for(size_t i = 0; i < attrs.size(); i++){
                art.addAttribute(attrs[i]);
            }
        }
    }