Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Gimp/plug-ins/file-dds/   (Gimp Bildeditor Version 3.2.0©)  Datei vom 14.2.2026 mit Größe 10 kB image not shown  

Quelle  bc7.c   Sprache: C

 

/*
 * DDS GIMP plugin
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program 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
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING.  If not, write to
 * the Free Software Foundation, 51 Franklin Street, Fifth Floor
 * Boston, MA 02110-1301, USA.
 */


/* ImageMagick's implementation of BC7 was referenced for our implementation.
 * The relevant commit: https://github.com/ImageMagick/ImageMagick/pull/4126/files
 */


#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <glib.h>

#include <libgimp/gimp.h>

#include "bc7.h"

#define SWAP(a, b)  do { typeof(a) t; t = a; a = b; b = t; } while(0)

static guchar    get_bits             (const guchar *block,
                                       guchar       *start_bit,
                                       guchar        length);

static void      decode_rgba_channels (BC7_colors   *colors,
                                       guchar       *src,
                                       guint         mode,
                                       guchar       *start);

static gboolean  is_pixel_anchor      (guchar        subset_index,
                                       guint         precision,
                                       guchar        pixel_index,
                                       guint         partition_id);


gint
bc7_decompress (guchar *src,
                guint   size,
                guchar *block)
{
  /* BC7 blocks are always 16 bytes */
  guchar     s[16];
  BC7_colors colors;
  guchar     rgb_indexes[16];
  guchar     alpha_indexes[16];
  guchar     subset_indexes[16];
  guchar     rgba[4];
  guint      mode             = 0;
  guint      subset_count     = 0;
  guint      partition_id     = 0;
  guint      swap             = 0;
  guint      selector         = 0;
  guchar     current_bit      = 0;
  guint      i_precision      = 0;
  guint      no_sel_precision = 0;

  for (gint i = 0; i < 16; i++)
    s[i] = src[i];

  /* BC7 blocks are read from the last bit of the last byte, backwards.
   * The mode is determined by the first 1 bit encountered. For instance,
   * 1 is mode 0, 10 is mode 1, 100 is mode 2, and so on. */

  while (current_bit <= 8 && ! get_bits (s, ¤t_bit, 1))
    {
      continue;
    }
  mode = current_bit - 1;

  if (mode > 7)
    return 0;

  /* For modes that support partitions, we start counting
   * from left of the mode bit, and get the partition ID.
   * The size of the partition ID is defined by the mode. */

  subset_count = mode_info[mode].subset_count;
  if (subset_count > 1)
    {
      partition_id = get_bits (s, ¤t_bit,
                               mode_info[mode].partition_bits);

      if (partition_id > 63)
        return 0;
    }

  /* Mode 4 and 5 might swap channels for better compression. 2 bits after the mode bit
   * indicate which were swapped (if any) */

  if (mode == 4 || mode == 5)
    swap = get_bits (s, ¤t_bit, 2);

  /* Mode 4 also has a single selector bit, to the left of its swap bits.
   * This bit determines where the alpha channel indexes are located. */

  if (mode == 4)
    selector = get_bits (s, ¤t_bit, 1);

  /* Channel values are stored in RnGnBn(An) format, where the mode determines
   * how many bits of precision and how many values are stored. */

  decode_rgba_channels (&colors, s, mode, ¤t_bit);

  /* Next, we get the indexes to assemble pixels from the channel values. */
  i_precision      = mode_info[mode].index_precision;
  no_sel_precision = mode_info[mode].no_sel_precision;

  if (mode == 4 && selector)
    {
      i_precision      = 3;
      alpha_indexes[0] = get_bits (s, ¤t_bit, 1);

      for (gint i = 1; i < 16; i++)
        alpha_indexes[i] = get_bits (s, ¤t_bit, 2);
    }

  /* First, calculate the RGB channel indexes based on the partition ID
   * and the number of subsets.  */

  for (gint i = 0; i < 16; i++)
    {
      guint precision = i_precision;

      if (subset_count == 2)
        subset_indexes[i] = partition_table[0][partition_id][i];
      else if (subset_count == 3)
        subset_indexes[i] = partition_table[1][partition_id][i];
      else
        subset_indexes[i] = 0;

      if (is_pixel_anchor (subset_indexes[i], subset_count, i, partition_id))
        precision--;

      rgb_indexes[i]= get_bits (s, ¤t_bit, precision);
    }

  if (mode == 5 || (mode == 4 && ! selector))
    {
      alpha_indexes[0] = get_bits (s, ¤t_bit, no_sel_precision - 1);

      for (gint i = 1; i < 16; i++)
        alpha_indexes[i] = get_bits (s, ¤t_bit, no_sel_precision);
    }

  /* Create pixels from subset indexes */
  for (gint i = 0; i < 16; i++)
    {
      guint  weight;
      guint  c0 = 2 * subset_indexes[i];
      guint  c1 = (2 * subset_indexes[i]) + 1;

      if (i_precision == 2)
        weight = weight_2[rgb_indexes[i]];
      else if (i_precision == 3)
        weight = weight_3[rgb_indexes[i]];
      else
        weight = weight_4[rgb_indexes[i]];

      rgba[0] = ((64 - weight) * colors.r[c0] + weight * colors.r[c1] + 32) >> 6;
      rgba[1] = ((64 - weight) * colors.g[c0] + weight * colors.g[c1] + 32) >> 6;
      rgba[2] = ((64 - weight) * colors.b[c0] + weight * colors.b[c1] + 32) >> 6;

      if (mode == 4 || mode == 5)
        {
          weight = weight_2[alpha_indexes[i]];

          if (mode == 4 && ! selector)
            weight = weight_3[alpha_indexes[i]];
        }
      rgba[3] = ((64 - weight) * colors.a[c0] + weight * colors.a[c1] + 32) >> 6;

      switch (swap)
        {
          case 1:
            SWAP (rgba[3], rgba[0]);
            break;
          case 2:
            SWAP (rgba[3], rgba[1]);
            break;
          case 3:
            SWAP (rgba[3], rgba[2]);
            break;
          default:
            break;
         }

      for (gint j = 0; j < 4; j++)
        block[(i * 4) + j] = rgba[j];
    }

  return 1;
}


/* Private Functions */

static guchar
get_bits (const guchar *block,
          guchar       *start_bit,
          guchar        length)
{
  guchar bits;
  guint  index;
  guint  base;
  guint  first_bits;
  guint  next_bits;

  index = (*start_bit) >> 3;
  base  = (*start_bit) - (index << 3);

  if (index > 15)
    return 0;

  if (base + length > 8)
    {
      first_bits = 8 - base;
      next_bits  = length - first_bits;

      bits = block[index] >> base;
      bits |= (block[index + 1] & ((1 << next_bits) - 1)) << first_bits;
    }
  else
    {
      bits = (block[index] >> base) & ((1 << length) - 1);
    }
  (*start_bit) += length;

  return bits;
}

static void
decode_rgba_channels (BC7_colors *colors,
                      guchar     *src,
                      guint       mode,
                      guchar     *start)
{
  guint channel_count   = mode_info[mode].subset_count * 2;
  guint rgb_precision   = mode_info[mode].rgb_precision;
  guint alpha_precision = mode_info[mode].alpha_precision;

  /* Get RGB channel values */
  for (gint i = 0; i < channel_count; i++)
    colors->r[i] = get_bits (src, start, rgb_precision);

  for (gint i = 0; i < channel_count; i++)
    colors->g[i] = get_bits (src, start, rgb_precision);

  for (gint i = 0; i < channel_count; i++)
    colors->b[i] = get_bits (src, start, rgb_precision);

  /* Modes 4 - 7 also have alpha values */
  if (alpha_precision)
    {
      for (gint i = 0; i < channel_count; i++)
        colors->a[i] = get_bits (src, start, alpha_precision);
    }
  else
    {
      for (gint i = 0; i < channel_count; i++)
        colors->a[i] = 255;
    }

  /* Modes 0, 1, 3, 6, and 7 have P-bits, which increase the precision
   * by 1. */

  if (mode_info[mode].p_bit_count)
    {
      rgb_precision++;
      if (alpha_precision)
        alpha_precision++;

      /* P-bits are added at the least significant bit, so
       * we have to shift existing channel values over by 1 */

      for (gint i = 0; i < channel_count; i++)
        {
          colors->r[i] <<= 1;
          colors->g[i] <<= 1;
          colors->b[i] <<= 1;
          if (alpha_precision)
            colors->a[i] <<= 1;
        }

      if (mode == 1)
        {
          guint p_bit_1 = get_bits (src, start, 1);
          guint p_bit_2 = get_bits (src, start, 1);

          for (gint i = 0; i < 2; i++)
            {
              colors->r[i] |= p_bit_1;
              colors->g[i] |= p_bit_1;
              colors->b[i] |= p_bit_1;

              colors->r[i + 2] |= p_bit_2;
              colors->g[i + 2] |= p_bit_2;
              colors->b[i + 2] |= p_bit_2;
            }
        }
      else
        {
          for (gint i = 0; i < channel_count; i++)
            {
              guint p_bit = get_bits (src, start, 1);

              colors->r[i] |= p_bit;
              colors->g[i] |= p_bit;
              colors->b[i] |= p_bit;
              if (alpha_precision)
                colors->a[i] |= p_bit;
            }
        }
    }

  /* Normalize all channel values to 8 bits */
  for (gint i = 0; i < channel_count; i++)
    {
      colors->r[i] <<= (8 - rgb_precision);
      colors->g[i] <<= (8 - rgb_precision);
      colors->b[i] <<= (8 - rgb_precision);

      colors->r[i] = colors->r[i] | (colors->r[i] >> rgb_precision);
      colors->g[i] = colors->g[i] | (colors->g[i] >> rgb_precision);
      colors->b[i] = colors->b[i] | (colors->b[i] >> rgb_precision);

      if (alpha_precision)
        {
          colors->a[i] <<= (8 - alpha_precision);
          colors->a[i] = colors->a[i] | (colors->a[i] >> alpha_precision);
        }
    }
}

static gboolean
is_pixel_anchor (guchar  subset_index,
                 guint   precision,
                 guchar  pixel_index,
                 guint   partition_id)
{
  guint table_index;

  if (subset_index == 0)
    table_index = 0;
  else if (subset_index == 1 && precision == 2)
    table_index = 1;
  else if (subset_index == 1 && precision == 3)
    table_index = 2;
  else
    table_index = 3;

  if (anchor_index_table[table_index][partition_id] == pixel_index)
    return TRUE;

  return FALSE;
}

Messung
CHZG
829610092

¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


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.