Otclient 1.0  14/8/2020
image.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010-2020 OTClient <https://github.com/edubart/otclient>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20  * THE SOFTWARE.
21  */
22 
23 
24 #include "image.h"
25 
29 
30 Image::Image(const Size& size, int bpp, uint8* pixels)
31 {
32  m_size = size;
33  m_bpp = bpp;
34 
35  m_pixels.resize(size.area() * bpp, 0);
36  if (pixels)
37  memcpy(&m_pixels[0], pixels, m_pixels.size());
38 }
39 
40 ImagePtr Image::load(std::string file)
41 {
42  ImagePtr image;
43  try {
44  file = g_resources.guessFilePath(file, "png");
45 
46  // load image file data
47  image = loadPNG(file);
48  }
49  catch (stdext::exception& e) {
50  g_logger.error(stdext::format("unable to load image '%s': %s", file, e.what()));
51  }
52  return image;
53 }
54 
55 ImagePtr Image::loadPNG(const std::string& file)
56 {
57  std::stringstream fin;
58  g_resources.readFileStream(file, fin);
59  ImagePtr image;
60  apng_data apng;
61  if (load_apng(fin, &apng) == 0) {
62  image = ImagePtr(new Image(Size(apng.width, apng.height), apng.bpp, apng.pdata));
63  free_apng(&apng);
64  }
65  return image;
66 }
67 
68 void Image::savePNG(const std::string& fileName)
69 {
70  FileStreamPtr fin = g_resources.createFile(fileName);
71  if (!fin)
72  stdext::throw_exception(stdext::format("failed to open file '%s' for write", fileName));
73 
74  fin->cache();
75  std::stringstream data;
76  save_png(data, m_size.width(), m_size.height(), 4, static_cast<unsigned char*>(getPixelData()));
77  fin->write(data.str().c_str(), data.str().length());
78  fin->flush();
79  fin->close();
80 }
81 
82 void Image::overwriteMask(const Color& maskedColor, const Color& insideColor, const Color& outsideColor)
83 {
84  assert(m_bpp == 4);
85 
86  for (int p = 0; p < getPixelCount(); ++p) {
87  uint8& r = m_pixels[p * 4 + 0];
88  uint8& g = m_pixels[p * 4 + 1];
89  uint8& b = m_pixels[p * 4 + 2];
90  uint8& a = m_pixels[p * 4 + 3];
91 
92  Color pixelColor(r, g, b, a);
93  Color writeColor = (pixelColor == maskedColor) ? insideColor : outsideColor;
94 
95  r = writeColor.r();
96  g = writeColor.g();
97  b = writeColor.b();
98  a = writeColor.a();
99  }
100 }
101 
102 void Image::blit(const Point& dest, const ImagePtr& other)
103 {
104  assert(m_bpp == 4);
105 
106  if (!other)
107  return;
108 
109  int coloredPixelSize = 0;
110 
111  uint8* otherPixels = other->getPixelData();
112  for (int p = 0; p < other->getPixelCount(); ++p) {
113  int x = p % other->getWidth();
114  int y = p / other->getWidth();
115  int pos = ((dest.y + y) * m_size.width() + (dest.x + x)) * 4;
116 
117  if (otherPixels[p * 4 + 3] != 0) {
118  m_pixels[pos + 0] = otherPixels[p * 4 + 0];
119  m_pixels[pos + 1] = otherPixels[p * 4 + 1];
120  m_pixels[pos + 2] = otherPixels[p * 4 + 2];
121  m_pixels[pos + 3] = otherPixels[p * 4 + 3];
122  ++coloredPixelSize;
123  }
124  }
125 }
126 
127 void Image::paste(const ImagePtr& other)
128 {
129  assert(m_bpp == 4);
130 
131  if (!other)
132  return;
133 
134  uint8* otherPixels = other->getPixelData();
135  for (int p = 0; p < other->getPixelCount(); ++p) {
136  int x = p % other->getWidth();
137  int y = p / other->getWidth();
138  int pos = (y * m_size.width() + x) * 4;
139 
140  m_pixels[pos + 0] = otherPixels[p * 4 + 0];
141  m_pixels[pos + 1] = otherPixels[p * 4 + 1];
142  m_pixels[pos + 2] = otherPixels[p * 4 + 2];
143  m_pixels[pos + 3] = otherPixels[p * 4 + 3];
144  }
145 }
146 
148 {
149  assert(m_bpp == 4);
150  assert(stdext::is_power_of_two(m_size.width()) && stdext::is_power_of_two(m_size.height()));
151 
152  int iw = m_size.width();
153  int ih = m_size.height();
154  if (iw == 1 && ih == 1)
155  return false;
156 
157  int ow = iw > 1 ? iw / 2 : 1;
158  int oh = ih > 1 ? ih / 2 : 1;
159 
160  std::vector<uint8> pixels(ow * oh * 4, 0xFF);
161 
162  //FIXME: calculate mipmaps for 8x1, 4x1, 2x1 ...
163  if (iw != 1 && ih != 1) {
164  for (int x = 0; x < ow; ++x) {
165  for (int y = 0; y < oh; ++y) {
166  uint8* inPixel[4];
167  inPixel[0] = &m_pixels[((y * 2) * iw + (x * 2)) * 4];
168  inPixel[1] = &m_pixels[((y * 2) * iw + (x * 2) + 1) * 4];
169  inPixel[2] = &m_pixels[((y * 2 + 1) * iw + (x * 2)) * 4];
170  inPixel[3] = &m_pixels[((y * 2 + 1) * iw + (x * 2) + 1) * 4];
171  uint8* outPixel = &pixels[(y * ow + x) * 4];
172 
173  int pixelsSum[4];
174  for (int i = 0; i < 4; ++i)
175  pixelsSum[i] = 0;
176 
177  int usedPixels = 0;
178  for (int j = 0; j < 4; ++j) {
179  // ignore colors of complete alpha pixels
180  if (inPixel[j][3] < 16)
181  continue;
182 
183  for (int i = 0; i < 4; ++i)
184  pixelsSum[i] += inPixel[j][i];
185 
186  usedPixels++;
187  }
188 
189  // try to guess the alpha pixel more accurately
190  for (int i = 0; i < 4; ++i) {
191  if (usedPixels > 0)
192  outPixel[i] = pixelsSum[i] / usedPixels;
193  else
194  outPixel[i] = 0;
195  }
196  outPixel[3] = pixelsSum[3] / 4;
197  }
198  }
199  }
200 
201  m_pixels = pixels;
202  m_size = Size(ow, oh);
203  return true;
204 }
205 
206 /*
207  *
208 
209 void Texture::generateSoftwareMipmaps(std::vector<uint8> inPixels)
210 {
211  bind();
212 
213  assert(stdext::is_power_of_two(m_glSize.width()) && stdext::is_power_of_two(m_glSize.height()));
214 
215  Size inSize = m_glSize;
216  Size outSize = inSize / 2;
217  std::vector<uint8> outPixels;
218 
219  int mipmap = 1;
220  while(true) {
221  outPixels.resize(outSize.area()*4, 0);
222 
223  // this is a simple bilinear filtering algorithm, it combines every 4 pixels in one pixel
224  for(int x=0;x<outSize.width();++x) {
225  for(int y=0;y<outSize.height();++y) {
226  uint8 *inPixel[4];
227  inPixel[0] = &inPixels[((y*2)*inSize.width() + (x*2))*4];
228  inPixel[1] = &inPixels[((y*2)*inSize.width() + (x*2)+1)*4];
229  inPixel[2] = &inPixels[((y*2+1)*inSize.width() + (x*2))*4];
230  inPixel[3] = &inPixels[((y*2+1)*inSize.width() + (x*2)+1)*4];
231  uint8 *outPixel = &outPixels[(y*outSize.width() + x)*4];
232 
233  int pixelsSum[4];
234  for(int i=0;i<4;++i)
235  pixelsSum[i] = 0;
236 
237  int usedPixels = 0;
238  for(int j=0;j<4;++j) {
239  // ignore colors of complete alpha pixels
240  if(inPixel[j][3] < 16)
241  continue;
242 
243  for(int i=0;i<4;++i)
244  pixelsSum[i] += inPixel[j][i];
245 
246  usedPixels++;
247  }
248 
249  // try to guess the alpha pixel more accurately
250  for(int i=0;i<4;++i) {
251  if(usedPixels > 0)
252  outPixel[i] = pixelsSum[i] / usedPixels;
253  else
254  outPixel[i] = 0;
255  }
256  outPixel[3] = pixelsSum[3]/4;
257  }
258  }
259 
260  glTexImage2D(GL_TEXTURE_2D, mipmap++, GL_RGBA, outSize.width(), outSize.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, &outPixels[0]);
261 
262  if(inSize.width() == 1 || inSize.height() == 1)
263  break;
264 
265  inPixels = std::move(outPixels);
266  inSize /= 2;
267  outSize /= 2;
268  }
269 
270  if(!m_hasMipmaps) {
271  m_hasMipmaps = true;
272  setupFilters();
273  }
274 }
275 */
FileStream::write
void write(const void *buffer, uint count)
Definition: filestream.cpp:130
Color::g
uint8 g() const
Definition: color.h:46
Color
Definition: color.h:32
TPoint::y
T y
Definition: point.h:83
FileStream::close
void close()
Definition: filestream.cpp:78
free_apng
void free_apng(struct apng_data *apng)
Definition: apngloader.cpp:1154
Image::load
static ImagePtr load(std::string file)
Definition: image.cpp:40
apngloader.h
TSize::area
T area() const
Definition: size.h:101
resourcemanager.h
Logger::error
void error(const std::string &what)
Definition: logger.h:54
stdext::is_power_of_two
bool is_power_of_two(size_t v)
Definition: math.h:31
Image::getPixelData
uint8 * getPixelData()
Definition: image.h:49
stdext::format
std::string format()
Definition: format.h:84
ImagePtr
stdext::shared_object_ptr< Image > ImagePtr
Definition: declarations.h:46
TSize::width
int width() const
Definition: size.h:43
Color::a
uint8 a() const
Definition: color.h:44
Image::nextMipmap
bool nextMipmap()
Definition: image.cpp:147
apng_data::height
unsigned int height
Definition: apngloader.h:31
Image::blit
void blit(const Point &dest, const ImagePtr &other)
Definition: image.cpp:102
g_resources
ResourceManager g_resources
Definition: resourcemanager.cpp:32
Image::paste
void paste(const ImagePtr &other)
Definition: image.cpp:127
FileStream::cache
void cache()
Definition: filestream.cpp:58
apng_data::bpp
unsigned char bpp
Definition: apngloader.h:34
g_logger
Logger g_logger
Definition: logger.cpp:35
save_png
void save_png(std::stringstream &f, unsigned int width, unsigned int height, int channels, unsigned char *pixels)
Definition: apngloader.cpp:927
apng_data
Definition: apngloader.h:28
image.h
Size
TSize< int > Size
Definition: size.h:107
TPoint::x
T x
Definition: point.h:83
Image::overwriteMask
void overwriteMask(const Color &maskedColor, const Color &insideColor=Color::white, const Color &outsideColor=Color::alpha)
Definition: image.cpp:82
Image::loadPNG
static ImagePtr loadPNG(const std::string &file)
Definition: image.cpp:55
stdext::throw_exception
void throw_exception(const std::string &what)
Throws a generic exception.
Definition: exception.h:43
filestream.h
stdext::exception::what
virtual const char * what() const
Definition: exception.h:37
TSize::height
int height() const
Definition: size.h:44
ResourceManager::readFileStream
void readFileStream(const std::string &fileName, std::iostream &out)
Definition: resourcemanager.cpp:173
load_apng
int load_apng(std::stringstream &file, struct apng_data *apng)
Definition: apngloader.cpp:515
stdext::shared_object_ptr
Definition: shared_object.h:39
Color::r
uint8 r() const
Definition: color.h:47
FileStream::flush
void flush()
Definition: filestream.cpp:90
Image::Image
Image(const Size &size, int bpp=4, uint8 *pixels=nullptr)
Definition: image.cpp:30
Image::getPixelCount
int getPixelCount()
Definition: image.h:50
TPoint< int >
apng_data::pdata
unsigned char * pdata
Definition: apngloader.h:29
ResourceManager::createFile
FileStreamPtr createFile(const std::string &fileName)
Definition: resourcemanager.cpp:250
TSize< int >
Color::b
uint8 b() const
Definition: color.h:45
Image::savePNG
void savePNG(const std::string &fileName)
Definition: image.cpp:68
uint8
uint8_t uint8
Definition: types.h:37
apng_data::width
unsigned int width
Definition: apngloader.h:30
ResourceManager::guessFilePath
std::string guessFilePath(const std::string &filename, const std::string &type)
Definition: resourcemanager.cpp:353
stdext::exception
Definition: exception.h:31