Logo Search packages:      
Sourcecode: lebiniou version File versions  Download package

picture_8bits.c

/*
 *  Copyright 1994-2011 Olivier Girondel
 *
 *  This file is part of lebiniou.
 *
 *  lebiniou 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.
 *
 *  lebiniou 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 lebiniou. If not, see <http://www.gnu.org/licenses/>.
 */

#include <libswscale/swscale.h>
#include "picture_8bits.h"
#include "pnglite.h"


Picture8_t *
Picture8_new()
{
  Picture8_t *p = NULL;

  p = xcalloc(1, sizeof(Picture8_t));
  
  p->id = -1;
  p->buff = Buffer8_new();

  return p;
}


void
Picture8_delete(Picture8_t *p)
{
  xfree(p->name);
  xfree(p->dname);

  if (p->buff)
    Buffer8_delete(p->buff);
  xfree(p);
}


static Pixel_t
rgb2y(const u_char r, const u_char g, const u_char b)
{
  float sum = 0.0;

  sum += (r * 0.299);
  sum += (g * 0.587);
  sum += (b * 0.114);

  return (Pixel_t)sum;
}


static Pixel_t *
PNG_to_Y(const png_t *png, const u_char *src)
{
  Pixel_t *res = NULL, *dst = NULL;
  size_t size, i;

  size = png->width * png->height;
  res = xmalloc(size*sizeof(Pixel_t));
  dst = res;

  switch (png->color_type) {
  case PNG_GREYSCALE:
    memcpy(dst, (const void *)src, size*sizeof(Pixel_t));
    break;

  case PNG_TRUECOLOR:
    for (i = 0; i < size; i++, dst++) {
      char r, g, b;

      r = *src++; g = *src++; b = *src++;
      *dst = rgb2y(r, g, b);
    }
    break;

  case PNG_INDEXED:
    /* TODO: unhandled ? */
    xerror("PNG_to_Y: PNG_INDEXED not yet implemented\n");
    break;

  case PNG_GREYSCALE_ALPHA:
    for (i = 0; i < size; i++, dst++) {
      char y;

      y = *src++;
      src++; /* Skip alpha component */
      *dst = y;
    }
    break;

  case PNG_TRUECOLOR_ALPHA:
    for (i = 0; i < size; i++, dst++) {
      char r, g, b;

      r = *src++; g = *src++; b = *src++;
      src++; /* Skip alpha component */
      *dst = rgb2y(r, g, b);
    }
    break;

  default:
    xerror("PNG_to_Y: unknown color_type= %d\n", png->color_type);
  }
  
  return res;
}


static Pixel_t *
rescale(const png_t *png, Pixel_t *src, const u_short dst_width, const u_short dst_height)
{
  Pixel_t *res = NULL;
  struct SwsContext *sws_context = NULL;
  int srcStride[4]={0,0,0,0}, dstStride[4]={0,0,0,0};
  uint8_t *srcSlice[4]={NULL,NULL,NULL,NULL}, *dst[4]={NULL,NULL,NULL,NULL};
  int ret;

  res = xmalloc(dst_width*dst_height*sizeof(Pixel_t));
  sws_context = sws_getContext(png->width, png->height, PIX_FMT_GRAY8,
                         dst_width, dst_height, PIX_FMT_GRAY8,
                         SWS_FAST_BILINEAR, NULL, NULL, NULL);
  if (NULL == sws_context)
    xerror("sws_getContext\n");

  srcStride[0] = png->width;
  dstStride[0] = dst_width;
  srcSlice[0] = src;
  dst[0] = res;

  ret = sws_scale(sws_context, (const uint8_t * const *)srcSlice, srcStride, 0, png->height, dst, dstStride);
  if (ret < 0)
    xerror("sws_scale\n");

  sws_freeContext(sws_context);

  return res;
}


static int
Picture8_load_PNG(Picture8_t *pic, const char *filename)
{
  png_t png;
  int res;

  res = png_open_file_read(&png, filename);
  if (PNG_NO_ERROR == res) {
    u_char *data = NULL;
    size_t size;

#ifdef XDEBUG
    printf("%s: ", filename);
    png_print_info(&png);
#endif
    size = png.width * png.height * png.bpp;
    data = xmalloc(size*sizeof(u_char));
    
    res = png_get_data(&png, data);
    if (PNG_NO_ERROR == res) {
      Pixel_t *y = NULL;
      Pixel_t *dst = pic->buff->buffer;
      xfree(dst);
      y = PNG_to_Y(&png, data);
      xfree(data);

      if ((png.width != WIDTH) || (png.height != HEIGHT)) {
      Pixel_t *scaled = rescale(&png, y, WIDTH, HEIGHT);
      xfree(y);
      pic->buff->buffer = scaled;
      } else {
      pic->buff->buffer = y;
      }
      Buffer8_flip_x(pic->buff);
    } else {
      static int verbose = 1;

      fprintf(stderr, "[!] png_get_data: %s (%s)\n", png_error_string(res), filename);
      if (verbose) {
      fprintf(stderr, "[!] if this is an indexed PNG, convert it to non-indexed\n");
      fprintf(stderr, "[!] also, remove any comments from the PNG\n");
      verbose = 0;
      }
      xfree(data);
      png_close_file(&png);

      return -1;
    }
  } else {
    fprintf(stderr, "[!] png_open_file_read: %s (%s)\n", png_error_string(res), filename);
    if (PNG_FILE_ERROR != res)
      png_close_file(&png);

    return -1;
  }

  png_close_file(&png);

  return 0;
}


int
Picture8_load(Picture8_t *pic, const long id, const char *dir, const char *filename)
{
  char *file = g_strdup_printf("%s/%s", dir, filename);

  if (Picture8_load_PNG(pic, file) != 0) {
    g_free(file);
    return (-1);
  }
  g_free(file);

  xfree(pic->name);
  pic->name = strdup(filename);
  xfree(pic->dname);
  pic->dname = strdup(pic->name);
  
  if ((file = strchr(pic->dname, '.')) != NULL)
    *file = '\0'; /* spr0tch */

  pic->id = id;

  return (0);
}


void
Picture8_copy(const Picture8_t *from, Picture8_t *to)
{
  assert(from != NULL);
  assert(to != NULL);

  assert(from->name != NULL);
  assert(from->dname != NULL);

  xfree(to->name);
  xfree(to->dname);

  to->name = strdup(from->name);
  to->dname = strdup(from->dname);

  to->id = from->id;

  Buffer8_copy(from->buff, to->buff);
}

Generated by  Doxygen 1.6.0   Back to index