26const char *NextField(
const char *s)
noexcept {
31 while (*s && *s !=
' ') {
41size_t MeasureLength(
const char *s)
noexcept {
43 while (s[i] && (s[i] !=
'\"'))
48unsigned int ValueOfHex(
const char ch)
noexcept {
49 if (ch >=
'0' && ch <=
'9')
51 else if (ch >=
'A' && ch <=
'F')
53 else if (ch >=
'a' && ch <=
'f')
60 const unsigned int r = ValueOfHex(val[0]) * 16 + ValueOfHex(val[1]);
61 const unsigned int g = ValueOfHex(val[2]) * 16 + ValueOfHex(val[3]);
62 const unsigned int b = ValueOfHex(val[4]) * 16 + ValueOfHex(val[5]);
70 return colourCodeTable[ch];
73void XPM::FillRun(
Surface *surface,
int code,
int startX,
int y,
int x)
const {
94 if ((0 == memcmp(textForm,
"/* X", 4)) && (0 == memcmp(textForm,
"/* XPM */", 9))) {
97 if (!linesForm.empty()) {
102 Init(
reinterpret_cast<const char *
const *
>(textForm));
116 const char *line0 = linesForm[0];
118 line0 = NextField(line0);
121 line0 = NextField(line0);
123 line0 = NextField(line0);
124 if (atoi(line0) != 1) {
130 const char *colourDef = linesForm[c+1];
131 const char code = colourDef[0];
134 if (*colourDef ==
'#') {
135 colour = ColourFromHex(colourDef+1);
142 for (
int y=0; y<
height; y++) {
143 const char *lform = linesForm[y+
nColours+1];
144 const size_t len = MeasureLength(lform);
145 for (
size_t x = 0; x<len; x++)
155 const int startY =
static_cast<int>(rc.
top + (rc.
Height() -
height) / 2);
156 const int startX =
static_cast<int>(rc.
left + (rc.
Width() -
width) / 2);
157 for (
int y=0; y<
height; y++) {
160 for (
int x=0; x<
width; x++) {
162 if (code != prevCode) {
163 FillRun(surface, prevCode, startX + xStartRun, startY + y, startX + x);
168 FillRun(surface, prevCode, startX + xStartRun, startY + y, startX +
width);
173 if (pixels.empty() || (x<0) || (x >= width) || (y<0) || (y >= height)) {
178 const int code = pixels[y * width + x];
179 transparent = code == codeTransparent;
183 colour = ColourFromCode(code);
189 std::vector<const char *> linesForm;
193 for (; countQuotes < (2*strings) && textForm[j] !=
'\0'; j++) {
194 if (textForm[j] ==
'\"') {
195 if (countQuotes == 0) {
197 const char *line0 = textForm + j + 1;
199 line0 = NextField(line0);
201 strings += atoi(line0);
202 line0 = NextField(line0);
204 strings += atoi(line0);
206 if (countQuotes / 2 >= strings) {
209 if ((countQuotes & 1) == 0) {
210 linesForm.push_back(textForm + j + 1);
215 if (textForm[j] ==
'\0' || countQuotes / 2 > strings) {
223 height(height_), width(width_), scale(scale_) {
236 for (
int y=0; y<
height; y++) {
237 for (
int x=0; x<
width; x++) {
239 bool transparent =
false;
240 xpm.
PixelAt(x, y, colour, transparent);
241 SetPixel(x, y, colour, transparent ? 0 : 255);
258 unsigned char *pixel = &pixelBytes[0] + (y*width+x) * 4;
260 pixel[0] = colour.GetRed();
261 pixel[1] = colour.GetGreen();
262 pixel[2] = colour.GetBlue();
263 pixel[3] =
static_cast<unsigned char>(alpha);
269 for (
size_t i = 0; i <
count; i++) {
270 const unsigned char alpha = pixelsRGBA[3];
272 pixelsBGRA[2] = pixelsRGBA[0] * alpha / 255;
273 pixelsBGRA[1] = pixelsRGBA[1] * alpha / 255;
274 pixelsBGRA[0] = pixelsRGBA[2] * alpha / 255;
275 pixelsBGRA[3] = alpha;
276 pixelsRGBA += bytesPerPixel;
277 pixelsBGRA += bytesPerPixel;
297 ImageMap::iterator it=
images.find(ident);
299 images[ident] = std::unique_ptr<RGBAImage>(image);
301 it->second.reset(image);
309 ImageMap::iterator it =
images.find(ident);
311 return it->second.get();
319 for (
const std::pair<
const int, std::unique_ptr<RGBAImage>> &image :
images) {
320 if (height < image.second->
GetHeight()) {
321 height = image.second->GetHeight();
331 for (
const std::pair<
const int, std::unique_ptr<RGBAImage>> &image :
images) {
332 if (width < image.second->
GetWidth()) {
333 width = image.second->GetWidth();
Define a classes to hold image data in the X Pixmap (XPM) and RGBA formats.
A geometric rectangle class.
static constexpr PRectangle FromInts(int left_, int top_, int right_, int bottom_) noexcept
constexpr XYPOSITION Height() const noexcept
constexpr XYPOSITION Width() const noexcept
int GetHeight() const
Give the largest height of the set.
int GetWidth() const
Give the largest width of the set.
void Add(int ident, RGBAImage *image)
Add an image.
RGBAImage * Get(int ident)
Get image by id.
void Clear() noexcept
Remove all images.
int width
Memorize largest width of the set.
int height
Memorize largest height of the set.
A translucent image stored as a sequence of RGBA bytes.
std::vector< unsigned char > pixelBytes
void SetPixel(int x, int y, ColourDesired colour, int alpha) noexcept
static void BGRAFromRGBA(unsigned char *pixelsBGRA, const unsigned char *pixelsRGBA, size_t count) noexcept
RGBAImage(int width_, int height_, float scale_, const unsigned char *pixels_)
const unsigned char * Pixels() const noexcept
int CountBytes() const noexcept
A surface abstracts a place to draw.
virtual void FillRectangle(PRectangle rc, ColourDesired back)=0
Hold a pixmap in XPM format.
void FillRun(Surface *surface, int code, int startX, int y, int x) const
int GetWidth() const noexcept
void PixelAt(int x, int y, ColourDesired &colour, bool &transparent) const noexcept
void Draw(Surface *surface, const PRectangle &rc)
Decompose image into runs and use FillRectangle for each run.
ColourDesired colourCodeTable[256]
static std::vector< const char * > LinesFormFromTextForm(const char *textForm)
XPM(const char *textForm)
int GetHeight() const noexcept
std::vector< unsigned char > pixels
void Init(const char *textForm)
ColourDesired ColourFromCode(int ch) const noexcept
#define fill(Order, Group, Idx, Charset, Name)
Styling buffer using one element for each run rather than using a filled buffer.