Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Gnome/gdk/loaders/   (Gnome Linux Desktop Version 4.23.2©)  Datei vom 30.5.2026 mit Größe 23 kB image not shown  

Quelle  gdktiff.c

  Sprache: C
 

/* GDK - The GIMP Drawing Kit
 * Copyright (C) 2021 Red Hat, Inc.
 *
 * 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, see <http://www.gnu.org/licenses/>.
 */


#include "config.h"

#include "gdktiffprivate.h"

#include "gdkcolorstate.h"
#include "gdkmemoryformatprivate.h"
#include "gdkmemorytextureprivate.h"
#include "gdkprofilerprivate.h"
#include "gdktexturedownloaderprivate.h"

#include <glib/gi18n-lib.h>
#include <tiffio.h>

/* Our main interest in tiff as an image format is that it is
 * flexible enough to save all our texture formats without
 * lossy conversions.
 *
 * The loader isn't meant to be a very versatile. It just aims
 * to load the subset that we're saving ourselves. For anything
 * else, we fall back to TIFFRGBAImage, which is the same api
 * that gdk-pixbuf uses.
 */


/* {{{ IO handling */

typedef struct
{
  GBytes **out_bytes;
  gchar *data;
  gsize size;
  gsize position;
} TiffIO;

static void
tiff_io_warning (const char *module,
                 const char *fmt,
                 va_list     ap) G_GNUC_PRINTF(20);
static void
tiff_io_warning (const char *module,
                 const char *fmt,
                 va_list     ap)
{
  g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, fmt, ap);
}

static void
tiff_io_error (const char *module,
               const char *fmt,
               va_list     ap) G_GNUC_PRINTF(20);
static void
tiff_io_error (const char *module,
               const char *fmt,
               va_list     ap)
{
  g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, fmt, ap);
}

static tsize_t
tiff_io_no_read (thandle_t handle,
                 tdata_t   buffer,
                 tsize_t   size)
{
  return (tsize_t) -1;
}

static tsize_t
tiff_io_read (thandle_t handle,
              tdata_t   buffer,
              tsize_t   size)
{
  TiffIO *io = (TiffIO *) handle;
  gsize read;

  if (io->position >= io->size)
    return 0;

  read = MIN (size, io->size - io->position);

  memcpy (buffer, io->data + io->position, read);
  io->position += read;

  return (tsize_t) read;
}

static tsize_t
tiff_io_no_write (thandle_t handle,
                  tdata_t   buffer,
                  tsize_t   size)
{
  return (tsize_t) -1;
}

static tsize_t
tiff_io_write (thandle_t handle,
               tdata_t   buffer,
               tsize_t   size)
{
  TiffIO *io = (TiffIO *) handle;

  if (io->position > io->size ||
      io->size - io->position < size)
    {
      io->size = io->position + size;
      io->data = g_realloc (io->data, io->size);
    }

  memcpy (io->data + io->position, buffer, size);
  io->position += size;

  return (tsize_t) size;
}

static toff_t
tiff_io_seek (thandle_t handle,
              toff_t    offset,
              int       whence)
{
  TiffIO *io = (TiffIO *) handle;

  switch (whence)
    {
    default:
      return -1;
    case SEEK_SET:
      break;
    case SEEK_CUR:
      offset += io->position;
      break;
    case SEEK_END:
      offset += io->size;
      break;
    }
  if (offset < 0)
    return -1;

  io->position = offset;

  return offset;
}

static int
tiff_io_close (thandle_t handle)
{
  TiffIO *io = (TiffIO *) handle;

  if (io->out_bytes)
    *io->out_bytes = g_bytes_new_take (io->data, io->size);

  g_free (io);

  return 0;
}

static toff_t
tiff_io_get_file_size (thandle_t handle)
{
  TiffIO *io = (TiffIO *) handle;

  return io->size;
}

static TIFF *
tiff_open_read (GBytes *bytes)
{
  TiffIO *io;

  TIFFSetWarningHandler ((TIFFErrorHandler) tiff_io_warning);
  TIFFSetErrorHandler ((TIFFErrorHandler) tiff_io_error);

  io = g_new0 (TiffIO, 1);

  io->data = (char *) g_bytes_get_data (bytes, &io->size);

  return TIFFClientOpen ("GTK-read""r",
                         (thandle_t) io,
                         tiff_io_read,
                         tiff_io_no_write,
                         tiff_io_seek,
                         tiff_io_close,
                         tiff_io_get_file_size,
                         NULL, NULL);
}

static TIFF *
tiff_open_write (GBytes **result)
{
  TiffIO *io;

  TIFFSetWarningHandler ((TIFFErrorHandler) tiff_io_warning);
  TIFFSetErrorHandler ((TIFFErrorHandler) tiff_io_error);

  io = g_new0 (TiffIO, 1);

  io->out_bytes = result;

  return TIFFClientOpen ("GTK-write""w",
                         (thandle_t) io,
                         tiff_io_no_read,
                         tiff_io_write,
                         tiff_io_seek,
                         tiff_io_close,
                         tiff_io_get_file_size,
                         NULL, NULL);
}

/* }}} */
/* {{{ Public API */

typedef struct _FormatData FormatData;
struct _FormatData {
  GdkMemoryFormat format;
  guint16 bits_per_sample;
  guint16 samples_per_pixel;
  guint16 sample_format;
  gint16 alpha_samples;
  guint16 photometric;
};

static const FormatData format_data[] = {
  [GDK_MEMORY_B8G8R8A8_PREMULTIPLIED]           = { GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,            84, SAMPLEFORMAT_UINT,   EXTRASAMPLE_ASSOCALPHA, PHOTOMETRIC_RGB },
  [GDK_MEMORY_A8R8G8B8_PREMULTIPLIED]           = { GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,            84, SAMPLEFORMAT_UINT,   EXTRASAMPLE_ASSOCALPHA, PHOTOMETRIC_RGB },
  [GDK_MEMORY_R8G8B8A8_PREMULTIPLIED]           = { GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,            84, SAMPLEFORMAT_UINT,   EXTRASAMPLE_ASSOCALPHA, PHOTOMETRIC_RGB },
  [GDK_MEMORY_A8B8G8R8_PREMULTIPLIED]           = { GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,            84, SAMPLEFORMAT_UINT,   EXTRASAMPLE_ASSOCALPHA, PHOTOMETRIC_RGB },
  [GDK_MEMORY_B8G8R8A8]                         = { GDK_MEMORY_R8G8B8A8,                          84, SAMPLEFORMAT_UINT,   EXTRASAMPLE_UNASSALPHA, PHOTOMETRIC_RGB },
  [GDK_MEMORY_A8R8G8B8]                         = { GDK_MEMORY_R8G8B8A8,                          84, SAMPLEFORMAT_UINT,   EXTRASAMPLE_UNASSALPHA, PHOTOMETRIC_RGB },
  [GDK_MEMORY_R8G8B8A8]                         = { GDK_MEMORY_R8G8B8A8,                          84, SAMPLEFORMAT_UINT,   EXTRASAMPLE_UNASSALPHA, PHOTOMETRIC_RGB },
  [GDK_MEMORY_A8B8G8R8]                         = { GDK_MEMORY_R8G8B8A8,                          84, SAMPLEFORMAT_UINT,   EXTRASAMPLE_UNASSALPHA, PHOTOMETRIC_RGB },
  [GDK_MEMORY_R8G8B8]                           = { GDK_MEMORY_R8G8B8,                            83, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_B8G8R8]                           = { GDK_MEMORY_R8G8B8,                            83, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_R8G8B8X8]                         = { GDK_MEMORY_R8G8B8X8,                          84, SAMPLEFORMAT_UINT,   0,                      PHOTOMETRIC_RGB },
  [GDK_MEMORY_X8R8G8B8]                         = { GDK_MEMORY_R8G8B8X8,                          84, SAMPLEFORMAT_UINT,   0,                      PHOTOMETRIC_RGB },
  [GDK_MEMORY_B8G8R8X8]                         = { GDK_MEMORY_R8G8B8X8,                          84, SAMPLEFORMAT_UINT,   0,                      PHOTOMETRIC_RGB },
  [GDK_MEMORY_X8B8G8R8]                         = { GDK_MEMORY_R8G8B8X8,                          84, SAMPLEFORMAT_UINT,   0,                      PHOTOMETRIC_RGB },
  [GDK_MEMORY_R16G16B16]                        = { GDK_MEMORY_R16G16B16,                        163, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_R16G16B16A16_PREMULTIPLIED]       = { GDK_MEMORY_R16G16B16A16_PREMULTIPLIED,       164, SAMPLEFORMAT_UINT,   EXTRASAMPLE_ASSOCALPHA, PHOTOMETRIC_RGB },
  [GDK_MEMORY_R16G16B16A16]                     = { GDK_MEMORY_R16G16B16A16,                     164, SAMPLEFORMAT_UINT,   EXTRASAMPLE_UNASSALPHA, PHOTOMETRIC_RGB },
  [GDK_MEMORY_R16G16B16_FLOAT]                  = { GDK_MEMORY_R16G16B16_FLOAT,                  163, SAMPLEFORMAT_IEEEFP, -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED] = { GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED, 164, SAMPLEFORMAT_IEEEFP, EXTRASAMPLE_ASSOCALPHA, PHOTOMETRIC_RGB },
  [GDK_MEMORY_R16G16B16A16_FLOAT]               = { GDK_MEMORY_R16G16B16A16_FLOAT,               164, SAMPLEFORMAT_IEEEFP, EXTRASAMPLE_UNASSALPHA, PHOTOMETRIC_RGB },
  [GDK_MEMORY_R32G32B32_FLOAT]                  = { GDK_MEMORY_R32G32B32_FLOAT,                  323, SAMPLEFORMAT_IEEEFP, -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED] = { GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED, 324, SAMPLEFORMAT_IEEEFP, EXTRASAMPLE_ASSOCALPHA, PHOTOMETRIC_RGB },
  [GDK_MEMORY_R32G32B32A32_FLOAT]               = { GDK_MEMORY_R32G32B32A32_FLOAT,               324, SAMPLEFORMAT_IEEEFP, EXTRASAMPLE_UNASSALPHA, PHOTOMETRIC_RGB },
  [GDK_MEMORY_G8A8_PREMULTIPLIED]               = { GDK_MEMORY_G8A8_PREMULTIPLIED,                82, SAMPLEFORMAT_UINT,   EXTRASAMPLE_ASSOCALPHA, PHOTOMETRIC_MINISBLACK },
  [GDK_MEMORY_G8A8]                             = { GDK_MEMORY_G8A8,                              82, SAMPLEFORMAT_UINT,   EXTRASAMPLE_UNASSALPHA, PHOTOMETRIC_MINISBLACK },
  [GDK_MEMORY_G8]                               = { GDK_MEMORY_G8,                                81, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_MINISBLACK },
  [GDK_MEMORY_G16A16_PREMULTIPLIED]             = { GDK_MEMORY_G16A16_PREMULTIPLIED,             162, SAMPLEFORMAT_UINT,   EXTRASAMPLE_ASSOCALPHA, PHOTOMETRIC_MINISBLACK },
  [GDK_MEMORY_G16A16]                           = { GDK_MEMORY_G16A16,                           162, SAMPLEFORMAT_UINT,   EXTRASAMPLE_UNASSALPHA, PHOTOMETRIC_MINISBLACK },
  [GDK_MEMORY_G16]                              = { GDK_MEMORY_G16,                              161, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_MINISBLACK },
  [GDK_MEMORY_A8]                               = { GDK_MEMORY_G8A8,                              82, SAMPLEFORMAT_UINT,   EXTRASAMPLE_UNASSALPHA, PHOTOMETRIC_MINISBLACK },
  [GDK_MEMORY_A16]                              = { GDK_MEMORY_G16A16,                           162, SAMPLEFORMAT_UINT,   EXTRASAMPLE_UNASSALPHA, PHOTOMETRIC_MINISBLACK },
  [GDK_MEMORY_A16_FLOAT]                        = { GDK_MEMORY_R16G16B16A16_FLOAT,               164, SAMPLEFORMAT_IEEEFP, EXTRASAMPLE_ASSOCALPHA, PHOTOMETRIC_RGB },
  [GDK_MEMORY_A32_FLOAT]                        = { GDK_MEMORY_R32G32B32A32_FLOAT,               324, SAMPLEFORMAT_IEEEFP, EXTRASAMPLE_ASSOCALPHA, PHOTOMETRIC_RGB },
  [GDK_MEMORY_G8_B8R8_420]                      = { GDK_MEMORY_R8G8B8,                            83, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_G8_R8B8_420]                      = { GDK_MEMORY_R8G8B8,                            83, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_G8_B8R8_422]                      = { GDK_MEMORY_R8G8B8,                            83, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_G8_R8B8_422]                      = { GDK_MEMORY_R8G8B8,                            83, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_G8_B8R8_444]                      = { GDK_MEMORY_R8G8B8,                            83, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_G8_R8B8_444]                      = { GDK_MEMORY_R8G8B8,                            83, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_G10X6_B10X6R10X6_420]             = { GDK_MEMORY_R16G16B16,                        163, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_G12X4_B12X4R12X4_420]             = { GDK_MEMORY_R16G16B16,                        163, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_G16_B16R16_420]                   = { GDK_MEMORY_R16G16B16,                        163, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_G8_B8_R8_410]                     = { GDK_MEMORY_R8G8B8,                            83, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_G8_R8_B8_410]                     = { GDK_MEMORY_R8G8B8,                            83, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_G8_B8_R8_411]                     = { GDK_MEMORY_R8G8B8,                            83, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_G8_R8_B8_411]                     = { GDK_MEMORY_R8G8B8,                            83, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_G8_B8_R8_420]                     = { GDK_MEMORY_R8G8B8,                            83, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_G8_R8_B8_420]                     = { GDK_MEMORY_R8G8B8,                            83, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_G8_B8_R8_422]                     = { GDK_MEMORY_R8G8B8,                            83, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_G8_R8_B8_422]                     = { GDK_MEMORY_R8G8B8,                            83, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_G8_B8_R8_444]                     = { GDK_MEMORY_R8G8B8,                            83, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_G8_R8_B8_444]                     = { GDK_MEMORY_R8G8B8,                            83, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_G8B8G8R8_422]                     = { GDK_MEMORY_R8G8B8,                            83, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_G8R8G8B8_422]                     = { GDK_MEMORY_R8G8B8,                            83, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_R8G8B8G8_422]                     = { GDK_MEMORY_R8G8B8,                            83, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_B8G8R8G8_422]                     = { GDK_MEMORY_R8G8B8,                            83, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_X6G10_X6B10_X6R10_420]            = { GDK_MEMORY_R16G16B16,                        163, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_X6G10_X6B10_X6R10_422]            = { GDK_MEMORY_R16G16B16,                        163, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_X6G10_X6B10_X6R10_444]            = { GDK_MEMORY_R16G16B16,                        163, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_X4G12_X4B12_X4R12_420]            = { GDK_MEMORY_R16G16B16,                        163, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_X4G12_X4B12_X4R12_422]            = { GDK_MEMORY_R16G16B16,                        163, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_X4G12_X4B12_X4R12_444]            = { GDK_MEMORY_R16G16B16,                        163, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_G16_B16_R16_420]                  = { GDK_MEMORY_R16G16B16,                        163, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_G16_B16_R16_422]                  = { GDK_MEMORY_R16G16B16,                        163, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_G16_B16_R16_444]                  = { GDK_MEMORY_R16G16B16,                        163, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_ARGB2101010_PREMULTIPLIED]        = { GDK_MEMORY_R16G16B16A16_PREMULTIPLIED,       164, SAMPLEFORMAT_UINT,   EXTRASAMPLE_ASSOCALPHA, PHOTOMETRIC_RGB },
  [GDK_MEMORY_ARGB2101010]                      = { GDK_MEMORY_R16G16B16A16,                     164, SAMPLEFORMAT_UINT,   EXTRASAMPLE_UNASSALPHA, PHOTOMETRIC_RGB },
  [GDK_MEMORY_XRGB2101010]                      = { GDK_MEMORY_R16G16B16,                        163, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
  [GDK_MEMORY_ABGR2101010_PREMULTIPLIED]        = { GDK_MEMORY_R16G16B16A16_PREMULTIPLIED,       164, SAMPLEFORMAT_UINT,   EXTRASAMPLE_ASSOCALPHA, PHOTOMETRIC_RGB },
  [GDK_MEMORY_ABGR2101010]                      = { GDK_MEMORY_R16G16B16A16,                     164, SAMPLEFORMAT_UINT,   EXTRASAMPLE_UNASSALPHA, PHOTOMETRIC_RGB },
  [GDK_MEMORY_XBGR2101010]                      = { GDK_MEMORY_R16G16B16,                        163, SAMPLEFORMAT_UINT,   -1,                     PHOTOMETRIC_RGB },
};

/* if this fails, somebody forgot to add formats above */
G_STATIC_ASSERT (G_N_ELEMENTS (format_data) == GDK_MEMORY_N_FORMATS);

GBytes *
gdk_save_tiff (GdkTexture *texture)
{
  TIFF *tif;
  int width, height;
  gsize stride;
  const guchar *line;
  const guchar *data;
  GBytes *bytes, *result = NULL;
  GdkTextureDownloader downloader;
  GdkMemoryFormat format;
  const FormatData *fdata = NULL;

  tif = tiff_open_write (&result);

  width = gdk_texture_get_width (texture);
  height = gdk_texture_get_height (texture);
  format = gdk_texture_get_format (texture);
  fdata = &format_data[format];

  if (fdata == NULL)
    fdata = &format_data[0];

  TIFFSetField (tif, TIFFTAG_SOFTWARE, "GTK");
  TIFFSetField (tif, TIFFTAG_IMAGEWIDTH, width);
  TIFFSetField (tif, TIFFTAG_IMAGELENGTH, height);
  TIFFSetField (tif, TIFFTAG_BITSPERSAMPLE, fdata->bits_per_sample);
  TIFFSetField (tif, TIFFTAG_SAMPLESPERPIXEL, fdata->samples_per_pixel);
  TIFFSetField (tif, TIFFTAG_SAMPLEFORMAT, fdata->sample_format);
  TIFFSetField (tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
  TIFFSetField (tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
  if (fdata->alpha_samples >= 0)
    TIFFSetField (tif, TIFFTAG_EXTRASAMPLES, 1, &fdata->alpha_samples);

  TIFFSetField (tif, TIFFTAG_PHOTOMETRIC, fdata->photometric);
  TIFFSetField (tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);

  gdk_texture_downloader_init (&downloader, texture);
  gdk_texture_downloader_set_format (&downloader, fdata->format);
  bytes = gdk_texture_downloader_download_bytes (&downloader, &stride);
  gdk_texture_downloader_finish (&downloader);
  data = g_bytes_get_data (bytes, NULL);

  line = (const guchar *)data;
  for (int y = 0; y < height; y++)
    {
      if (TIFFWriteScanline (tif, (void *)line, y, 0) == -1)
        {
          TIFFClose (tif);
          g_bytes_unref (bytes);
          return NULL;
        }

      line += stride;
    }

  TIFFFlushData (tif);
  TIFFClose (tif);

  g_assert (result);

  g_bytes_unref (bytes);

  return result;
}

static GdkTexture *
load_fallback (TIFF    *tif,
               GError **error)
{
  int width, height;
  guchar *data;
  GBytes *bytes;
  GdkTexture *texture;

  TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &width);
  TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &height);

  data = g_malloc (width * height * 4);

  if (!TIFFReadRGBAImageOriented (tif, width, height, (guint32 *)data, ORIENTATION_TOPLEFT, 1))
    {
      g_set_error_literal (error,
                           GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_CORRUPT_IMAGE,
                           _("Failed to load RGB data from TIFF file"));
      g_free (data);
      return NULL;
    }

  bytes = g_bytes_new_take (data, width * height * 4);

  texture = gdk_memory_texture_new (width, height,
                                    GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
                                    bytes,
                                    width * 4);

  g_bytes_unref (bytes);

  return texture;
}

GdkTexture *
gdk_load_tiff (GBytes  *input_bytes,
               GError **error)
{
  TIFF *tif;
  guint16 samples_per_pixel;
  guint16 bits_per_sample;
  guint16 photometric;
  guint16 planarconfig;
  guint16 sample_format;
  guint16 orientation;
  guint32 width, height;
  gint16 alpha_samples;
  GdkMemoryFormat format;
  GdkMemoryLayout layout;
  guchar *data, *line;
  GBytes *bytes;
  GdkTexture *texture;
  G_GNUC_UNUSED gint64 before = GDK_PROFILER_CURRENT_TIME;

  tif = tiff_open_read (input_bytes);
  if (!tif)
    {
      g_set_error_literal (error,
                           GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_CORRUPT_IMAGE,
                           _("Could not load TIFF data"));
      return NULL;
    }

  TIFFSetDirectory (tif, 0);

  TIFFGetFieldDefaulted (tif, TIFFTAG_SAMPLESPERPIXEL, &samples_per_pixel);
  TIFFGetFieldDefaulted (tif, TIFFTAG_BITSPERSAMPLE, &bits_per_sample);
  TIFFGetFieldDefaulted (tif, TIFFTAG_SAMPLEFORMAT, &sample_format);
  TIFFGetFieldDefaulted (tif, TIFFTAG_PHOTOMETRIC, &photometric);
  TIFFGetFieldDefaulted (tif, TIFFTAG_PLANARCONFIG, &planarconfig);
  TIFFGetFieldDefaulted (tif, TIFFTAG_ORIENTATION, &orientation);
  TIFFGetFieldDefaulted (tif, TIFFTAG_IMAGEWIDTH, &width);
  TIFFGetFieldDefaulted (tif, TIFFTAG_IMAGELENGTH, &height);

  if (samples_per_pixel == 2 || samples_per_pixel == 4)
    {
      guint16 extra;
      guint16 *extra_types;

      if (TIFFGetField (tif, TIFFTAG_EXTRASAMPLES, &extra, &extra_types))
        alpha_samples = extra_types[0];
      else
        alpha_samples = -1;

      if (alpha_samples >= 0 && alpha_samples != EXTRASAMPLE_ASSOCALPHA && alpha_samples != EXTRASAMPLE_UNASSALPHA && alpha_samples != 0)
        {
          texture = load_fallback (tif, error);
          TIFFClose (tif);
          return texture;
        }
    }
  else
    alpha_samples = -1;

  for (format = 0; format < G_N_ELEMENTS (format_data); format++)
    {
      /* not a native format */
      if (format_data[format].format != format)
        continue;

      if (format_data[format].sample_format == sample_format &&
          format_data[format].bits_per_sample == bits_per_sample &&
          format_data[format].samples_per_pixel == samples_per_pixel &&
          format_data[format].alpha_samples == alpha_samples &&
          format_data[format].photometric == photometric)
        {
          break;
        }
    }

  if (format == G_N_ELEMENTS(format_data) ||
      (photometric != PHOTOMETRIC_RGB && photometric != PHOTOMETRIC_MINISBLACK) ||
      planarconfig != PLANARCONFIG_CONTIG ||
      TIFFIsTiled (tif) ||
      orientation != ORIENTATION_TOPLEFT)
    {
      texture = load_fallback (tif, error);
      TIFFClose (tif);
      return texture;
    }

  if (!gdk_memory_layout_try_init (&layout, format, width, height, 1) ||
      !(data = g_try_malloc (layout.size)))
    {
      g_set_error (error,
                   GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_TOO_LARGE,
                   _("Not enough memory for image size %ux%u"), width, height);
      TIFFClose (tif);
      return NULL;
    }

  g_assert (TIFFScanlineSize (tif) == layout.planes[0].stride);

  line = data + layout.planes[0].offset;
  for (int y = 0; y < height; y++)
    {
      if (TIFFReadScanline (tif, line, y, 0) == -1)
        {
          g_set_error (error,
                       GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_CORRUPT_IMAGE,
                       _("Reading data failed at row %d"), y);
          TIFFClose (tif);
          g_free (data);
          return NULL;
        }

      line += layout.planes[0].stride;
    }

  bytes = g_bytes_new_take (data, layout.size);
  texture = gdk_memory_texture_new_from_layout (bytes,
                                                &layout,
                                                gdk_color_state_get_srgb (),
                                                NULL, NULL);
  g_bytes_unref (bytes);

  TIFFClose (tif);

  if (GDK_PROFILER_IS_RUNNING)
    {
      gint64 end = GDK_PROFILER_CURRENT_TIME;
      if (end - before > 500000)
        gdk_profiler_add_mark (before, end - before, "Load tiff", NULL);
    }

  return texture;
}

/* }}} */

/* vim:set foldmethod=marker: */

Messung V0.5 in Prozent
C=99 H=98 G=98

¤ Dauer der Verarbeitung: 0.17 Sekunden  (vorverarbeitet am  2026-07-03) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.