User:AtteSmythe/yppRAW/yppRAWrd.c

From YPPedia
/* bmpread.c	reads any bitmap I could get for testing */
/* Alexander.Schulz@stud.uni-karlsruhe.de                */

/*
 * The GIMP -- an image manipulation program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * 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; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 * ----------------------------------------------------------------------------
 * Modified - atteSmythe@atteSmythe.com - 10 Aug 05
 */

#include "config.h"

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

#include <gtk/gtk.h>

#include <libgimp/gimp.h>

#include "yppRAW.h"

#include "libgimp/stdplugins-intl.h"
#if !defined(WIN32) || defined(__MINGW32__)
#define BI_RGB 		0
#define BI_RLE8  	1
#define BI_RLE4  	2
#define BI_BITFIELDS  	3
#else
#include <windows.h>
#endif

static gint32 ReadImage (
                         FILE     *fd,
                         guint    width,
                         guint    height,
                         guchar   *alpha,
                         guchar   **palette,
                         guint    colors
                         );

static gint32
ToL (const guchar *puffer)
{
  return (puffer[3] | puffer[2] << 8 | puffer[1] << 16 | puffer[0] << 24);
}

static gint16
ToS (const guchar *puffer)
{
  return (puffer[1] | puffer[0] << 8);
}

static gboolean
ReadPalette(FILE *fd, guchar *alpha, guchar **colors, guint entries) {
  guint i;
  guchar ABGR[4];

  for (i=0; i < entries; ++i) {
    if (!ReadOK (fd, ABGR, sizeof(ABGR))) {
      g_message(_("Palette Incomplete"));
      return FALSE;
    }
// Since we want to do A(RGB), not A(BGR), we'll have to swap here,
// so as only to swap once.
    alpha[i]     = ABGR[0];
    colors[0][i] = ABGR[1];
    colors[1][i] = ABGR[2];
    colors[2][i] = ABGR[3];
  }

  return TRUE;
}
/*

static gboolean
ReadColorMap (FILE     *fd,
	      guchar    buffer[256][3],
	      gint      number,
	      gint      size,
	      gboolean *grey)
{
  gint   i;
  guchar rgb[4];
  
  *grey = (number > 2);
  
  for (i = 0; i < number ; i++)
  {
    if (!ReadOK (fd, rgb, size))
    {
      g_message (_("Bad colormap"));
      return FALSE;
    }
    
    // Bitmap save the colors in another order! But change only once!
    
    buffer[i][0] = rgb[2];
    buffer[i][1] = rgb[1];
    buffer[i][2] = rgb[0];
    *grey = ((*grey) && (rgb[0]==rgb[1]) && (rgb[1]==rgb[2]));
  }
  return TRUE;
}
static gboolean
ReadChannelMasks (FILE *fd, Bitmap_Channel *masks, guint channels)
{
  guint32 tmp[3];
  guint32 mask;
  gint    nbits, offset, bit;
  guint   i;

  if (!ReadOK (fd, tmp, 3 * sizeof (guint32)))
    return FALSE;

  for (i = 0; i < channels; i++)
    {
      mask = ToL ((guchar*) &tmp[i]);
      masks[i].mask = mask;
      nbits = 0;
      offset = -1;
      for (bit = 0; bit < 32; bit++)
        {
          if (mask & 1)
            {
              nbits++;
              if (offset == -1)
                offset = bit;
            }
          mask = mask >> 1;
        }
      masks[i].shiftin = offset;
      masks[i].shiftout = 8 - nbits;
#ifdef DEBUG
      g_print ("Channel %d mask %08x in %d out %d\n", i, masks[i].mask, masks[i].shiftin, masks[i].shiftout);
#endif
    }
  return TRUE;
}
*/
gint32
ReadRAW (const gchar *name)
{
  FILE     *fd;
  gchar    *temp_buf;

  struct RAW_File_Head_Struct {
    _int32 Xsize;
    _int32 Ysize;
    _int32 PaletteUsed;
    _int32 PaletteSize;
  } RAW_File_Head;
 
  guchar    *palAlpha;
  guchar    **palColors;
  gint32    image_ID;

  gint      i;

  filename = name;
  fd = fopen (filename, "rb");
  
  if (!fd) {
    g_message (_("Could not open '%s' for reading: %s"),
      gimp_filename_to_utf8 (filename), g_strerror (errno));
    return -1;
  }
  
  temp_buf = g_strdup_printf (_("Opening '%s'..."),
    gimp_filename_to_utf8 (name));
  gimp_progress_init (temp_buf);
  g_free (temp_buf);
  
  // It is a File. Now is it a valid RAWfile? Read the shortest possible header
  
  if (!ReadOK (fd, &RAW_File_Head, sizeof(RAW_File_Head))) {
    g_message (_("Could not read file header in '%s'"),
      gimp_filename_to_utf8 (filename));
    return -1;
  }
  
  RAW_File_Head.Xsize = ToL((unsigned char*)&RAW_File_Head.Xsize);
  RAW_File_Head.Ysize = ToL((unsigned char*)&RAW_File_Head.Ysize);
  RAW_File_Head.PaletteUsed = ToL((unsigned char *)&RAW_File_Head.PaletteUsed);
  RAW_File_Head.PaletteSize = ToL((unsigned char *)&RAW_File_Head.PaletteSize);

  if (RAW_File_Head.PaletteSize < RAW_File_Head.PaletteUsed) {
    g_message (_("'%s' is not a valid Y!PP RAW file"),
      gimp_filename_to_utf8 (filename));
    return -1;
  }
  
  // How about a palette? I'd like a palette. And an alpha palette!
  
  // First check for no colors...
  if (RAW_File_Head.PaletteSize == 0 || 
      RAW_File_Head.Xsize == 0 ||
      RAW_File_Head.Ysize == 0) {
    g_message (_("Error reading Y!PP RAW file header from '%s'"),
               gimp_filename_to_utf8(filename));
    return -1;
  }

  palAlpha = (guchar*)g_malloc(RAW_File_Head.PaletteSize);
  palColors = (guchar**)g_malloc(sizeof(unsigned char*[3]));
  for (i=0; i<3; ++i) {
    palColors[i] = (guchar*)g_malloc(RAW_File_Head.PaletteSize);
  }

  if (!ReadPalette(fd, palAlpha, palColors, RAW_File_Head.PaletteSize)) {
    g_message (_("'%s' is not a valid Y!PP RAW file"),
               gimp_filename_to_utf8 (filename));
    return -1;
  }

  

  // Get the Image and return the ID or -1 on error
  image_ID = ReadImage (fd,
    RAW_File_Head.Xsize,
    RAW_File_Head.Ysize,
    palAlpha,
    palColors,
    RAW_File_Head.PaletteSize
    );

  g_free(palAlpha);
  for (i=0; i<3; ++i) {
    g_free(palColors[i]);
  }
  g_free(palColors);
  return image_ID;
}

static gint32
ReadImage (
           FILE     *fd,
           guint    width,
           guint    height,
           guchar   *alpha,
           guchar   **palette,
           guint    colors
           )
{
  /*
  guchar        v, n;
  guchar       *dest, *temp, *buffer;
  guchar        gimp_cmap[768];
  gushort       rgb;
  glong         rowstride, channels;
  */
  gint32        image;
  gint32        layer;
  glong         rowstride, channels;
  GimpPixelRgn  pixel_rgn;
  GimpDrawable *drawable;

  guchar       *dest, *temp, *buffer;
  gint          cur_progress, max_progress;
  guint          xpos, ypos;
  guint         cidx;

  // Create an image in the GIMP
  image = gimp_image_new (width, height, GIMP_RGB);
  layer = gimp_layer_new (image, _("Background"),
    width, height,
    GIMP_RGBA_IMAGE, 100, GIMP_NORMAL_MODE);

  channels = 4; // RGB+A
  
  gimp_image_set_filename (image, filename);
  
  gimp_image_add_layer (image, layer, 0);
  drawable = gimp_drawable_get (layer);
  
  // create a temporary, uncompressed version from which to transfer to GIMP
  dest      = g_malloc (drawable->width * drawable->height * channels);
  // read buffer - size = 1 row of _source_
  buffer    = g_malloc (drawable->width);
  // how far to advance the pointer into the dest array each iteration
  rowstride = drawable->width * channels;
  
  cur_progress = 0;
  max_progress = height;

  for (ypos=0; ypos < height; ++ypos) {
    if (!ReadOK(fd,buffer,drawable->width)) { break; }

    temp = dest + ypos*rowstride;
    for (xpos=0; xpos < width; ++xpos) {
      cidx = buffer[xpos];
      *(temp++)=palette[0][cidx]; // R
      *(temp++)=palette[1][cidx]; // G
      *(temp++)=palette[2][cidx]; // B
      *(temp++)=alpha[cidx];      // A
    }
    ++cur_progress;
    if ((cur_progress %5) == 0) {
      gimp_progress_update((gdouble) cur_progress / (gdouble)max_progress);
    }
  }

  
  fclose (fd);
    
  gimp_progress_update (1);
  
  gimp_pixel_rgn_init (&pixel_rgn, drawable,
    0, 0, drawable->width, drawable->height, TRUE, FALSE);
  gimp_pixel_rgn_set_rect (&pixel_rgn, dest,
    0, 0, drawable->width, drawable->height);
  
  gimp_drawable_flush (drawable);
  gimp_drawable_detach (drawable);
  g_free (dest);
  g_free (buffer);

  return image;
}