/*
 *   -- http://android-fb2png.googlecode.com/svn/trunk/img_process.c --
 *
 *   Copyright 2011, Kyan He <kyan.ql.he@gmail.com>
 *
 *
 *   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 3 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, see <http://www.gnu.org/licenses/>.
 */

#include <errno.h>
#include <png.h>

#include "img_process.h"
#include "log.h"

int rgb565_to_rgb888(const char* src, char* dst, size_t pixel)
{
    struct rgb565  *from;
    struct rgb888  *to;

    from = (struct rgb565 *) src;
    to = (struct rgb888 *) dst;

    int i = 0;
    /* traverse pixel of the row */
    while(i++ < pixel) {

        to->r = from->r;
        to->g = from->g;
        to->b = from->b;
        /* scale */
        to->r <<= 3;
        to->g <<= 2;
        to->b <<= 3;

        to++;
        from++;
    }

    return 0;
}

int argb8888_to_rgb888(const char* src, char* dst, size_t pixel)
{
    int i;
    struct argb8888  *from;
    struct rgb888  *to;

    from = (struct argb8888 *) src;
    to = (struct rgb888 *) dst;

    i = 0;
    /* traverse pixel of the row */
    while(i++ < pixel) {

        to->r = from->r;
        to->g = from->g;
        to->b = from->b;

        to++;
        from++;
    }

    return 0;
}

int abgr8888_to_rgb888(const char* src, char* dst, size_t pixel)
{
    int i;
    struct abgr8888  *from;
    struct rgb888  *to;

    from = (struct abgr8888 *) src;
    to = (struct rgb888 *) dst;

    i = 0;
    /* traverse pixel of the row */
    while(i++ < pixel) {

        to->r = from->r;
        to->g = from->g;
        to->b = from->b;

        to++;
        from++;
    }

    return 0;
}

int bgra8888_to_rgb888(const char* src, char* dst, size_t pixel)
{
    int i;
    struct bgra8888  *from;
    struct rgb888  *to;

    from = (struct bgra8888 *) src;
    to = (struct rgb888 *) dst;

    i = 0;
    /* traverse pixel of the row */
    while(i++ < pixel) {

        to->r = from->r;
        to->g = from->g;
        to->b = from->b;

        to++;
        from++;
    }

    return 0;
}

int rgba8888_to_rgb888(const char* src, char* dst, size_t pixel)
{
    int i;
    struct rgba8888  *from;
    struct rgb888  *to;

    from = (struct rgba8888 *) src;
    to = (struct rgb888 *) dst;

    i = 0;
    /* traverse pixel of the row */
    while(i++ < pixel) {

        to->r = from->r;
        to->g = from->g;
        to->b = from->b;

        to++;
        from++;
    }

    return 0;
}

static void
stdio_write_func (png_structp png, png_bytep data, png_size_t size)
{
    FILE *fp;
    size_t ret;

    fp = png_get_io_ptr (png);
    while (size) {
        ret = fwrite (data, 1, size, fp);
        size -= ret;
        data += ret;
      if (size && ferror (fp))
         E("write: %m\n");
   }
}

static void
png_simple_output_flush_fn (png_structp png_ptr)
{
}

static void
png_simple_error_callback (png_structp png,
                       png_const_charp error_msg)
{
    E("png error: %s\n", error_msg);
}

static void
png_simple_warning_callback (png_structp png,
                         png_const_charp error_msg)
{
    fprintf(stderr, "png warning: %s\n", error_msg);
}

/* save rgb888 to png format in fp */
int save_png(const char* path, const char* data, int width, int height)
{
    FILE *fp;
    png_byte **volatile rows;
    png_struct *png;
    png_info *info;

    fp = fopen(path, "w");
    if (!fp) {
        int errsv = errno;
        E("Cannot open file %s for writing.\n", path);
        return errsv;
    }

    rows = malloc(height * sizeof rows[0]);
    if (!rows) goto oops;

    int i;
    for (i = 0; i < height; i++)
        rows[i] = (png_byte *) data + i * width * 3 /*fb.stride*/;

    png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL,
                               png_simple_error_callback,
                               png_simple_warning_callback);
    if (!png) {
        E("png_create_write_struct failed\n");
        goto oops;
    }

    info = png_create_info_struct (png);
    if (!info) {
        E("png_create_info_struct failed\n");
        png_destroy_write_struct (&png, NULL);
        goto oops;
    }

    png_set_write_fn (png, fp, stdio_write_func, png_simple_output_flush_fn);
    png_set_IHDR (png, info,
            width,
            height,
#define DEPTH 8
            DEPTH,
        PNG_COLOR_TYPE_RGB,
        PNG_INTERLACE_NONE,
        PNG_COMPRESSION_TYPE_DEFAULT,
        PNG_FILTER_TYPE_DEFAULT);

    png_color_16 white;

    white.gray = (1 << DEPTH) - 1;
    white.red = white.blue = white.green = white.gray;

    png_set_bKGD (png, info, &white);
    png_write_info (png, info);

    png_write_image (png, rows);
    png_write_end (png, info);

    png_destroy_write_struct (&png, &info);

    fclose(fp);
    free (rows);
    return 0;

oops:
    fclose(fp);
    free (rows);
    return -1;
}
