1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /***************************************************************************
3  *            image.cc
4  *
5  *  Sat Mar 16 15:05:09 CET 2013
6  *  Copyright 2013 Bent Bisballe Nyeng
7  *  deva@aasimon.org
8  ****************************************************************************/
9 
10 /*
11  *  This file is part of DrumGizmo.
12  *
13  *  DrumGizmo is free software; you can redistribute it and/or modify
14  *  it under the terms of the GNU Lesser General Public License as published by
15  *  the Free Software Foundation; either version 3 of the License, or
16  *  (at your option) any later version.
17  *
18  *  DrumGizmo is distributed in the hope that it will be useful,
19  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  *  GNU Lesser General Public License for more details.
22  *
23  *  You should have received a copy of the GNU Lesser General Public License
24  *  along with DrumGizmo; if not, write to the Free Software
25  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
26  */
27 #include "image.h"
28 
29 #include <cstring>
30 #include <cstdint>
31 #include <cstdlib>
32 #include <cassert>
33 
34 #include <hugin.hpp>
35 
36 #include "resource.h"
37 #include "lodepng/lodepng.h"
38 
39 namespace GUI
40 {
41 
Image(const char * data,size_t size)42 Image::Image(const char* data, size_t size)
43 {
44 	load(data, size);
45 }
46 
Image(const std::string & filename)47 Image::Image(const std::string& filename)
48 	: filename(filename)
49 {
50 	Resource rc(filename);
51 	if(!rc.valid())
52 	{
53 		setError();
54 		return;
55 	}
56 	load(rc.data(), rc.size());
57 }
58 
Image(Image && other)59 Image::Image(Image&& other)
60 	: _width(other._width)
61 	, _height(other._height)
62 	, image_data(std::move(other.image_data))
63 	, image_data_raw(std::move(other.image_data_raw))
64 	, filename(other.filename)
65 {
66 	other._width = 0;
67 	other._height = 0;
68 }
69 
~Image()70 Image::~Image()
71 {
72 }
73 
operator =(Image && other)74 Image& Image::operator=(Image&& other)
75 {
76 	image_data.clear();
77 	image_data = std::move(other.image_data);
78 	image_data_raw.clear();
79 	image_data_raw = std::move(other.image_data_raw);
80 	_width = other._width;
81 	_height = other._height;
82 	valid = other.valid;
83 
84 	other._width = 0;
85 	other._height = 0;
86 	other.valid = false;
87 	return *this;
88 }
89 
setError()90 void Image::setError()
91 {
92 	valid = false;
93 	Resource rc(":resources/png_error");
94 	if(!rc.valid())
95 	{
96 		_width = _height = 0u;
97 		return;
98 	}
99 
100 	const unsigned char* ptr = (const unsigned char*)rc.data();
101 
102 	std::uint32_t iw, ih;
103 
104 	iw = (uint32_t) ptr[0] |
105 	     (uint32_t) ptr[1] << 8 |
106 	     (uint32_t) ptr[2] << 16 |
107 	     (uint32_t) ptr[3] << 24;
108 	ptr += sizeof(uint32_t);
109 
110 	ih = (uint32_t) ptr[0] |
111 	     (uint32_t) ptr[1] << 8 |
112 	     (uint32_t) ptr[2] << 16 |
113 	     (uint32_t) ptr[3] << 24;
114 	ptr += sizeof(uint32_t);
115 
116 	_width = iw;
117 	_height = ih;
118 
119 	image_data.clear();
120 	image_data.reserve(_width * _height);
121 
122 	image_data_raw.clear();
123 	image_data_raw.reserve(_width * _height * 4);
124 	memcpy(image_data_raw.data(), ptr, _height * _width);
125 
126 	for(std::size_t y = 0; y < _height; ++y)
127 	{
128 		for(std::size_t x = 0; x < _width; ++x)
129 		{
130 			image_data.emplace_back(Colour{ptr[0] / 255.0f, ptr[1] / 255.0f,
131 						ptr[2] / 255.0f, ptr[3] / 255.0f});
132 		}
133 	}
134 
135 	assert(image_data.size() == (_width * _height));
136 }
137 
load(const char * data,size_t size)138 void Image::load(const char* data, size_t size)
139 {
140 	has_alpha = false;
141 	unsigned int iw{0}, ih{0};
142 	std::uint8_t* char_image_data{nullptr};
143 	unsigned int res = lodepng_decode32((std::uint8_t**)&char_image_data,
144 	                                    &iw, &ih,
145 	                                    (const std::uint8_t*)data, size);
146 
147 	if(res != 0)
148 	{
149 		ERR(image, "Error in lodepng_decode32: %d while loading '%s'",
150 		    res, filename.c_str());
151 		setError();
152 		return;
153 	}
154 
155 	_width = iw;
156 	_height = ih;
157 
158 	image_data.clear();
159 	image_data.reserve(_width * _height);
160 
161 	image_data_raw.clear();
162 	image_data_raw.reserve(_width * _height * 4);
163 	memcpy(image_data_raw.data(), char_image_data, _height * _width * 4);
164 
165 	for(std::size_t y = 0; y < _height; ++y)
166 	{
167 		for(std::size_t x = 0; x < _width; ++x)
168 		{
169 			std::uint8_t* ptr = &char_image_data[(x + y * _width) * 4];
170 			image_data.emplace_back(Colour{ptr[0], ptr[1], ptr[2], ptr[3]});
171 			has_alpha |= ptr[3] != 0xff;
172 		}
173 	}
174 
175 	assert(image_data.size() == (_width * _height));
176 
177 	std::free(char_image_data);
178 	valid = true;
179 }
180 
width() const181 size_t Image::width() const
182 {
183 	return _width;
184 }
185 
height() const186 size_t Image::height() const
187 {
188 	return _height;
189 }
190 
getPixel(size_t x,size_t y) const191 const Colour& Image::getPixel(size_t x, size_t y) const
192 {
193 	if(x > _width || y > _height)
194 	{
195 		return out_of_range;
196 	}
197 
198 	return image_data[x + y * _width];
199 }
200 
line(std::size_t y,std::size_t x_offset) const201 const std::uint8_t* Image::line(std::size_t y, std::size_t x_offset) const
202 {
203 	return image_data_raw.data() + y * _width * 4 + x_offset * 4;
204 }
205 
hasAlpha() const206 bool Image::hasAlpha() const
207 {
208 	return has_alpha;
209 }
210 
isValid() const211 bool Image::isValid() const
212 {
213 	return valid;
214 }
215 
216 } // GUI::
217