Skip to content

Commit a41d231

Browse files
committed
Move everything that deals with images directly to an Image class
1 parent 77fdcd1 commit a41d231

6 files changed

+176
-75
lines changed

CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ set(mapper_SRCS
142142
PlayerAttributes.cpp
143143
TileGenerator.cpp
144144
ZlibDecompressor.cpp
145+
Image.cpp
145146
mapper.cpp
146147
util.cpp
147148
db-sqlite3.cpp

Image.cpp

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#include <cstdio>
2+
#include <cerrno>
3+
#include <cstring>
4+
#include <iostream>
5+
#include <sstream>
6+
#include <stdexcept>
7+
#include <gd.h>
8+
#include <gdfontmb.h>
9+
10+
#include "Image.h"
11+
12+
#ifndef NDEBUG
13+
#define SIZECHECK(x, y) do { \
14+
if((x) < 0 || (x) >= m_width) \
15+
throw std::out_of_range("sizecheck x"); \
16+
if((y) < 0 || (y) >= m_height) \
17+
throw std::out_of_range("sizecheck y"); \
18+
} while(0)
19+
#else
20+
#define SIZECHECK(x, y) do {} while(0)
21+
#endif
22+
23+
// BGRA but with inverted alpha
24+
25+
static inline int color2int(Color c)
26+
{
27+
u8 a = 255 - c.a;
28+
return (a << 24) | (c.r << 16) | (c.g << 8) | c.b;
29+
}
30+
31+
static inline Color int2color(int c)
32+
{
33+
Color c2;
34+
u8 a;
35+
c2.b = c & 0xff;
36+
c2.g = (c >> 8) & 0xff;
37+
c2.r = (c >> 16) & 0xff;
38+
a = (c >> 24) & 0xff;
39+
c2.a = 255 - a;
40+
return c2;
41+
}
42+
43+
44+
Image::Image(int width, int height) :
45+
m_width(width), m_height(height), m_image(NULL)
46+
{
47+
m_image = gdImageCreateTrueColor(m_width, m_height);
48+
}
49+
50+
Image::~Image()
51+
{
52+
gdImageDestroy(m_image);
53+
}
54+
55+
void Image::setPixel(int x, int y, const Color &c)
56+
{
57+
SIZECHECK(x, y);
58+
m_image->tpixels[y][x] = color2int(c);
59+
}
60+
61+
Color Image::getPixel(int x, int y)
62+
{
63+
#ifndef NDEBUG
64+
if(x < 0 || x > m_width || y < 0 || y > m_height)
65+
throw std::out_of_range("sizecheck");
66+
#endif
67+
return int2color(m_image->tpixels[y][x]);
68+
}
69+
70+
void Image::drawLine(int x1, int y1, int x2, int y2, const Color &c)
71+
{
72+
SIZECHECK(x1, y1);
73+
SIZECHECK(x2, y2);
74+
gdImageLine(m_image, x1, y1, x2, y2, color2int(c));
75+
}
76+
77+
void Image::drawText(int x, int y, const std::string &s, const Color &c)
78+
{
79+
SIZECHECK(x, y);
80+
gdImageString(m_image, gdFontGetMediumBold(), x, y, (unsigned char*) s.c_str(), color2int(c));
81+
}
82+
83+
void Image::drawFilledRect(int x, int y, int w, int h, const Color &c)
84+
{
85+
SIZECHECK(x, y);
86+
SIZECHECK(x + w - 1, y + h - 1);
87+
gdImageFilledRectangle(m_image, x, y, x + w - 1, y + h - 1, color2int(c));
88+
}
89+
90+
void Image::drawCircle(int x, int y, int diameter, const Color &c)
91+
{
92+
SIZECHECK(x, y);
93+
gdImageArc(m_image, x, y, diameter, diameter, 0, 360, color2int(c));
94+
}
95+
96+
void Image::save(const std::string &filename)
97+
{
98+
FILE *f = fopen(filename.c_str(), "wb");
99+
if(!f) {
100+
std::ostringstream oss;
101+
oss << "Error writing image file: " << std::strerror(errno);
102+
throw std::runtime_error(oss.str());
103+
}
104+
gdImagePng(m_image, f); // other formats?
105+
fclose(f);
106+
}

Image.h

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#ifndef IMAGE_HEADER
2+
#define IMAGE_HEADER
3+
4+
#include "types.h"
5+
#include <string>
6+
#include <gd.h>
7+
8+
struct Color {
9+
Color() : r(0), g(0), b(0), a(0) {};
10+
Color(u8 r, u8 g, u8 b) : r(r), g(g), b(b), a(255) {};
11+
Color(u8 r, u8 g, u8 b, u8 a) : r(r), g(g), b(b), a(a) {};
12+
u8 r, g, b, a;
13+
};
14+
15+
class Image {
16+
public:
17+
Image(int width, int height);
18+
~Image();
19+
20+
void setPixel(int x, int y, const Color &c);
21+
Color getPixel(int x, int y);
22+
void drawLine(int x1, int y1, int x2, int y2, const Color &c);
23+
void drawText(int x, int y, const std::string &s, const Color &c);
24+
void drawFilledRect(int x, int y, int w, int h, const Color &c);
25+
void drawCircle(int x, int y, int diameter, const Color &c);
26+
void save(const std::string &filename);
27+
28+
private:
29+
Image(const Image&);
30+
31+
int m_width, m_height;
32+
gdImagePtr m_image;
33+
};
34+
35+
#endif // IMAGE_HEADER

TileGenerator.cpp

+30-62
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@
22
#include <cstdlib>
33
#include <climits>
44
#include <fstream>
5-
#include <gdfontmb.h>
65
#include <iostream>
76
#include <sstream>
87
#include <stdexcept>
9-
#include <cerrno>
108
#include <cstring>
119
#include <vector>
1210
#include "config.h"
@@ -29,16 +27,6 @@ static inline uint16_t readU16(const unsigned char *data)
2927
return data[0] << 8 | data[1];
3028
}
3129

32-
static inline int rgb2int(uint8_t r, uint8_t g, uint8_t b, uint8_t a=0xFF)
33-
{
34-
return (a << 24) + (r << 16) + (g << 8) + b;
35-
}
36-
37-
static inline int color2int(Color c)
38-
{
39-
return rgb2int(c.r, c.g, c.b, c.a);
40-
}
41-
4230
// rounds n (away from 0) to a multiple of f while preserving the sign of n
4331
static inline int round_multiple_nosign(int n, int f)
4432
{
@@ -377,10 +365,9 @@ void TileGenerator::createImage()
377365
std::cerr << "Warning: The width or height of the image to be created exceeds 4096 pixels!"
378366
<< " (Dimensions: " << image_width << "x" << image_height << ")"
379367
<< std::endl;
380-
m_image = gdImageCreateTrueColor(image_width, image_height);
368+
m_image = new Image(image_width, image_height);
381369
m_blockPixelAttributes.setWidth(m_mapWidth);
382-
// Background
383-
gdImageFilledRectangle(m_image, 0, 0, image_width - 1, image_height - 1, color2int(m_bgColor));
370+
m_image->drawFilledRect(0, 0, image_width, image_height, m_bgColor); // Background
384371
}
385372

386373
void TileGenerator::renderMap()
@@ -560,15 +547,15 @@ inline void TileGenerator::renderMapBlock(const ustring &mapBlock, const BlockPo
560547
else
561548
m_color[z][x] = mixColors(m_color[z][x], c);
562549
if(m_color[z][x].a == 0xFF) {
563-
setZoomed(m_image,imageY,imageX,color2int(m_color[z][x]));
550+
setZoomed(imageX, imageY, m_color[z][x]);
564551
m_readPixels[z] |= (1 << x);
565552
m_blockPixelAttributes.attribute(15 - z, xBegin + x).thickness = m_thickness[z][x];
566553
} else {
567554
m_thickness[z][x] = (m_thickness[z][x] + color->second.t) / 2.0;
568555
continue;
569556
}
570557
} else {
571-
setZoomed(m_image,imageY,imageX,color2int(c));
558+
setZoomed(imageX, imageY, c);
572559
m_readPixels[z] |= (1 << x);
573560
}
574561
if(!(m_readInfo[z] & (1 << x))) {
@@ -598,7 +585,7 @@ inline void TileGenerator::renderMapBlockBottom(const BlockPos &pos)
598585
int imageX = xBegin + x;
599586

600587
if (m_drawAlpha) {
601-
setZoomed(m_image,imageY,imageX, color2int(m_color[z][x]));
588+
setZoomed(imageX, imageY, m_color[z][x]);
602589
m_readPixels[z] |= (1 << x);
603590
m_blockPixelAttributes.attribute(15 - z, xBegin + x).thickness = m_thickness[z][x];
604591
}
@@ -628,48 +615,43 @@ inline void TileGenerator::renderShading(int zPos)
628615
// more thickness -> less visible shadows: t=0 -> 100% visible, t=255 -> 0% visible
629616
if (m_drawAlpha)
630617
d = d * ((0xFF - m_blockPixelAttributes.attribute(z, x).thickness) / 255.0);
631-
int sourceColor = m_image->tpixels[getImageY(imageY)][getImageX(x)] & 0xffffff;
632-
uint8_t r = (sourceColor & 0xff0000) >> 16;
633-
uint8_t g = (sourceColor & 0x00ff00) >> 8;
634-
uint8_t b = (sourceColor & 0x0000ff);
635-
r = colorSafeBounds(r + d);
636-
g = colorSafeBounds(g + d);
637-
b = colorSafeBounds(b + d);
638-
setZoomed(m_image,imageY,x, rgb2int(r, g, b));
618+
Color c = m_image->getPixel(getImageX(x), getImageY(imageY));
619+
c.r = colorSafeBounds(c.r + d);
620+
c.g = colorSafeBounds(c.g + d);
621+
c.b = colorSafeBounds(c.b + d);
622+
setZoomed(x, imageY, c);
639623
}
640624
}
641625
m_blockPixelAttributes.scroll();
642626
}
643627

644628
void TileGenerator::renderScale()
645629
{
646-
int color = color2int(m_scaleColor);
647-
648630
string scaleText;
649631

650632
if (m_scales & SCALE_TOP) {
651-
gdImageString(m_image, gdFontGetMediumBold(), 24, 0, reinterpret_cast<unsigned char *>(const_cast<char *>("X")), color);
633+
m_image->drawText(24, 0, "X", m_scaleColor);
652634
for (int i = (m_xMin / 4) * 4; i <= m_xMax; i += 4) {
653635
stringstream buf;
654636
buf << i * 16;
655637
scaleText = buf.str();
656638

657639
int xPos = (m_xMin * -16 + i * 16)*m_zoom + m_xBorder;
658-
gdImageString(m_image, gdFontGetMediumBold(), xPos + 2, 0, reinterpret_cast<unsigned char *>(const_cast<char *>(scaleText.c_str())), color);
659-
gdImageLine(m_image, xPos, 0, xPos, m_yBorder - 1, color);
640+
m_image->drawText(xPos + 2, 0, scaleText, m_scaleColor);
641+
m_image->drawLine(xPos, 0, xPos, m_yBorder - 1, m_scaleColor);
660642
}
661643
}
662644

663645
if (m_scales & SCALE_LEFT) {
664-
gdImageString(m_image, gdFontGetMediumBold(), 2, 24, reinterpret_cast<unsigned char *>(const_cast<char *>("Z")), color);
646+
m_image->drawText(2, 24, "Z", m_scaleColor);
665647
for (int i = (m_zMax / 4) * 4; i >= m_zMin; i -= 4) {
666648
stringstream buf;
667649
buf << i * 16;
668650
scaleText = buf.str();
669651

670652
int yPos = (m_mapHeight - 1 - (i * 16 - m_zMin * 16))*m_zoom + m_yBorder;
671-
gdImageString(m_image, gdFontGetMediumBold(), 2, yPos, reinterpret_cast<unsigned char *>(const_cast<char *>(scaleText.c_str())), color);
672-
gdImageLine(m_image, 0, yPos, m_xBorder - 1, yPos, color);
653+
m_image->drawText(2, yPos, scaleText, m_scaleColor);
654+
m_image->drawLine(0, yPos, m_xBorder - 1, yPos, m_scaleColor);
673655
}
674656
}
675657

@@ -680,9 +662,9 @@ void TileGenerator::renderScale()
680662
scaleText = buf.str();
681663

682664
int xPos = (m_xMin * -16 + i * 16)*m_zoom + m_xBorder;
683-
int yPos = m_yBorder + m_mapHeight;
684-
gdImageString(m_image, gdFontGetMediumBold(), xPos + 2, yPos, reinterpret_cast<unsigned char *>(const_cast<char *>(scaleText.c_str())), color);
685-
gdImageLine(m_image, xPos, yPos, xPos, yPos + 39, color);
665+
int yPos = m_yBorder + m_mapHeight*m_zoom;
666+
m_image->drawText(xPos + 2, yPos, scaleText, m_scaleColor);
667+
m_image->drawLine(xPos, yPos, xPos, yPos + 39, m_scaleColor);
686668
}
687669
}
688670

@@ -692,10 +674,10 @@ void TileGenerator::renderScale()
692674
buf << i * 16;
693675
scaleText = buf.str();
694676

695-
int xPos = m_xBorder + m_mapWidth;
677+
int xPos = m_xBorder + m_mapWidth*m_zoom;
696678
int yPos = (m_mapHeight - 1 - (i * 16 - m_zMin * 16))*m_zoom + m_yBorder;
697-
gdImageString(m_image, gdFontGetMediumBold(), xPos + 2, yPos, reinterpret_cast<unsigned char *>(const_cast<char *>(scaleText.c_str())), color);
698-
gdImageLine(m_image, xPos, yPos, xPos + 39, yPos, color);
679+
m_image->drawText(xPos + 2, yPos, scaleText, m_scaleColor);
680+
m_image->drawLine(xPos, yPos, xPos + 39, yPos, m_scaleColor);
699681
}
700682
}
701683
}
@@ -704,20 +686,18 @@ void TileGenerator::renderOrigin()
704686
{
705687
int imageX = (-m_xMin * 16)*m_zoom + m_xBorder;
706688
int imageY = (m_mapHeight - m_zMin * -16)*m_zoom + m_yBorder;
707-
gdImageArc(m_image, imageX, imageY, 12, 12, 0, 360, color2int(m_originColor));
689+
m_image->drawCircle(imageX, imageY, 12, m_originColor);
708690
}
709691

710692
void TileGenerator::renderPlayers(const std::string &inputPath)
711693
{
712-
int color = color2int(m_playerColor);
713-
714694
PlayerAttributes players(inputPath);
715695
for (PlayerAttributes::Players::iterator player = players.begin(); player != players.end(); ++player) {
716696
int imageX = (player->x / 10 - m_xMin * 16)*m_zoom + m_xBorder;
717697
int imageY = (m_mapHeight - (player->z / 10 - m_zMin * 16))*m_zoom + m_yBorder;
718698

719-
gdImageArc(m_image, imageX, imageY, 5, 5, 0, 360, color);
720-
gdImageString(m_image, gdFontGetMediumBold(), imageX + 2, imageY + 2, reinterpret_cast<unsigned char *>(const_cast<char *>(player->name.c_str())), color);
699+
m_image->drawCircle(imageX, imageY, 5, m_playerColor);
700+
m_image->drawText(imageX + 2, imageY + 2, player->name, m_playerColor);
721701
}
722702
}
723703

@@ -735,16 +715,9 @@ inline std::list<int> TileGenerator::getZValueList() const
735715

736716
void TileGenerator::writeImage(const std::string &output)
737717
{
738-
FILE *out;
739-
out = fopen(output.c_str(), "wb");
740-
if (!out) {
741-
std::ostringstream oss;
742-
oss << "Error opening '" << output.c_str() << "': " << std::strerror(errno);
743-
throw std::runtime_error(oss.str());
744-
}
745-
gdImagePng(m_image, out);
746-
fclose(out);
747-
gdImageDestroy(m_image);
718+
m_image->save(output);
719+
delete m_image;
720+
m_image = NULL;
748721
}
749722

750723
void TileGenerator::printUnknown()
@@ -767,11 +740,6 @@ inline int TileGenerator::getImageY(int val) const
767740
return (m_zoom*val) + m_yBorder;
768741
}
769742

770-
inline void TileGenerator::setZoomed(gdImagePtr image, int y, int x, int color) {
771-
int xx,yy;
772-
for (xx = 0; xx < m_zoom; xx++) {
773-
for (yy = 0; yy < m_zoom; yy++) {
774-
image->tpixels[m_yBorder + (y*m_zoom) + xx][m_xBorder + (x*m_zoom) + yy] = color;
775-
}
776-
}
743+
inline void TileGenerator::setZoomed(int x, int y, Color color) {
744+
m_image->drawFilledRect(getImageX(x), getImageY(y), m_zoom, m_zoom, color);
777745
}

0 commit comments

Comments
 (0)