source: trunk/src/image/codec/gdiplus-image.cpp @ 2013

Last change on this file since 2013 was 2013, checked in by sam, 7 years ago

image: better error detection in the GDI+ image codec.

  • Property svn:keywords set to Id
File size: 3.2 KB
Line 
1//
2// Lol Engine
3//
4// Copyright: (c) 2010-2011 Sam Hocevar <sam@hocevar.net>
5//   This program is free software; you can redistribute it and/or
6//   modify it under the terms of the Do What The Fuck You Want To
7//   Public License, Version 2, as published by Sam Hocevar. See
8//   http://sam.zoy.org/projects/COPYING.WTFPL for more details.
9//
10
11#if defined HAVE_CONFIG_H
12#   include "config.h"
13#endif
14
15#if defined USE_GDIPLUS
16
17#include <algorithm>
18
19using namespace std;
20
21#include <windows.h>
22#include <gdiplus.h>
23
24#include "core.h"
25#include "../../image/image-private.h"
26
27namespace lol
28{
29
30/*
31 * Image implementation class
32 */
33
34DECLARE_IMAGE_LOADER(GdiPlusImageData, 100)
35{
36public:
37    virtual bool Open(char const *);
38    virtual bool Close();
39
40    virtual void *GetData() const;
41
42private:
43    Gdiplus::Bitmap *bitmap;
44    Gdiplus::BitmapData bdata;
45};
46
47/*
48 * Public Image class
49 */
50
51bool GdiPlusImageData::Open(char const *path)
52{
53    Gdiplus::Status status;
54    ULONG_PTR token;
55    Gdiplus::GdiplusStartupInput input;
56    status = Gdiplus::GdiplusStartup(&token, &input, NULL);
57    if (status != Gdiplus::Ok)
58    {
59#if !LOL_RELEASE
60        Log::Error("error %d while initialising GDI+\n", status);
61#endif
62        return false;
63    }
64
65    size_t len;
66    len = mbstowcs(NULL, path, 0);
67    wchar_t *wpath = new wchar_t[len + 1];
68    if (mbstowcs(wpath, path, len + 1) == (size_t)-1)
69    {
70#if !LOL_RELEASE
71        Log::Error("invalid image name %s\n", path);
72#endif
73        delete[] wpath;
74        return false;
75    }
76
77    bitmap = NULL;
78    status = Gdiplus::Ok;
79    for (wchar_t const *wname = wpath; *wname; wname++)
80    {
81        bitmap = Gdiplus::Bitmap::FromFile(wname, 0);
82        if (bitmap)
83        {
84            status = bitmap->GetLastStatus();
85            if (status == Gdiplus::Ok)
86                break;
87#if !LOL_RELEASE
88            if (status != Gdiplus::InvalidParameter)
89                Log::Error("error %d loading %s\n", status, path);
90#endif
91            delete bitmap;
92        }
93    }
94
95    delete[] wpath;
96    if (!bitmap)
97    {
98#if !LOL_RELEASE
99        Log::Error("could not load %s\n", path);
100#endif
101        return false;
102    }
103
104    size = ivec2(bitmap->GetWidth(), bitmap->GetHeight());
105    format = Image::FORMAT_RGBA;
106
107    Gdiplus::Rect rect(0, 0, size.x, size.y);
108    if(bitmap->LockBits(&rect, Gdiplus::ImageLockModeRead,
109                        PixelFormat32bppARGB, &bdata) != Gdiplus::Ok)
110    {
111#if !LOL_RELEASE
112        Log::Error("could not lock bits in %s\n", path);
113#endif
114        delete bitmap;
115        return false;
116    }
117
118    /* FIXME: GDI+ doesn't know about RGBA, only ARGB. And OpenGL doesn't
119     * know about ARGB, only RGBA. So we swap bytes. We could also fix
120     * this in the shader. */
121    uint8_t *p = static_cast<uint8_t *>(bdata.Scan0);
122    for (int y = 0; y < size.y; y++)
123        for (int x = 0; x < size.x; x++)
124        {
125            uint8_t tmp = p[2];
126            p[2] = p[0];
127            p[0] = tmp;
128            p += 4;
129        }
130
131    return true;
132}
133
134bool GdiPlusImageData::Close()
135{
136    bitmap->UnlockBits(&bdata);
137    delete bitmap;
138
139    return true;
140}
141
142void * GdiPlusImageData::GetData() const
143{
144    return bdata.Scan0;
145}
146
147} /* namespace lol */
148
149#endif /* defined USE_GDIPLUS */
150
Note: See TracBrowser for help on using the repository browser.