1 //------------------------------------------------------------------------------
2 // emImage.h
3 //
4 // Copyright (C) 2001,2003-2010,2014,2018,2020 Oliver Hamann.
5 //
6 // Homepage: http://eaglemode.sourceforge.net/
7 //
8 // This program is free software: you can redistribute it and/or modify it under
9 // the terms of the GNU General Public License version 3 as published by the
10 // Free Software Foundation.
11 //
12 // This program is distributed in the hope that it will be useful, but WITHOUT
13 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 // FOR A PARTICULAR PURPOSE. See the GNU General Public License version 3 for
15 // more details.
16 //
17 // You should have received a copy of the GNU General Public License version 3
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 //------------------------------------------------------------------------------
20
21 #ifndef emImage_h
22 #define emImage_h
23
24 #ifndef emColor_h
25 #include <emCore/emColor.h>
26 #endif
27
28 #ifndef emATMatrix_h
29 #include <emCore/emATMatrix.h>
30 #endif
31
32 class emRootContext;
33 class emPainter;
34
35
36 //==============================================================================
37 //================================== emImage ===================================
38 //==============================================================================
39
40 class emImage {
41
42 public:
43
44 // Class for an image with copy-on-write behavior. Such an image
45 // consists of a three-dimensional array of bytes. The dimensions are X,
46 // Y and color channel.
47 //
48 // An image can have one, two, three or four channels. Each channel has
49 // one byte per pixel. The meaning of the channels depends on the number
50 // of channels:
51 //
52 // ChannelCount = 1: Grey image without alpha
53 // channel 0: grey components.
54 // ChannelCount = 2: Grey image with alpha
55 // channel 0: grey components.
56 // channel 1: alpha components.
57 // ChannelCount = 3: Color image without alpha
58 // channel 0: red components.
59 // channel 1: green components.
60 // channel 2: blue components.
61 // ChannelCount = 4: Color image with alpha
62 // channel 0: red components.
63 // channel 1: green components.
64 // channel 2: blue components.
65 // channel 3: alpha components.
66 //
67 // Like in most computer graphics, the origin of the image is in the
68 // upper-left corner, the X-axis points to the right, and the Y-axis
69 // points down. Pixels are areas and not points.
70
71 emImage();
72 // Construct an empty image. It has Width==0, Height==0 and
73 // ChannelCount==1.
74
75 emImage(const emImage & img);
76 // Construct a copied image.
77
78 emImage(int width, int height, int channelCount);
79 // Construct with the given dimensions. The pixel map is not
80 // initialized.
81 // Arguments:
82 // width - Horizontal extent in pixels.
83 // height - Vertical extent in pixels.
84 // channelCount - Number of channels (bytes per pixel, 1-4).
85
86 ~emImage();
87 // Destructor.
88
89 emImage & operator = (const emImage & img);
90 // Copy an image.
91
92 bool operator == (const emImage & image) const;
93 bool operator != (const emImage & image) const;
94 // Compare images.
95
96 void Setup(int width, int height, int channelCount);
97 // Set the dimensions of this image. This method does not care
98 // about preserving the contents.
99 // Arguments:
100 // width - Horizontal extent in pixels.
101 // height - Vertical extent in pixels.
102 // channelCount - Number of channels (bytes per pixel, 1-4).
103
104 void SetUserMap(int width, int height, int channelCount, emByte * map);
105 // Prepare this image for being an interface to a user allocated
106 // pixel map. For example, this feature could be used for
107 // exchanging image data between system processes through shared
108 // memory. You should know about the following semantics: The
109 // copy-on-write behavior is disabled for such a "user map
110 // image", and the user map feature is never copied. That means,
111 // when copying a user map image to another image, a deep copy
112 // is performed immediately and the target image will be a
113 // normal image. Each operation which actually changes the
114 // dimensions of the image, will give up the user map feature
115 // and revert to the normal behavior. This means for example,
116 // calling Setup preserves the feature if the dimensions are not
117 // really changed. Call Clear or '=' if you want to revert to
118 // the normal behavior in any case.
119 // Arguments:
120 // width - Horizontal extent of the user map in pixels.
121 // height - Vertical extent of the user map in pixels.
122 // channelCount - Number of channels in the user map (bytes
123 // per pixel, 1-4).
124 // map - The user allocated pixel map. It's what you
125 // will get through GetMap(). If channelCount
126 // is 2 or 4, the map address must be aligned
127 // accordingly.
128
129 bool HasUserMap() const;
130 // Ask whether this image interfaces a user allocated pixel map.
131
132 void TryParseXpm(const char * const * xpm, int channelCount=-1);
133 // Set this image by parsing an X Pixmap (XPM). The idea is to
134 // include an XPM file in the C++ source, and to convert it to
135 // an emImage at run-time using this method.
136 // Arguments:
137 // xpm - The X Pixmap data array.
138 // channelCount - Channel count of the returned image (1-4),
139 // or -1 to select the best channel count from
140 // the X Pixmap.
141 // Throws: An error message on failure.
142
143 void TryParseTga(const unsigned char * tgaData, size_t tgaSize,
144 int channelCount=-1);
145 // -------------------------------------------------------------
146 // This method is deprecated and should not be used any longer.
147 // -------------------------------------------------------------
148 // Set this image by parsing a Targa image (TGA). The idea is
149 // to convert a run-length encoded TGA file to a C source file,
150 // and to include that source file in the C++ source, and to
151 // convert it to an emImage at run-time using this function.
152 // Arguments:
153 // tgaData - Byte array with the contents of a TGA file.
154 // tgaSize - Number of bytes in the array.
155 // channelCount - Channel count of the returned image (1-4),
156 // or -1 to select the best channel count from
157 // the TGA image.
158 // Throws: An error message on failure.
159
160 void Clear();
161 // Empty this image. This is like Setup(0,0,1).
162
163 bool IsEmpty() const;
164 // Ask whether this image is empty. It is empty if at least one
165 // of width and height is zero.
166
167 int GetWidth() const;
168 int GetHeight() const;
169 int GetChannelCount() const;
170 // Get the dimensions of this image.
171
172 const emByte * GetMap() const;
173 // Get a pointer to the pixel map of this image. If ChannelCount
174 // is 2 or 4, the map address is aligned accordingly. At least
175 // because of the copy-on-write feature, the pointer is valid
176 // only until calling any non-const method or operator on this
177 // image, or giving this image as a non-const argument to any
178 // call in the world. Hint: Even methods like GetConverted,
179 // GetCropped and so on may make shallow copies, like the copy
180 // operator and copy constructor do.
181 // Index to the map is:
182 // (y*GetWidth()+x)*GetChannelCount()+c
183 // With:
184 // x: 0 to GetWidth()-1
185 // y: 0 to GetHeight()-1
186 // c: 0 to GetChannelCount()-1
187
188 emByte * GetWritableMap();
189 // Like GetMap(), but for modifying the image. The rules for
190 // validity of the pointer are the same as with GetMap(), but:
191 // The pointer must not be used for modifying after doing
192 // something which could have made a shallow copy of this image.
193
194 emColor GetPixel(int x, int y) const;
195 void SetPixel(int x, int y, emColor color);
196 // Get or set a pixel.
197
198 emByte GetPixelChannel(int x, int y, int channel) const;
199 void SetPixelChannel(int x, int y, int channel, emByte value);
200 // Get or set one channel of a pixel.
201
202 emColor GetPixelInterpolated(double x, double y, double w,
203 double h, emColor bgColor) const;
204 // Get an average color from a rectangular area. Performs
205 // bi-linear interpolation or area-sampling.
206 // Arguments:
207 // x,y,w,h - Upper-left corner and size of the rectangle.
208 // bgColor - A background color. It is used where the
209 // rectangle lies outside the image.
210 // Returns: The interpolated color.
211
212 void Fill(emColor color);
213 void Fill(int x, int y, int w, int h, emColor color);
214 // Fill the whole image or a rectangular area with the given
215 // color.
216
217 void FillChannel(int channel, emByte value=0);
218 void FillChannel(int x, int y, int w, int h, int channel,
219 emByte value);
220 // Like Fill, but for modifying just a single channel.
221
222 void Copy(int x, int y, const emImage & img);
223 void Copy(int x, int y, const emImage & img,
224 int srcX, int srcY, int w, int h);
225 // Copy a rectangular area of pixels from a source image to this
226 // image. Source and target may overlap.
227 // Arguments:
228 // x,y - Upper-left corner of target rectangle on
229 // this image.
230 // img - The source image.
231 // srcX,srcY,w,h - Upper-left corner and size of the rectangle
232 // on the source image, which is to be copied.
233 // Without these arguments, the whole source
234 // image is taken.
235
236 void CopyChannel(int x, int y, int channel, const emImage & img,
237 int srcChannel);
238 void CopyChannel(int x, int y, int channel, const emImage & img,
239 int srcX, int srcY, int w, int h, int srcChannel);
240 // Copy one channel of a rectangular area of pixels from a
241 // source image to this image. Source and target may overlap.
242 // Arguments:
243 // x,y - Upper-left corner of target rectangle on
244 // this image.
245 // channel - Target channel on this image.
246 // img - The source image.
247 // srcX,srcY,w,h - Upper-left corner and size of the rectangle
248 // on the source image, which is to be copied.
249 // Without these arguments, the whole source
250 // image is taken.
251 // srcChannel - Source channel on the given image.
252
253 void CopyTransformed(int x, int y, int w, int h,
254 const emATMatrix & atm, const emImage & img,
255 bool interpolate=false, emColor bgColor=0);
256 // Copy an image to this image while performing an affine
257 // transformation. Source and target must not overlap.
258 // Arguments:
259 // x,y,w,h - A clipping rectangle for the operation on
260 // this image. Exactly this area of pixels is
261 // modified.
262 // atm - A transformation matrix for transforming
263 // source image coordinates to coordinates of
264 // this image.
265 // img - The source image.
266 // interpolate - Whether to perform bi-linear interpolation.
267 // bgColor - A color to be used for areas outside the
268 // source image.
269
270 emImage GetTransformed(const emATMatrix & atm, bool interpolate=false,
271 emColor bgColor=0, int channelCount=-1) const;
272 // Get an affine transformed version of this image.
273 // Arguments:
274 // atm - A transformation matrix for transforming
275 // coordinates of this image to coordinates of
276 // the returned image. Here, any translation
277 // will be ignored.
278 // interpolate - Whether to perform bi-linear interpolation.
279 // bgColor - A color to be used for areas outside the
280 // source image.
281 // channelCount - Number of channels in the returned image
282 // (1-4), or -1 for taking the channel count of
283 // this image.
284 // Returns: The resulting image.
285
286 void CalcMinMaxRect(int * pX, int * pY, int * pW, int * pH,
287 emColor bgColor) const;
288 // Calculate the smallest rectangle which contains all pixels
289 // which are not equal to the given background color.
290 // Arguments:
291 // pX,pY,pW,pH - Pointers for returning the rectangle.
292 // bgColor - The background color.
293
294 void CalcChannelMinMaxRect(int * pX, int * pY, int * pW, int * pH,
295 int channel, emByte bgValue) const;
296 // Like CalcMinMaxRect, but for a single channel.
297 // Arguments:
298 // pX,pY,pW,pH - Pointers for returning the rectangle.
299 // channel - The channel to be inspected.
300 // bgValue - The channel value of the background color.
301
302 void CalcAlphaMinMaxRect(int * pX, int * pY, int * pW,
303 int * pH) const;
304 // Calculate the smallest rectangle which contains all pixels
305 // which are not zero in the alpha channel.
306 // Arguments:
307 // pX,pY,pW,pH - Pointers for returning the rectangle.
308
309 emImage GetConverted(int channelCount) const;
310 // Get a copy of this image, converted to the given number of
311 // channels.
312
313 emImage GetCropped(int x, int y, int w, int h,
314 int channelCount=-1) const;
315 // Get a sub-image of this image.
316 // Arguments:
317 // x,y,w,h - A rectangle on this image. It's the area to
318 // be copied to the returned image, which will
319 // have the size of that rectangle (after
320 // clipping it by the image boundaries).
321 // channelCount - Number of channels of the returned image
322 // (1-4), or -1 for taking the channel count of
323 // this image.
324 // Returns: The sub-image.
325
326 emImage GetCroppedByAlpha(int channelCount=-1) const;
327 // Like GetCropped with a rectangle returned by
328 // GetAlphaMinMaxRect.
329
330 bool PreparePainter(emPainter * painter, emRootContext & rootContext,
331 double clipX1=0.0, double clipY1=0.0,
332 double clipX2=3E9, double clipY2=3E9,
333 double originX=0.0, double originY=0.0,
334 double scaleX=1.0, double scaleY=1.0);
335 // Prepare the given painter for painting to this image with
336 // the given clipping and transformation. IMPORTANT: Currently,
337 // the image must have 4 channels, otherwise painting would not
338 // be possible. But the alpha channel cannot be painted and may
339 // be damaged by the painter. In a near future version of
340 // emPainter, the image may have to have 3 channels. And in a
341 // far future version, any channel count may be acceptable. If
342 // painting is not possible due to the channel count, the
343 // painter is disabled and false is returned. If you want to
344 // paint to an image in a portable way, please poll for a
345 // suitable channel count via IsChannelCountPaintable and
346 // prepare the image accordingly. After painting, you may
347 // convert the image to the desired channel count, or you could
348 // copy channels around. The rules for usability of the painter
349 // are like with a pointer returned by GetWritableMap().
350
351 static bool IsChannelCountPaintable(int channelCount);
352 // Ask whether PreparePainter would be successful for an image
353 // of the given channel count.
354
355 unsigned int GetDataRefCount() const;
356 // Get number of references to the data behind this image.
357
358 void MakeNonShared();
359 // This must be called before handing the image to another
360 // thread.
361
362 private:
363
364 void MakeWritable();
365 void FreeData();
366
367 struct SharedData {
368 unsigned int RefCount;
369 int Width;
370 int Height;
371 emByte ChannelCount;
372 emByte IsUsersMap;
373 emByte * Map;
374 // From here on comes the non-user map.
375 };
376
377 SharedData * Data;
378
379 static SharedData EmptyData;
380 };
381
382 #ifndef EM_NO_DATA_EXPORT
emImage()383 inline emImage::emImage()
384 {
385 Data=&EmptyData;
386 }
387 #endif
388
emImage(const emImage & img)389 inline emImage::emImage(const emImage & img)
390 {
391 Data=img.Data;
392 Data->RefCount++;
393 if (Data->IsUsersMap) MakeWritable();
394 }
395
~emImage()396 inline emImage::~emImage()
397 {
398 if (!--Data->RefCount) FreeData();
399 }
400
401 inline bool emImage::operator != (const emImage & image) const
402 {
403 return !(*this == image);
404 }
405
HasUserMap()406 inline bool emImage::HasUserMap() const
407 {
408 return Data->IsUsersMap!=0;
409 }
410
411 #ifndef EM_NO_DATA_EXPORT
Clear()412 inline void emImage::Clear()
413 {
414 if (!--Data->RefCount) FreeData();
415 Data=&EmptyData;
416 }
417 #endif
418
IsEmpty()419 inline bool emImage::IsEmpty() const
420 {
421 return Data->Width==0 || Data->Height==0;
422 }
423
GetWidth()424 inline int emImage::GetWidth() const
425 {
426 return Data->Width;
427 }
428
GetHeight()429 inline int emImage::GetHeight() const
430 {
431 return Data->Height;
432 }
433
GetChannelCount()434 inline int emImage::GetChannelCount() const
435 {
436 return Data->ChannelCount;
437 }
438
GetMap()439 inline const emByte * emImage::GetMap() const
440 {
441 return Data->Map;
442 }
443
GetWritableMap()444 inline emByte * emImage::GetWritableMap()
445 {
446 if (Data->RefCount>1) MakeWritable();
447 return Data->Map;
448 }
449
Fill(emColor color)450 inline void emImage::Fill(emColor color)
451 {
452 Fill(0,0,Data->Width,Data->Height,color);
453 }
454
FillChannel(int channel,emByte value)455 inline void emImage::FillChannel(int channel, emByte value)
456 {
457 FillChannel(0,0,Data->Width,Data->Height,channel,value);
458 }
459
Copy(int x,int y,const emImage & img)460 inline void emImage::Copy(int x, int y, const emImage & img)
461 {
462 Copy(x,y,img,0,0,img.Data->Width,img.Data->Height);
463 }
464
CopyChannel(int x,int y,int channel,const emImage & img,int srcChannel)465 inline void emImage::CopyChannel(
466 int x, int y, int channel, const emImage & img, int srcChannel
467 )
468 {
469 CopyChannel(
470 x,y,channel,img,
471 0,0,img.Data->Width,img.Data->Height,
472 srcChannel
473 );
474 }
475
GetConverted(int channelCount)476 inline emImage emImage::GetConverted(int channelCount) const
477 {
478 return GetCropped(0,0,Data->Width,Data->Height,channelCount);
479 }
480
MakeNonShared()481 inline void emImage::MakeNonShared()
482 {
483 MakeWritable();
484 }
485
486
487 #endif
488