summaryrefslogtreecommitdiff
path: root/wx+/image_resources.cpp
blob: 3a7ba3eee3816bf985762ccc5d5d52107476b1bb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// **************************************************************************
// * This file is part of the FreeFileSync project. It is distributed under *
// * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0        *
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved        *
// **************************************************************************

#include "image_resources.h"
#include <memory>
#include <map>
#include <wx/wfstream.h>
#include <wx/zipstrm.h>
#include <wx/image.h>
#include <wx/mstream.h>
#include <zen/utf.h>
#include "image_tools.h"

using namespace zen;


namespace
{
void loadAnimFromZip(wxZipInputStream& zipInput, wxAnimation& anim)
{
    //work around wxWidgets bug:
    //construct seekable input stream (zip-input stream is non-seekable) for wxAnimation::Load()
    //luckily this method call is very fast: below measurement precision!
    std::vector<char> data;
    data.reserve(10000);

    int newValue = 0;
    while ((newValue = zipInput.GetC()) != wxEOF)
        data.push_back(newValue);

    wxMemoryInputStream seekAbleStream(&data.front(), data.size()); //stream does not take ownership of data

    anim.Load(seekAbleStream, wxANIMATION_TYPE_GIF);
}


class GlobalResources
{
public:
    static GlobalResources& instance()
    {
        //caveat: function scope static initialization is not thread-safe in VS 2010! => but we wouldn't use wxWidgets in combination with multithreading anyway!
        static GlobalResources inst;
        return inst;
    }

    void init(const Zstring& filepath);

    const wxBitmap&    getImage    (const wxString& name) const;
    const wxAnimation& getAnimation(const wxString& name) const;

private:
    GlobalResources() {}
    GlobalResources           (const GlobalResources&) = delete;
    GlobalResources& operator=(const GlobalResources&) = delete;

    std::map<wxString, wxBitmap> bitmaps;
    std::map<wxString, wxAnimation> anims;
};


void GlobalResources::init(const Zstring& filepath)
{
    assert(bitmaps.empty() && anims.empty());

    wxFFileInputStream input(utfCvrtTo<wxString>(filepath));
    if (input.IsOk()) //if not... we don't want to react too harsh here
    {
        //activate support for .png files
        wxImage::AddHandler(new wxPNGHandler); //ownership passed

        wxZipInputStream streamIn(input, wxConvUTF8);
        //do NOT rely on wxConvLocal! On failure shows unhelpful popup "Cannot convert from the charset 'Unknown encoding (-1)'!"

        while (true)
        {
            std::unique_ptr<wxZipEntry> entry(streamIn.GetNextEntry()); //take ownership!
            if (!entry)
                break;

            const wxString name = entry->GetName();

            //generic image loading
            if (endsWith(name, L".png"))
            {
                wxImage img(streamIn, wxBITMAP_TYPE_PNG);

                //end this alpha/no-alpha/mask/wxDC::DrawBitmap/RTL/high-contrast-scheme interoperability nightmare here and now!!!!
                //=> there's only one type of png image: with alpha channel, no mask!!!
                convertToVanillaImage(img);

                bitmaps.emplace(name, img);
            }
            else if (endsWith(name, L".gif"))
                loadAnimFromZip(streamIn, anims[name]);
        }
    }
}


const wxBitmap& GlobalResources::getImage(const wxString& name) const
{
    auto it = bitmaps.find(contains(name, L'.') ? name : name + L".png"); //assume .png ending if nothing else specified
    if (it != bitmaps.end())
        return it->second;

    assert(false);
    return wxNullBitmap;
}


const wxAnimation& GlobalResources::getAnimation(const wxString& name) const
{
    auto it = anims.find(contains(name, L'.') ? name : name + L".gif");
    if (it != anims.end())
        return it->second;

    assert(false);
    return wxNullAnimation;
}
}


void zen::initResourceImages(const Zstring& filepath) { GlobalResources::instance().init(filepath); }

const wxBitmap& zen::getResourceImage(const wxString& name) { return GlobalResources::instance().getImage(name); }

const wxAnimation& zen::getResourceAnimation(const wxString& name) { return GlobalResources::instance().getAnimation(name); }
bgstack15