Esempio n. 1
0
ExifData* load_file (file_t* file)
{
  ExifData* ed = exif_data_new ();
  exif_data_unset_option (ed, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION);
  exif_data_set_option (ed, EXIF_DATA_OPTION_IGNORE_UNKNOWN_TAGS);
  exif_data_load_data (ed, file->addr, file->st.st_size);
  return ed;
}
ExifData *
exif_data_new_from_data (const unsigned char *data, unsigned int size)
{
	ExifData *edata;

	edata = exif_data_new ();
	exif_data_load_data (edata, data, size);
	return (edata);
}
Esempio n. 3
0
static int Dloadbuffer (lua_State *L) { /** data:loadbuffer(buf) */
  ExifData *data = checkdata(L);
  size_t length;
  const char *buffer = luaL_checklstring(L, 2, &length);

  exif_data_load_data(data, (const unsigned char *)buffer, length);

  return 0;
}
Esempio n. 4
0
ExifData *
exif_loader_get_data (ExifLoader *loader)
{
	ExifData *ed;

	if (!loader)
		return NULL;

	ed = exif_data_new_mem (loader->mem);
	exif_data_log (ed, loader->log);
	exif_data_load_data (ed, loader->buf, loader->bytes_read);

	return ed;
}
Esempio n. 5
0
/* Like exif_data_new_from_data(), but don't default missing fields. 
 * 
 * If we do exif_data_new_from_data(), then missing fields are set to 
 * their default value and we won't know about it. 
 */
static ExifData *
vips_exif_load_data_without_fix( void *data, int length )
{
	ExifData *ed;

	if( !(ed = exif_data_new()) ) {
		vips_error( "exif", "%s", _( "unable to init exif" ) ); 
		return( NULL );
	}

	exif_data_unset_option( ed, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION );
	exif_data_load_data( ed, data, length );

	return( ed );
}
Esempio n. 6
0
ExifData *
exif_loader_get_data (ExifLoader *loader)
{
	ExifData *ed;

	if (!loader || (loader->data_format == EL_DATA_FORMAT_UNKNOWN) ||
	    !loader->bytes_read)
		return NULL;

	ed = exif_data_new_mem (loader->mem);
	exif_data_log (ed, loader->log);
	exif_data_load_data (ed, loader->buf, loader->bytes_read);

	return ed;
}
Esempio n. 7
0
GstTagList *
gst_droidcamsrc_exif_tags_from_jpeg_data (void *data, size_t size)
{
  GstTagList *tags = NULL;
  ExifMem *mem = exif_mem_new (g_malloc0, g_realloc, g_free);
  ExifData *exif = exif_data_new_mem (mem);
  unsigned char *exif_data = NULL;
  void *_exif_data = NULL;
  unsigned int exif_data_size = 0;
  GstBuffer *buffer;
  ExifEntry *iso;
  int x, i;

  exif_data_load_data (exif, data, size);
  exif_data_set_data_type (exif, EXIF_DATA_TYPE_COMPRESSED);

  exif_data_save_data (exif, &exif_data, &exif_data_size);
  if (!exif_data_size) {
    goto out;
  }

  if (exif_data_size <= 6) {
    goto out;
  }

  /* dump the data. based on libexif code */
  for (x = 0; x < EXIF_IFD_COUNT; x++) {
    if (exif->ifd[x] && exif->ifd[x]->count) {
      for (i = 0; i < exif->ifd[x]->count; i++) {
        char val[1024];
        ExifEntry *e = exif->ifd[x]->entries[i];
        GST_LOG ("Exif IFD: %s. Tag 0x%x (%s) = %s", exif_ifd_get_name (x),
            e->tag, exif_tag_get_name_in_ifd (e->tag, exif_entry_get_ifd (e)),
            exif_entry_get_value (e, val, sizeof (val)));
      }
    }
  }

  _exif_data = exif_data;

  exif_data += 6;
  exif_data_size -= 6;

  buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
      exif_data, exif_data_size, 0, exif_data_size, NULL, NULL);
  tags = gst_tag_list_from_exif_buffer_with_tiff_header (buffer);
  gst_buffer_unref (buffer);

  /* We don't want these tags */
  gst_tag_list_remove_tag (tags, GST_TAG_DEVICE_MANUFACTURER);
  gst_tag_list_remove_tag (tags, GST_TAG_DEVICE_MODEL);
  gst_tag_list_remove_tag (tags, GST_TAG_APPLICATION_NAME);
  gst_tag_list_remove_tag (tags, GST_TAG_DATE_TIME);

  /* we have a mess with ISO so we will just behave as N9 */
  iso = exif_content_get_entry (exif->ifd[EXIF_IFD_EXIF],
      EXIF_TAG_ISO_SPEED_RATINGS);

  if (iso) {
#ifdef __arm__
    guint16 val = exif_get_short (iso->data, EXIF_BYTE_ORDER_MOTOROLA);
#else
    guint16 val = exif_get_short (iso->data, EXIF_BYTE_ORDER_INTEL);
#endif
    gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE,
        GST_TAG_CAPTURING_ISO_SPEED, val, NULL);
  }

  /* TODO: the following are being dropped
   *
   * 0x213  EXIF_TAG_YCBCR_POSITIONING
   * 0x9004 EXIF_TAG_DATE_TIME_DIGITIZED
   * 0x9101 EXIF_TAG_COMPONENTS_CONFIGURATION
   * 0xa001 EXIF_TAG_COLOR_SPACE
   * 0xa002 EXIF_TAG_PIXEL_X_DIMENSION
   * 0xa003 EXIF_TAG_PIXEL_Y_DIMENSION
   * 0xa005 EXIF_TAG_INTEROPERABILITY_IFD_POINTER
   * thumbnail.
   * 0x100 EXIF_TAG_IMAGE_WIDTH
   * 0x101 EXIF_TAG_IMAGE_LENGTH
   * 0x9203 EXIF_TAG_BRIGHTNESS_VALUE
   * 0x9205 EXIF_TAG_MAX_APERTURE_VALUE
   * 0x9206 EXIF_TAG_SUBJECT_DISTANCE
   * 0x9208 EXIF_TAG_LIGHT_SOURCE
   * 0x9286 EXIF_TAG_USER_COMMENT
   */
out:
  if (_exif_data) {
    exif_mem_free (mem, _exif_data);
  }

  if (exif) {
    exif_data_free (exif);
  }

  exif_mem_unref (mem);

  return tags;
}
void
jpeg_data_load_data (JPEGData *data, const unsigned char *d,
		     unsigned int size)
{
	unsigned int i, o, len;
	JPEGSection *s;
	JPEGMarker marker;

	if (!data) return;
	if (!d) return;

	for (o = 0; o < size;) {

		/*
		 * JPEG sections start with 0xff. The first byte that is
		 * not 0xff is a marker (hopefully).
		 */
		for (i = 0; i < MIN(7, size - o); i++)
			if (d[o + i] != 0xff)
				break;
		if ((i >= size - o) || !JPEG_IS_MARKER (d[o + i])) {
			exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, "jpeg-data",
					_("Data does not follow JPEG specification."));
			return;
		}
		marker = d[o + i];

		/* Append this section */
		jpeg_data_append_section (data);
		if (!data->count) return;
		s = &data->sections[data->count - 1];
		s->marker = marker;
		o += i + 1;

		switch (s->marker) {
		case JPEG_MARKER_SOI:
		case JPEG_MARKER_EOI:
			break;
		default:

			/* Read the length of the section */
			if (2 > size - o) { o = size; break; }
			len = ((d[o] << 8) | d[o + 1]) - 2;
			if (len > size) { o = size; break; }
			o += 2;
			if (len > size - o) { o = size; break; }

			switch (s->marker) {
			case JPEG_MARKER_APP1:
            /* Changed to add the EXIF_LOG feature.
               2012.04.05 - Samsung Electronics */
				/*s->content.app1 = exif_data_new_from_data (
							d + o - 4, len + 4); */
				s->content.app1 = exif_data_new();
                exif_data_log(s->content.app1, data->priv->log);
            	exif_data_load_data (s->content.app1, d + o - 4, len + 4);
				break;
			default:
				s->content.generic.data =
						malloc (sizeof (char) * len);
				if (!s->content.generic.data) {
					EXIF_LOG_NO_MEMORY (data->priv->log, "jpeg-data", sizeof (char) * len);
					return;
				}
				s->content.generic.size = len;
				memcpy (s->content.generic.data, &d[o], len);

				/* In case of SOS, image data will follow. */
				if (s->marker == JPEG_MARKER_SOS) {
					data->size = size - o - len;
					if (data->size >= 2) {
						/* -2 means 'take all but the last 2 bytes which are
						   hoped to be JPEG_MARKER_EOI */
						data->size -= 2;
						if (d[o + len + data->size] != 0xFF) {
							/* A truncated file (i.e. w/o JPEG_MARKER_EOI at the end).
							   Instead of trying to use the last two bytes as marker,
							   touching memory beyond allocated memory and posssibly saving
							   back screwed file, we rather take the rest of the file. */
							data->size += 2;
						}
					}
					data->data = malloc (
						sizeof (char) * data->size);
					if (!data->data) {
						EXIF_LOG_NO_MEMORY (data->priv->log, "jpeg-data", sizeof (char) * data->size);
						data->size = 0;
						return;
					}
					memcpy (data->data, d + o + len,
						data->size);
					o += data->size;
				}
				break;
			}
			o += len;
			break;
		}
	}
}
Esempio n. 9
0
gint32
load_image (const gchar  *filename,
            GimpRunMode   runmode,
            gboolean      preview,
            GError      **error)
{
  GimpPixelRgn     pixel_rgn;
  GimpDrawable    *drawable;
  gint32 volatile  image_ID;
  gint32           layer_ID;
  struct jpeg_decompress_struct cinfo;
  struct my_error_mgr           jerr;
  jpeg_saved_marker_ptr         marker;
  FILE            *infile;
  guchar          *buf;
  guchar         **rowbuf;
  gint             image_type;
  gint             layer_type;
  gint             tile_height;
  gint             scanlines;
  gint             i, start, end;
#ifdef HAVE_LIBEXIF
  gint             orientation = 0;
#endif
#ifdef HAVE_LCMS
  cmsHTRANSFORM    cmyk_transform = NULL;
#else
  gpointer         cmyk_transform = NULL;
#endif

  /* We set up the normal JPEG error routines. */
  cinfo.err = jpeg_std_error (&jerr.pub);
  jerr.pub.error_exit = my_error_exit;

  if (!preview)
    {
      jerr.pub.output_message = my_output_message;
    }

  if ((infile = g_fopen (filename, "rb")) == NULL)
    {
      g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
                   _("Could not open '%s' for reading: %s"),
                   gimp_filename_to_utf8 (filename), g_strerror (errno));
      return -1;
    }

  if (!preview)
    gimp_progress_init_printf (_("Opening '%s'"),
                               gimp_filename_to_utf8 (filename));

  image_ID = -1;

  /* Establish the setjmp return context for my_error_exit to use. */
  if (setjmp (jerr.setjmp_buffer))
    {
      /* If we get here, the JPEG code has signaled an error.
       * We need to clean up the JPEG object, close the input file, and return.
       */
      jpeg_destroy_decompress (&cinfo);
      if (infile)
        fclose (infile);

      if (image_ID != -1 && !preview)
        gimp_image_delete (image_ID);

      if (preview)
        destroy_preview ();

      return -1;
    }

  /* Now we can initialize the JPEG decompression object. */
  jpeg_create_decompress (&cinfo);

  /* Step 2: specify data source (eg, a file) */

  jpeg_stdio_src (&cinfo, infile);

  if (! preview)
    {
      /* - step 2.1: tell the lib to save the comments */
      jpeg_save_markers (&cinfo, JPEG_COM, 0xffff);

      /* - step 2.2: tell the lib to save APP1 data (EXIF or XMP) */
      jpeg_save_markers (&cinfo, JPEG_APP0 + 1, 0xffff);

      /* - step 2.3: tell the lib to save APP2 data (ICC profiles) */
      jpeg_save_markers (&cinfo, JPEG_APP0 + 2, 0xffff);
    }

  /* Step 3: read file parameters with jpeg_read_header() */

  jpeg_read_header (&cinfo, TRUE);

  /* We can ignore the return value from jpeg_read_header since
   *   (a) suspension is not possible with the stdio data source, and
   *   (b) we passed TRUE to reject a tables-only JPEG file as an error.
   * See libjpeg.doc for more info.
   */

  /* Step 4: set parameters for decompression */

  /* In this example, we don't need to change any of the defaults set by
   * jpeg_read_header(), so we do nothing here.
   */

  /* Step 5: Start decompressor */

  jpeg_start_decompress (&cinfo);

  /* We may need to do some setup of our own at this point before reading
   * the data.  After jpeg_start_decompress() we have the correct scaled
   * output image dimensions available, as well as the output colormap
   * if we asked for color quantization.
   */

  /* temporary buffer */
  tile_height = gimp_tile_height ();
  buf = g_new (guchar,
               tile_height * cinfo.output_width * cinfo.output_components);

  rowbuf = g_new (guchar *, tile_height);

  for (i = 0; i < tile_height; i++)
    rowbuf[i] = buf + cinfo.output_width * cinfo.output_components * i;

  switch (cinfo.output_components)
    {
    case 1:
      image_type = GIMP_GRAY;
      layer_type = GIMP_GRAY_IMAGE;
      break;

    case 3:
      image_type = GIMP_RGB;
      layer_type = GIMP_RGB_IMAGE;
      break;

    case 4:
      if (cinfo.out_color_space == JCS_CMYK)
        {
          image_type = GIMP_RGB;
          layer_type = GIMP_RGB_IMAGE;
          break;
        }
      /*fallthrough*/

    default:
      g_message ("Don't know how to load JPEG images "
                 "with %d color channels, using colorspace %d (%d).",
                 cinfo.output_components, cinfo.out_color_space,
                 cinfo.jpeg_color_space);
      return -1;
      break;
    }

  if (preview)
    {
      image_ID = preview_image_ID;
    }
  else
    {
      image_ID = gimp_image_new (cinfo.output_width, cinfo.output_height,
                                 image_type);

      gimp_image_undo_disable (image_ID);
      gimp_image_set_filename (image_ID, filename);
    }

  if (preview)
    {
      preview_layer_ID = gimp_layer_new (preview_image_ID, _("JPEG preview"),
                                         cinfo.output_width,
                                         cinfo.output_height,
                                         layer_type, 100, GIMP_NORMAL_MODE);
      layer_ID = preview_layer_ID;
    }
  else
    {
      layer_ID = gimp_layer_new (image_ID, _("Background"),
                                 cinfo.output_width,
                                 cinfo.output_height,
                                 layer_type, 100, GIMP_NORMAL_MODE);
    }

  drawable_global = drawable = gimp_drawable_get (layer_ID);
  gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0,
                       drawable->width, drawable->height, TRUE, FALSE);

  if (! preview)
    {
      GString  *comment_buffer = NULL;
      guint8   *profile        = NULL;
      guint     profile_size   = 0;
#ifdef HAVE_LIBEXIF
      ExifData *exif_data      = NULL;
#endif

      /* Step 5.0: save the original JPEG settings in a parasite */
      jpeg_detect_original_settings (&cinfo, image_ID);

      /* Step 5.1: check for comments, or EXIF metadata in APP1 markers */
      for (marker = cinfo.marker_list; marker; marker = marker->next)
        {
          const gchar *data = (const gchar *) marker->data;
          gsize        len  = marker->data_length;

          if (marker->marker == JPEG_COM)
            {
#ifdef GIMP_UNSTABLE
              g_print ("jpeg-load: found image comment (%d bytes)\n",
                       marker->data_length);
#endif

              if (! comment_buffer)
                {
                  comment_buffer = g_string_new_len (data, len);
                }
              else
                {
                  /* concatenate multiple comments, separate them with LF */
                  g_string_append_c (comment_buffer, '\n');
                  g_string_append_len (comment_buffer, data, len);
                }
            }
          else if ((marker->marker == JPEG_APP0 + 1)
                   && (len > sizeof (JPEG_APP_HEADER_EXIF) + 8)
                   && ! strcmp (JPEG_APP_HEADER_EXIF, data))
            {
#ifdef GIMP_UNSTABLE
              g_print ("jpeg-load: found EXIF block (%d bytes)\n",
                       (gint) (len - sizeof (JPEG_APP_HEADER_EXIF)));
#endif
#ifdef HAVE_LIBEXIF
              if (! exif_data)
                exif_data = exif_data_new ();
              /* if there are multiple blocks, their data will be merged */
              exif_data_load_data (exif_data, (unsigned char *) data, len);
#endif
            }
        }

#ifdef HAVE_LIBEXIF
      if (!jpeg_load_exif_resolution (image_ID, exif_data))
#endif
        jpeg_load_resolution (image_ID, &cinfo);

      /* if we found any comments, then make a parasite for them */
      if (comment_buffer && comment_buffer->len)
        {
          GimpParasite *parasite;

          jpeg_load_sanitize_comment (comment_buffer->str);
          parasite = gimp_parasite_new ("gimp-comment",
                                        GIMP_PARASITE_PERSISTENT,
                                        strlen (comment_buffer->str) + 1,
                                        comment_buffer->str);
          gimp_image_attach_parasite (image_ID, parasite);
          gimp_parasite_free (parasite);

          g_string_free (comment_buffer, TRUE);
        }

#ifdef HAVE_LIBEXIF
      /* if we found any EXIF block, then attach the metadata to the image */
      if (exif_data)
        {
          gimp_metadata_store_exif (image_ID, exif_data);
          orientation = jpeg_exif_get_orientation (exif_data);
          exif_data_unref (exif_data);
          exif_data = NULL;
        }
#endif

      /* Step 5.2: check for XMP metadata in APP1 markers (after EXIF) */
      for (marker = cinfo.marker_list; marker; marker = marker->next)
        {
          const gchar *data = (const gchar *) marker->data;
          gsize        len  = marker->data_length;

          if ((marker->marker == JPEG_APP0 + 1)
              && (len > sizeof (JPEG_APP_HEADER_XMP) + 20)
              && ! strcmp (JPEG_APP_HEADER_XMP, data))
            {
              GimpParam *return_vals;
              gint       nreturn_vals;
              gchar     *xmp_packet;

#ifdef GIMP_UNSTABLE
              g_print ("jpeg-load: found XMP packet (%d bytes)\n",
                       (gint) (len - sizeof (JPEG_APP_HEADER_XMP)));
#endif
              xmp_packet = g_strndup (data + sizeof (JPEG_APP_HEADER_XMP),
                                      len - sizeof (JPEG_APP_HEADER_XMP));

              /* FIXME: running this through the PDB is not very efficient */
              return_vals = gimp_run_procedure ("plug-in-metadata-decode-xmp",
                                                &nreturn_vals,
                                                GIMP_PDB_IMAGE, image_ID,
                                                GIMP_PDB_STRING, xmp_packet,
                                                GIMP_PDB_END);

              if (return_vals[0].data.d_status != GIMP_PDB_SUCCESS)
                {
                  g_warning ("JPEG - unable to decode XMP metadata packet");
                }

              gimp_destroy_params (return_vals, nreturn_vals);
              g_free (xmp_packet);
            }
        }

      /* Step 5.3: check for an embedded ICC profile in APP2 markers */
      jpeg_icc_read_profile (&cinfo, &profile, &profile_size);

      if (cinfo.out_color_space == JCS_CMYK)
        {
          cmyk_transform = jpeg_load_cmyk_transform (profile, profile_size);
        }
      else if (profile) /* don't attach the profile if we are transforming */
        {
          GimpParasite *parasite;

          parasite = gimp_parasite_new ("icc-profile",
                                        GIMP_PARASITE_PERSISTENT |
                                        GIMP_PARASITE_UNDOABLE,
                                        profile_size, profile);
          gimp_image_attach_parasite (image_ID, parasite);
          gimp_parasite_free (parasite);
        }

      g_free (profile);

      /* Do not attach the "jpeg-save-options" parasite to the image
       * because this conflicts with the global defaults (bug #75398).
       */
    }

  /* Step 6: while (scan lines remain to be read) */
  /*           jpeg_read_scanlines(...); */

  /* Here we use the library's state variable cinfo.output_scanline as the
   * loop counter, so that we don't have to keep track ourselves.
   */
  while (cinfo.output_scanline < cinfo.output_height)
    {
      start = cinfo.output_scanline;
      end   = cinfo.output_scanline + tile_height;
      end   = MIN (end, cinfo.output_height);

      scanlines = end - start;

      for (i = 0; i < scanlines; i++)
        jpeg_read_scanlines (&cinfo, (JSAMPARRAY) &rowbuf[i], 1);

      if (cinfo.out_color_space == JCS_CMYK)
        jpeg_load_cmyk_to_rgb (buf, drawable->width * scanlines,
                               cmyk_transform);

      gimp_pixel_rgn_set_rect (&pixel_rgn, buf,
                               0, start, drawable->width, scanlines);

      if (! preview && (cinfo.output_scanline % 32) == 0)
        gimp_progress_update ((gdouble) cinfo.output_scanline /
                              (gdouble) cinfo.output_height);
    }

  /* Step 7: Finish decompression */

  jpeg_finish_decompress (&cinfo);
  /* We can ignore the return value since suspension is not possible
   * with the stdio data source.
   */

#ifdef HAVE_LCMS
  if (cmyk_transform)
    cmsDeleteTransform (cmyk_transform);
#endif

  /* Step 8: Release JPEG decompression object */

  /* This is an important step since it will release a good deal of memory. */
  jpeg_destroy_decompress (&cinfo);

  /* free up the temporary buffers */
  g_free (rowbuf);
  g_free (buf);

  /* After finish_decompress, we can close the input file.
   * Here we postpone it until after no more JPEG errors are possible,
   * so as to simplify the setjmp error logic above.  (Actually, I don't
   * think that jpeg_destroy can do an error exit, but why assume anything...)
   */
  fclose (infile);

  /* At this point you may want to check to see whether any corrupt-data
   * warnings occurred (test whether jerr.num_warnings is nonzero).
   */

  /* Detach from the drawable and add it to the image.
   */
  if (! preview)
    {
      gimp_progress_update (1.0);
      gimp_drawable_detach (drawable);
    }

  gimp_image_insert_layer (image_ID, layer_ID, -1, 0);

#ifdef HAVE_LIBEXIF
  jpeg_exif_rotate_query (image_ID, orientation);
#endif

  return image_ID;
}