geany  1.38
About: Geany is a text editor (using GTK2) with basic features of an integrated development environment (syntax highlighting, code folding, symbol name auto-completion, ...). F: office T: editor programming GTK+ IDE
  Fossies Dox: geany-1.38.tar.bz2  ("unofficial" and yet experimental doxygen-generated source code documentation)  

XPM.cxx
Go to the documentation of this file.
1// Scintilla source code edit control
2/** @file XPM.cxx
3 ** Define a class that holds data in the X Pixmap (XPM) format.
4 **/
5// Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
6// The License.txt file describes the conditions under which this software may be distributed.
7
8#include <cstdlib>
9#include <cstring>
10
11#include <stdexcept>
12#include <vector>
13#include <map>
14#include <algorithm>
15#include <iterator>
16#include <memory>
17
18#include "Platform.h"
19
20#include "XPM.h"
21
22using namespace Scintilla;
23
24namespace {
25
26const char *NextField(const char *s) noexcept {
27 // In case there are leading spaces in the string
28 while (*s == ' ') {
29 s++;
30 }
31 while (*s && *s != ' ') {
32 s++;
33 }
34 while (*s == ' ') {
35 s++;
36 }
37 return s;
38}
39
40// Data lines in XPM can be terminated either with NUL or "
41size_t MeasureLength(const char *s) noexcept {
42 size_t i = 0;
43 while (s[i] && (s[i] != '\"'))
44 i++;
45 return i;
46}
47
48unsigned int ValueOfHex(const char ch) noexcept {
49 if (ch >= '0' && ch <= '9')
50 return ch - '0';
51 else if (ch >= 'A' && ch <= 'F')
52 return ch - 'A' + 10;
53 else if (ch >= 'a' && ch <= 'f')
54 return ch - 'a' + 10;
55 else
56 return 0;
57}
58
59ColourDesired ColourFromHex(const char *val) noexcept {
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]);
63 return ColourDesired(r, g, b);
64}
65
66}
67
68
69ColourDesired XPM::ColourFromCode(int ch) const noexcept {
70 return colourCodeTable[ch];
71}
72
73void XPM::FillRun(Surface *surface, int code, int startX, int y, int x) const {
74 if ((code != codeTransparent) && (startX != x)) {
75 const PRectangle rc = PRectangle::FromInts(startX, y, x, y + 1);
76 surface->FillRectangle(rc, ColourFromCode(code));
77 }
78}
79
80XPM::XPM(const char *textForm) {
81 Init(textForm);
82}
83
84XPM::XPM(const char *const *linesForm) {
85 Init(linesForm);
86}
87
89}
90
91void XPM::Init(const char *textForm) {
92 // Test done is two parts to avoid possibility of overstepping the memory
93 // if memcmp implemented strangely. Must be 4 bytes at least at destination.
94 if ((0 == memcmp(textForm, "/* X", 4)) && (0 == memcmp(textForm, "/* XPM */", 9))) {
95 // Build the lines form out of the text form
96 std::vector<const char *> linesForm = LinesFormFromTextForm(textForm);
97 if (!linesForm.empty()) {
98 Init(&linesForm[0]);
99 }
100 } else {
101 // It is really in line form
102 Init(reinterpret_cast<const char * const *>(textForm));
103 }
104}
105
106void XPM::Init(const char *const *linesForm) {
107 height = 1;
108 width = 1;
109 nColours = 1;
110 pixels.clear();
111 codeTransparent = ' ';
112 if (!linesForm)
113 return;
114
116 const char *line0 = linesForm[0];
117 width = atoi(line0);
118 line0 = NextField(line0);
119 height = atoi(line0);
120 pixels.resize(width*height);
121 line0 = NextField(line0);
122 nColours = atoi(line0);
123 line0 = NextField(line0);
124 if (atoi(line0) != 1) {
125 // Only one char per pixel is supported
126 return;
127 }
128
129 for (int c=0; c<nColours; c++) {
130 const char *colourDef = linesForm[c+1];
131 const char code = colourDef[0];
132 colourDef += 4;
133 ColourDesired colour(0xff, 0xff, 0xff);
134 if (*colourDef == '#') {
135 colour = ColourFromHex(colourDef+1);
136 } else {
137 codeTransparent = code;
138 }
139 colourCodeTable[static_cast<unsigned char>(code)] = colour;
140 }
141
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++)
146 pixels[y * width + x] = lform[x];
147 }
148}
149
150void XPM::Draw(Surface *surface, const PRectangle &rc) {
151 if (pixels.empty()) {
152 return;
153 }
154 // Centre the pixmap
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++) {
158 int prevCode = 0;
159 int xStartRun = 0;
160 for (int x=0; x<width; x++) {
161 const int code = pixels[y * width + x];
162 if (code != prevCode) {
163 FillRun(surface, prevCode, startX + xStartRun, startY + y, startX + x);
164 xStartRun = x;
165 prevCode = code;
166 }
167 }
168 FillRun(surface, prevCode, startX + xStartRun, startY + y, startX + width);
169 }
170}
171
172void XPM::PixelAt(int x, int y, ColourDesired &colour, bool &transparent) const noexcept {
173 if (pixels.empty() || (x<0) || (x >= width) || (y<0) || (y >= height)) {
174 colour = ColourDesired(0);
175 transparent = true;
176 return;
177 }
178 const int code = pixels[y * width + x];
179 transparent = code == codeTransparent;
180 if (transparent) {
181 colour = ColourDesired(0);
182 } else {
183 colour = ColourFromCode(code);
184 }
185}
186
187std::vector<const char *> XPM::LinesFormFromTextForm(const char *textForm) {
188 // Build the lines form out of the text form
189 std::vector<const char *> linesForm;
190 int countQuotes = 0;
191 int strings=1;
192 int j=0;
193 for (; countQuotes < (2*strings) && textForm[j] != '\0'; j++) {
194 if (textForm[j] == '\"') {
195 if (countQuotes == 0) {
196 // First field: width, height, number of colours, chars per pixel
197 const char *line0 = textForm + j + 1;
198 // Skip width
199 line0 = NextField(line0);
200 // Add 1 line for each pixel of height
201 strings += atoi(line0);
202 line0 = NextField(line0);
203 // Add 1 line for each colour
204 strings += atoi(line0);
205 }
206 if (countQuotes / 2 >= strings) {
207 break; // Bad height or number of colours!
208 }
209 if ((countQuotes & 1) == 0) {
210 linesForm.push_back(textForm + j + 1);
211 }
212 countQuotes++;
213 }
214 }
215 if (textForm[j] == '\0' || countQuotes / 2 > strings) {
216 // Malformed XPM! Height + number of colours too high or too low
217 linesForm.clear();
218 }
219 return linesForm;
220}
221
222RGBAImage::RGBAImage(int width_, int height_, float scale_, const unsigned char *pixels_) :
223 height(height_), width(width_), scale(scale_) {
224 if (pixels_) {
225 pixelBytes.assign(pixels_, pixels_ + CountBytes());
226 } else {
227 pixelBytes.resize(CountBytes());
228 }
229}
230
232 height = xpm.GetHeight();
233 width = xpm.GetWidth();
234 scale = 1;
235 pixelBytes.resize(CountBytes());
236 for (int y=0; y<height; y++) {
237 for (int x=0; x<width; x++) {
238 ColourDesired colour;
239 bool transparent = false;
240 xpm.PixelAt(x, y, colour, transparent);
241 SetPixel(x, y, colour, transparent ? 0 : 255);
242 }
243 }
244}
245
247}
248
249int RGBAImage::CountBytes() const noexcept {
250 return width * height * 4;
251}
252
253const unsigned char *RGBAImage::Pixels() const noexcept {
254 return &pixelBytes[0];
255}
256
257void RGBAImage::SetPixel(int x, int y, ColourDesired colour, int alpha) noexcept {
258 unsigned char *pixel = &pixelBytes[0] + (y*width+x) * 4;
259 // RGBA
260 pixel[0] = colour.GetRed();
261 pixel[1] = colour.GetGreen();
262 pixel[2] = colour.GetBlue();
263 pixel[3] = static_cast<unsigned char>(alpha);
264}
265
266// Transform a block of pixels from RGBA to BGRA with premultiplied alpha.
267// Used for DrawRGBAImage on some platforms.
268void RGBAImage::BGRAFromRGBA(unsigned char *pixelsBGRA, const unsigned char *pixelsRGBA, size_t count) noexcept {
269 for (size_t i = 0; i < count; i++) {
270 const unsigned char alpha = pixelsRGBA[3];
271 // Input is RGBA, output is BGRA with premultiplied alpha
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;
278 }
279}
280
281RGBAImageSet::RGBAImageSet() : height(-1), width(-1) {
282}
283
285 Clear();
286}
287
288/// Remove all images.
289void RGBAImageSet::Clear() noexcept {
290 images.clear();
291 height = -1;
292 width = -1;
293}
294
295/// Add an image.
296void RGBAImageSet::Add(int ident, RGBAImage *image) {
297 ImageMap::iterator it=images.find(ident);
298 if (it == images.end()) {
299 images[ident] = std::unique_ptr<RGBAImage>(image);
300 } else {
301 it->second.reset(image);
302 }
303 height = -1;
304 width = -1;
305}
306
307/// Get image by id.
309 ImageMap::iterator it = images.find(ident);
310 if (it != images.end()) {
311 return it->second.get();
312 }
313 return nullptr;
314}
315
316/// Give the largest height of the set.
318 if (height < 0) {
319 for (const std::pair<const int, std::unique_ptr<RGBAImage>> &image : images) {
320 if (height < image.second->GetHeight()) {
321 height = image.second->GetHeight();
322 }
323 }
324 }
325 return (height > 0) ? height : 0;
326}
327
328/// Give the largest width of the set.
330 if (width < 0) {
331 for (const std::pair<const int, std::unique_ptr<RGBAImage>> &image : images) {
332 if (width < image.second->GetWidth()) {
333 width = image.second->GetWidth();
334 }
335 }
336 }
337 return (width > 0) ? width : 0;
338}
Interface to platform facilities.
Define a classes to hold image data in the X Pixmap (XPM) and RGBA formats.
A geometric rectangle class.
Definition: Platform.h:131
static constexpr PRectangle FromInts(int left_, int top_, int right_, int bottom_) noexcept
Definition: Platform.h:142
constexpr XYPOSITION Height() const noexcept
Definition: Platform.h:177
constexpr XYPOSITION Width() const noexcept
Definition: Platform.h:176
int GetHeight() const
Give the largest height of the set.
Definition: XPM.cxx:317
int GetWidth() const
Give the largest width of the set.
Definition: XPM.cxx:329
void Add(int ident, RGBAImage *image)
Add an image.
Definition: XPM.cxx:296
RGBAImage * Get(int ident)
Get image by id.
Definition: XPM.cxx:308
void Clear() noexcept
Remove all images.
Definition: XPM.cxx:289
int width
Memorize largest width of the set.
Definition: XPM.h:79
ImageMap images
Definition: XPM.h:77
int height
Memorize largest height of the set.
Definition: XPM.h:78
A translucent image stored as a sequence of RGBA bytes.
Definition: XPM.h:47
std::vector< unsigned char > pixelBytes
Definition: XPM.h:51
void SetPixel(int x, int y, ColourDesired colour, int alpha) noexcept
Definition: XPM.cxx:257
static void BGRAFromRGBA(unsigned char *pixelsBGRA, const unsigned char *pixelsRGBA, size_t count) noexcept
Definition: XPM.cxx:268
virtual ~RGBAImage()
Definition: XPM.cxx:246
RGBAImage(int width_, int height_, float scale_, const unsigned char *pixels_)
Definition: XPM.cxx:222
const unsigned char * Pixels() const noexcept
Definition: XPM.cxx:253
int CountBytes() const noexcept
Definition: XPM.cxx:249
A surface abstracts a place to draw.
Definition: Platform.h:340
virtual void FillRectangle(PRectangle rc, ColourDesired back)=0
Hold a pixmap in XPM format.
Definition: XPM.h:16
int height
Definition: XPM.h:17
int width
Definition: XPM.h:18
void FillRun(Surface *surface, int code, int startX, int y, int x) const
Definition: XPM.cxx:73
char codeTransparent
Definition: XPM.h:22
int GetWidth() const noexcept
Definition: XPM.h:38
void PixelAt(int x, int y, ColourDesired &colour, bool &transparent) const noexcept
Definition: XPM.cxx:172
void Draw(Surface *surface, const PRectangle &rc)
Decompose image into runs and use FillRectangle for each run.
Definition: XPM.cxx:150
ColourDesired colourCodeTable[256]
Definition: XPM.h:21
static std::vector< const char * > LinesFormFromTextForm(const char *textForm)
Definition: XPM.cxx:187
XPM(const char *textForm)
Definition: XPM.cxx:80
int GetHeight() const noexcept
Definition: XPM.h:37
std::vector< unsigned char > pixels
Definition: XPM.h:20
int nColours
Definition: XPM.h:19
void Init(const char *textForm)
Definition: XPM.cxx:91
ColourDesired ColourFromCode(int ch) const noexcept
Definition: XPM.cxx:69
#define fill(Order, Group, Idx, Charset, Name)
Definition: encodings.c:62
unsigned int count
Styling buffer using one element for each run rather than using a filled buffer.
Definition: Converter.h:9