Logo Search packages:      
Sourcecode: f-spot version File versions

jpeg-data.c

/* jpeg-data.c
 *
 * Copyright (C) 2001 Lutz Müller <lutz@users.sourceforge.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details. 
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/* Changed by Paolo Bacchilega. */

#include <config.h>

#ifdef HAVE_LIBEXIF

#include <config.h>
#include "jpeg-data.h"

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

//#define DEBUG

struct _JPEGDataPrivate
{
      unsigned int ref_count;
};

JPEGData *
jpeg_data_new (void)
{
      JPEGData *data;

      data = malloc (sizeof (JPEGData));
      if (!data)
            return (NULL);
      memset (data, 0, sizeof (JPEGData));
      data->priv = malloc (sizeof (JPEGDataPrivate));
      if (!data->priv) {
            free (data);
            return (NULL);
      }
      memset (data->priv, 0, sizeof (JPEGDataPrivate));
      data->priv->ref_count = 1;

      return (data);
}

static void
jpeg_data_append_section (JPEGData *data)
{
      JPEGSection *s;

      if (!data->count)
            s = malloc (sizeof (JPEGSection));
      else
            s = realloc (data->sections,
                       sizeof (JPEGSection) * (data->count + 1));
      if (!s)
            return;

      data->sections = s;
      data->count++;
}

void
jpeg_data_save_file (JPEGData *data, const char *path)
{
      FILE *f;
      unsigned char *d = NULL;
      unsigned int size = 0;
      
      printf ("Saving jpeg data\n");
      jpeg_data_save_data (data, &d, &size);
      if (!d) {
            printf ("error serializing jpeg data\n");
            return;
      }

      unlink (path);
      f = fopen (path, "wb");
      if (!f) {
            printf ("error opening file\n");
            free (d);
            return;
      }
      fwrite (d, sizeof (char), size, f);
      fclose (f);
      free (d);
}

void
jpeg_data_save_data (JPEGData *data, unsigned char **d, unsigned int *ds)
{
      unsigned int i, eds = 0;
      JPEGSection s;
      unsigned char *ed = NULL;

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

      for (*ds = i = 0; i < data->count; i++) {
            s = data->sections[i];
#ifdef DEBUG
            printf ("Writing marker 0x%x at position %i...\n",
                  s.marker, *ds);
#endif

            /* Write the marker */
            *d = realloc (*d, sizeof (char) * (*ds + 2));
            (*d)[*ds + 0] = 0xff;
            (*d)[*ds + 1] = s.marker;
            *ds += 2;

            switch (s.marker) {
            case JPEG_MARKER_SOI:
            case JPEG_MARKER_EOI:
                  break;
            case JPEG_MARKER_APP1:
                  exif_data_save_data (s.content.app1, &ed, &eds);
                  *d = realloc (*d, sizeof (char) * (*ds + 2));
                  (*d)[*ds + 0] = (eds + 2) >> 8;
                  (*d)[*ds + 1] = (eds + 2) >> 0;
                  *ds += 2;
                  *d = realloc (*d, sizeof (char) * (*ds + eds));
                  memcpy (*d + *ds, ed, eds);
                  *ds += eds;
                  break;
            default:
                  *d = realloc (*d, sizeof (char) *
                              (*ds + s.content.generic.size + 2));
                  (*d)[*ds + 0] = (s.content.generic.size + 2) >> 8;
                  (*d)[*ds + 1] = (s.content.generic.size + 2) >> 0;
                  *ds += 2;
                  memcpy (*d + *ds, s.content.generic.data,
                        s.content.generic.size);
                  *ds += s.content.generic.size;

                  /* In case of SOS, we need to write the data. */
                  if (s.marker == JPEG_MARKER_SOS) {
                        *d = realloc (*d, *ds + data->size);
                        memcpy (*d + *ds, data->data, data->size);
                        *ds += data->size;
                  }
                  break;
            }
      }
}

JPEGData *
jpeg_data_new_from_data (const unsigned char *d,
                   unsigned int size)
{
      JPEGData *data;

      data = jpeg_data_new ();
      jpeg_data_load_data (data, d, size);
      return (data);
}

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;

#ifdef DEBUG
      printf ("Parsing %i bytes...\n", size);
#endif

      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 < 7; i++)
                  if (d[o + i] != 0xff)
                        break;
            if (!JPEG_IS_MARKER (d[o + i]))
                  return;
            marker = d[o + i];

#ifdef DEBUG
            printf ("Found marker 0x%x ('%s') at %i.\n", marker,
                  jpeg_marker_get_name (marker), o + i);
#endif

            /* Append this section */
            jpeg_data_append_section (data);
            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 */
                  len = ((d[o] << 8) | d[o + 1]) - 2;
                  o += 2;

                  switch (s->marker) {
                  case JPEG_MARKER_APP1:
                        s->content.app1 = exif_data_new_from_data (
                                          d + o - 4, len + 4);
                        break;
                  default:
                        s->content.generic.size = len;
                        s->content.generic.data =
                                    malloc (sizeof (char) * 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 - 2 - o - len;
                              data->data = malloc (
                                    sizeof (char) * data->size);
                              memcpy (data->data, d + o + len,
                                    data->size);
                              o += data->size;
                        }
                        break;
                  }
                  o += len;
                  break;
            }
      }
}

JPEGData *
jpeg_data_new_from_file (const char *path)
{
      JPEGData *data;

      data = jpeg_data_new ();
      jpeg_data_load_file (data, path);
      return (data);
}

void
jpeg_data_load_file (JPEGData *data, const char *path)
{
      FILE *f;
      unsigned char *d;
      unsigned int size;

      if (!data)
            return;
      if (!path)
            return;

      f = fopen (path, "rb");
      if (!f)
            return;

      /* For now, we read the data into memory. Patches welcome... */
      fseek (f, 0, SEEK_END);
      size = ftell (f);
      fseek (f, 0, SEEK_SET);
      d = malloc (sizeof (char) * size);
      if (!d) {
            fclose (f);
            return;
      }
      if (fread (d, 1, size, f) != size) {
            free (d);
            fclose (f);
            return;
      }
      fclose (f);

      jpeg_data_load_data (data, d, size);
      free (d);
}

void
jpeg_data_ref (JPEGData *data)
{
      if (!data)
            return;

      data->priv->ref_count++;
}

void
jpeg_data_unref (JPEGData *data)
{
      if (!data)
            return;

      data->priv->ref_count--;
      if (!data->priv->ref_count)
            jpeg_data_free (data);
}

void
jpeg_data_free (JPEGData *data)
{
      unsigned int i;
      JPEGSection s;

      if (!data)
            return;

      if (data->count) {
            for (i = 0; i < data->count; i++) {
                  s = data->sections[i];
                  switch (s.marker) {
                  case JPEG_MARKER_SOI:
                  case JPEG_MARKER_EOI:
                        break;
                  case JPEG_MARKER_APP1:
                        exif_data_unref (s.content.app1);
                        break;
                  default:
                        free (s.content.generic.data);
                        break;
                  }
            }
            free (data->sections);
      }

      if (data->data)
            free (data->data);
      free (data->priv);
      free (data);
}

void
jpeg_data_dump (JPEGData *data)
{
      unsigned int i;
      JPEGContent content;
      JPEGMarker marker;

      if (!data)
            return;

      printf ("Dumping JPEG data (%i bytes of data)...\n", data->size);
      for (i = 0; i < data->count; i++) {
            marker = data->sections[i].marker;
            content = data->sections[i].content;
            printf ("Section %i (marker 0x%x - %s):\n", i, marker,
                  jpeg_marker_get_name (marker));
            printf ("  Description: %s\n",
                  jpeg_marker_get_description (marker));
            switch (marker) {
                case JPEG_MARKER_SOI:
                case JPEG_MARKER_EOI:
                  break;
                case JPEG_MARKER_APP1:
                  exif_data_dump (content.app1);
                  break;
                default:
                  printf ("  Size: %i\n", content.generic.size);
                        printf ("  Unknown content.\n");
                        break;
                }
        }
}

static JPEGSection *
jpeg_data_get_section (JPEGData *data, JPEGMarker marker)
{
      unsigned int i;

      if (!data)
            return (NULL);

      for (i = 0; i < data->count; i++)
            if (data->sections[i].marker == marker)
                  return (&data->sections[i]);
      return (NULL);
}

ExifData *
jpeg_data_get_exif_data (JPEGData *data)
{
      JPEGSection *section;

      if (!data)
            return NULL;

      section = jpeg_data_get_section (data, JPEG_MARKER_APP1);
      if (section) {
            exif_data_ref (section->content.app1);
            return (section->content.app1);
      }

      return (NULL);
}

void
jpeg_data_set_exif_data (JPEGData *data, ExifData *exif_data)
{
      JPEGSection *section;

      section = jpeg_data_get_section (data, JPEG_MARKER_APP1);
      if (!section) {
            jpeg_data_append_section (data);
            memmove (&data->sections[2], &data->sections[1],
                   data->count - 2);
            section = &data->sections[1];
      }
      section->marker = JPEG_MARKER_APP1;
      section->content.app1 = exif_data;
      exif_data_ref (exif_data);
}

#endif /* HAVE_LIBEXIF */

Generated by  Doxygen 1.6.0   Back to index