/*
 *  libpipi       Pathetic image processing interface library
 *  Copyright (c) 2004-2008 Sam Hocevar <sam@zoy.org>
 *                All Rights Reserved
 *
 *  $Id$
 *
 *  This library is free software. It comes without any warranty, to
 *  the extent permitted by applicable law. You can redistribute it
 *  and/or modify it under the terms of the Do What The Fuck You Want
 *  To Public License, Version 2, as published by Sam Hocevar. See
 *  http://sam.zoy.org/wtfpl/COPYING for more details.
 */

/*
 * gdi.c: Windows GDI I/O functions (BMP only)
 */

#include "config.h"

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

#include <windows.h>

#include <Gdiplus.h>

extern "C" {
#include "pipi.h"
#include "pipi_internals.h"
}

extern "C" pipi_image_t *pipi_load_gdiplus(const char *name)
{
    size_t len;
    len = mbstowcs(NULL, name, 0);
    wchar_t *wname = new wchar_t[len + 1];
    if(mbstowcs(wname, name, len + 1) == (size_t)-1)
    {
        delete[] wname;
        return NULL;
    }

    ULONG_PTR token;
    Gdiplus::GdiplusStartupInput input;
    Gdiplus::GdiplusStartup(&token, &input, NULL);

    Gdiplus::Bitmap *b = Gdiplus::Bitmap::FromFile(wname, 0);
    if(!b)
    {
        delete[] wname;
        return NULL;
    }
    delete[] wname;

    Gdiplus::BitmapData bdata;
    Gdiplus::Rect rect(0, 0, b->GetWidth(), b->GetHeight());

    if(b->LockBits(&rect, Gdiplus::ImageLockModeRead,
                   PixelFormat32bppARGB, &bdata) != Gdiplus::Ok)
    {
        delete b;
        return NULL;
    }

    pipi_image_t *img = pipi_new(b->GetWidth(), b->GetHeight());
    pipi_pixels_t *p = pipi_getpixels(img, PIPI_PIXELS_RGBA_C);
    memcpy(p->pixels, bdata.Scan0, bdata.Width * bdata.Height * 4);

    b->UnlockBits(&bdata);
    delete b;

    img->codec_priv = NULL;

    img->wrap = 0;
    img->u8 = 1;

    return img;
}

extern "C" int pipi_save_gdiplus(pipi_image_t *img, const char *name)
{
    wchar_t const *fmt;
    if(strstr(name, ".gif"))
        fmt = L"image/gif";
    else if(strstr(name, ".jpeg") || strstr(name, ".jpeg"))
        fmt = L"image/jpeg";
    else if(strstr(name, ".png"))
        fmt = L"image/png";
    else if(strstr(name, ".tiff"))
        fmt = L"image/tiff";
    else /* if(strstr(name, ".bmp")) */
        fmt = L"image/bmp";

    unsigned int num = 0, size = 0;
    Gdiplus::GetImageEncodersSize(&num, &size);
    if(size == 0)
        return -1;
    Gdiplus::ImageCodecInfo *codecs
        = (Gdiplus::ImageCodecInfo *)(malloc(size));
    if(!codecs)
        return -1;
    Gdiplus::GetImageEncoders(num, size, codecs);
    CLSID clsid;
    for(unsigned int i = 0; i < num; i++)
    {
        if(wcscmp(codecs[i].MimeType, fmt) == 0)
        {
            clsid = codecs[i].Clsid;
            break;
        }
    }

    size_t len;
    len = mbstowcs(NULL, name, 0);
    wchar_t *wname = new wchar_t[len + 1];
    if(mbstowcs(wname, name, len + 1) == (size_t)-1)
    {
        delete[] wname;
        return -1;
    }

    ULONG_PTR token;
    Gdiplus::GdiplusStartupInput input;
    Gdiplus::GdiplusStartup(&token, &input, NULL);

    Gdiplus::Bitmap *b = new Gdiplus::Bitmap(img->w, img->h,
                                             PixelFormat32bppARGB);

    Gdiplus::BitmapData bdata;
    Gdiplus::Rect rect(0, 0, img->w, img->h);

    if(b->LockBits(&rect, (unsigned int)Gdiplus::ImageLockModeWrite,
                   PixelFormat32bppARGB, &bdata) != Gdiplus::Ok)
    {
        delete b;
        return -1;
    }

    pipi_pixels_t *p = pipi_getpixels(img, PIPI_PIXELS_RGBA_C);
    memcpy(bdata.Scan0, p->pixels, bdata.Width * bdata.Height * 4);

    b->UnlockBits(&bdata);

    if(b->Save(wname, &clsid, NULL) != Gdiplus::Ok)
    {
        delete[] wname;
        delete b;
        return -1;
    }
    delete[] wname;
    delete b;

    return 0;
}

/*
 * XXX: The following functions are local.
 */

