SMIL  0.9.1
DImageDraw.hpp
1 /*
2  * Copyright (c) 2011-2016, Matthieu FAESSEL and ARMINES
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of Matthieu FAESSEL, or ARMINES nor the
14  * names of its contributors may be used to endorse or promote products
15  * derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 
30 #ifndef _D_IMAGE_DRAW_HPP
31 #define _D_IMAGE_DRAW_HPP
32 
33 #include "DLineArith.hpp"
34 #include "Base/include/DImageDraw.h"
35 
36 #ifdef USE_FREETYPE
37  #include <ft2build.h>
38  #include FT_FREETYPE_H
39 #endif // USE_FREETYPE
40 
41 
42 namespace smil
43 {
44 
60  template <class T>
61  RES_T drawLine(Image<T> &im, int x0, int y0, int x1, int y1, T value=ImDtTypes<T>::max())
62  {
63  if (!im.isAllocated())
64  return RES_ERR_BAD_ALLOCATION;
65 
66  size_t imW = im.getWidth();
67  size_t imH = im.getHeight();
68 
69  vector<IntPoint> bPoints;
70  if ( x0<0 || x0>=int(imW) || y0<0 || y0>=int(imH) || x1<0 || x1>=int(imW) || y1<0 || y1>=int(imH) )
71  bPoints = bresenhamPoints(x0, y0, x1, y1, imW, imH);
72  else
73  bPoints = bresenhamPoints(x0, y0, x1, y1); // no image range check (faster)
74 
75  typename Image<T>::sliceType lines = im.getLines();
76 
77  for(vector<IntPoint>::iterator it=bPoints.begin();it!=bPoints.end();it++)
78  lines[(*it).y][(*it).x] = value;
79 
80  im.modified();
81  return RES_OK;
82  }
83 
91  template <class T>
92  RES_T drawLine(Image<T> &imOut, vector<UINT> coords, T value=ImDtTypes<T>::max())
93  {
94  if (coords.size()!=4)
95  return RES_ERR;
96  return drawLine<T>(imOut, coords[0], coords[1], coords[2], coords[3], value);
97  }
98 
99 
100 
112  template <class T>
113  RES_T drawRectangle(Image<T> &imOut, int x0, int y0, size_t width, size_t height, T value=ImDtTypes<T>::max(), bool fill=false, size_t zSlice=0)
114  {
115  ASSERT_ALLOCATED(&imOut);
116 
117  ImageFreezer freeze(imOut);
118 
119  size_t imW = imOut.getWidth();
120  size_t imH = imOut.getHeight();
121  size_t imD = imOut.getDepth();
122 
123  ASSERT((zSlice<imD), "zSlice is out of range", RES_ERR);
124 
125  size_t x1 = x0 + width - 1;
126  size_t y1 = y0 + height -1;
127  x1 = x1<imW ? x1 : imW-1;
128  y1 = y1<imH ? y1 : imH-1;
129 
130  x0 = x0>=0 ? x0 : 0;
131  y0 = y0>=0 ? y0 : 0;
132 
133  typename Image<T>::volType slices = imOut.getSlices();
134  const typename Image<T>::sliceType lines = slices[zSlice];
135  fillLine<T> fillFunc;
136 
137  if (fill)
138  {
139  for (size_t j=y0;j<=y1;j++)
140  fillFunc(lines[j]+x0, width, value);
141  }
142  else
143  {
144  fillFunc(lines[y0]+x0, width, value);
145  fillFunc(lines[y1]+x0, width, value);
146  for (size_t j=y0+1;j<=y1;j++)
147  {
148  lines[j][x0] = value;
149  lines[j][x1] = value;
150  }
151  }
152 
153  return RES_OK;
154  }
155 
156 
157  template <class T>
158  RES_T drawRectangle(Image<T> &imOut, vector<UINT> coords, T value=ImDtTypes<T>::max(), bool fill=false)
159  {
160  if (coords.size()!=4)
161  return RES_ERR;
162  return drawRectangle<T>(imOut, coords[0], coords[1], coords[2]-coords[0]+1, coords[3]-coords[1]+1, value, fill);
163  }
164 
169  template <class T, class MapT>
170  RES_T drawRectangles(Image<T> &imOut, const map<MapT, vector<size_t> > &coordsVectMap, bool fill=false)
171  {
172  ASSERT_ALLOCATED(&imOut);
173  ImageFreezer freeze(imOut);
174 
175  typename map<MapT, vector<size_t> >::const_iterator it = coordsVectMap.begin();
176  if (it->second.size()!=4)
177  return RES_ERR;
178  for (;it!=coordsVectMap.end();it++)
179  {
180  const vector<size_t> &coords = it->second;
181  T val = T(it->first);
182  if (drawRectangle<T>(imOut, coords[0], coords[1], coords[2]-coords[0]+1, coords[3]-coords[1]+1, val, fill)!=RES_OK)
183  return RES_ERR;
184  }
185  return RES_OK;
186  }
187 
188 
201  template <class T>
202  RES_T drawCircle(Image<T> &imOut, int x0, int y0, int radius, T value=ImDtTypes<T>::max(), size_t zSlice=0)
203  {
204  ASSERT_ALLOCATED(&imOut);
205  ASSERT((zSlice<imOut.getDepth()), "zSlice is out of range", RES_ERR);
206 
207  ImageFreezer freeze(imOut);
208 
209  int imW = imOut.getWidth();
210  int imH = imOut.getHeight();
211 
212  typename ImDtTypes<T>::sliceType lines = imOut.getSlices()[zSlice];
213 
214  int d = (5 - radius * 4) / 4;
215  int x = 0;
216  int y = radius;
217 // int ptX, ptY;
218 
219  do
220  {
221  if (x0+x >= 0 && x0+x <= imW-1 && y0+y >= 0 && y0+y <= imH-1) lines[y0+y][x0+x] = value;
222  if (x0+x >= 0 && x0+x <= imW-1 && y0-y >= 0 && y0-y <= imH-1) lines[y0-y][x0+x] = value;
223  if (x0-x >= 0 && x0-x <= imW-1 && y0+y >= 0 && y0+y <= imH-1) lines[y0+y][x0-x] = value;
224  if (x0-x >= 0 && x0-x <= imW-1 && y0-y >= 0 && y0-y <= imH-1) lines[y0-y][x0-x] = value;
225  if (x0+y >= 0 && x0+y <= imW-1 && y0+x >= 0 && y0+x <= imH-1) lines[y0+x][x0+y] = value;
226  if (x0+y >= 0 && x0+y <= imW-1 && y0-x >= 0 && y0-x <= imH-1) lines[y0-x][x0+y] = value;
227  if (x0-y >= 0 && x0-y <= imW-1 && y0+x >= 0 && y0+x <= imH-1) lines[y0+x][x0-y] = value;
228  if (x0-y >= 0 && x0-y <= imW-1 && y0-x >= 0 && y0-x <= imH-1) lines[y0-x][x0-y] = value;
229  if (d < 0)
230  {
231  d = d + (4 * x) + 6;
232  }
233  else
234  {
235  d = d + 4 * (x - y) + 10;
236  y--;
237  }
238  x++;
239  } while (x <= y);
240 
241  return RES_OK;
242  }
243 
252  template <class T>
253  RES_T drawSphere(Image<T> &imOut, int x0, int y0, int z0, int radius, T value=ImDtTypes<T>::max())
254  {
255  ASSERT_ALLOCATED(&imOut);
256 
257  ImageFreezer freeze(imOut);
258 
259  int imW = imOut.getWidth();
260  int imH = imOut.getHeight();
261  int imD = imOut.getDepth();
262 
263  int x1 = MAX(x0-radius, 0);
264  int y1 = MAX(y0-radius, 0);
265  int z1 = MAX(z0-radius, 0);
266 
267  int x2 = MIN(x0+radius, imW-1);
268  int y2 = MIN(y0+radius, imH-1);
269  int z2 = MIN(z0+radius, imD-1);
270 
271  int r2 = radius*radius;
272 
273 
274  typename Image<T>::volType slices = imOut.getSlices();
275  typename Image<T>::sliceType lines;
276  typename Image<T>::lineType curLine;
277 
278  for (int z=z1;z<=z2;z++)
279  {
280  lines = slices[z];
281  for (int y=y1;y<=y2;y++)
282  {
283  curLine = lines[y];
284  for (int x=x1;x<=x2;x++)
285  if ((x-x0)*(x-x0)+(y-y0)*(y-y0)+(z-z0)*(z-z0)<=r2)
286  curLine[x] = value;
287  }
288 
289  }
290 
291  return RES_OK;
292  }
293 
305  template <class T>
306  RES_T drawDisc(Image<T> &imOut, int x0, int y0, size_t zSlice, int radius, T value=ImDtTypes<T>::max())
307  {
308  ASSERT_ALLOCATED(&imOut);
309  ASSERT((zSlice<imOut.getDepth()), "zSlice is out of range", RES_ERR);
310 
311  ImageFreezer freeze(imOut);
312 
313  int imW = imOut.getWidth();
314  int imH = imOut.getHeight();
315 
316  int x1 = MAX(x0-radius, 0);
317  int y1 = MAX(y0-radius, 0);
318 
319  int x2 = MIN(x0+radius, imW-1);
320  int y2 = MIN(y0+radius, imH-1);
321 
322  int r2 = radius*radius;
323 
324 
325  typename Image<T>::sliceType lines = imOut.getSlices()[zSlice];
326  typename Image<T>::lineType curLine;
327 
328  for (int y=y1;y<=y2;y++)
329  {
330  curLine = lines[y];
331  for (int x=x1;x<=x2;x++)
332  if ((x-x0)*(x-x0)+(y-y0)*(y-y0)<=r2)
333  curLine[x] = value;
334  }
335 
336  return RES_OK;
337  }
338 
339  // 2D Overload
340  template <class T>
341  RES_T drawDisc(Image<T> &imOut, int x0, int y0, int radius, T value=ImDtTypes<T>::max())
342  {
343  return drawDisc(imOut, x0, y0, 0, radius, value);
344  }
345 
346 
357  template <class T>
358  RES_T drawBox(Image<T> &imOut, size_t x0, size_t y0, size_t z0, size_t width, size_t height, size_t depth, T value=ImDtTypes<T>::max(), bool fill=false)
359  {
360  ASSERT_ALLOCATED(&imOut);
361 
362  ImageFreezer freeze(imOut);
363 
364  ASSERT((drawRectangle(imOut, x0, y0, width, height, value, true, z0)==RES_OK));
365  for (size_t z=z0+1;z<z0+depth-1;z++)
366  ASSERT((drawRectangle(imOut, x0, y0, width, height, value, fill, z)==RES_OK));
367  ASSERT((drawRectangle(imOut, x0, y0, width, height, value, true, z0+depth-1)==RES_OK));
368 
369  return RES_OK;
370 
371  }
372 
373 
374  #ifdef USE_FREETYPE
375 
381  template <class T>
382  RES_T drawText(Image<T> &imOut, size_t x, size_t y, size_t z, string txt, string font, UINT size=20, T value=ImDtTypes<T>::max())
383  {
384  ASSERT_ALLOCATED(&imOut);
385 
386  size_t imW = imOut.getWidth();
387  size_t imH = imOut.getHeight();
388 
389  ASSERT((x>=0 && x<imW && y>=0 && y<imH && z>=0 && z<imOut.getDepth()), "Text position out of image range.", RES_ERR);
390 
391  FT_Library library;
392  FT_Face face;
393  FT_GlyphSlot slot;
394  const char *text = txt.c_str();
395 
396  ASSERT((!FT_Init_FreeType( &library )), "Problem initializing freetype library.", RES_ERR);
397  ASSERT((!FT_New_Face( library, font.c_str(), 0, &face )), "The font file could not be opened.", RES_ERR);
398  ASSERT((!FT_Set_Pixel_Sizes( face, 0, size )), "Error defining font size.", RES_ERR);
399 
400  slot = face->glyph;
401 
402  for (UINT c=0;c<txt.length();c++)
403  {
404  FT_Load_Char( face, text[c], FT_LOAD_NO_BITMAP | FT_LOAD_RENDER | FT_LOAD_TARGET_MONO);
405 
406  FT_Bitmap *bitmap = &slot->bitmap;
407 
408  FT_Int i, j, p, q;
409  FT_Int x_min = x + slot->bitmap_left;
410  FT_Int y_min = y - slot->bitmap_top;
411  FT_Int x_max = x_min + bitmap->width;
412  FT_Int y_max = y_min + bitmap->rows;
413 
414  typename ImDtTypes<T>::sliceType slc = imOut.getSlices()[z];
415 
416 
417  for ( j = y_min, q = 0; j < y_max; j++, q++ )
418  {
419  unsigned char *in = bitmap->buffer + q * bitmap->pitch;
420  typename ImDtTypes<T>::lineType out = slc[j];
421  unsigned char bit = 0x80;
422  for ( i = x_min, p = 0; i < x_max; i++, p++ )
423  {
424  if (i>=0 && j>=0 && i<(int)imW && j<(int)imH)
425  if (*in & bit)
426  out[i] = value;
427  bit >>= 1;
428  if (bit == 0)
429  {
430  bit = 0x80;
431  in++;
432  }
433  }
434  }
435  x += slot->advance.x >> 6;
436  y += slot->advance.y >> 6;
437  }
438 
439  FT_Done_Face ( face );
440  FT_Done_FreeType( library );
441 
442  imOut.modified();
443 
444  return RES_OK;
445  }
446 
447  template <class T>
448  RES_T drawText(Image<T> &imOut, size_t x, size_t y, string txt, string font, UINT size=20, T value=ImDtTypes<T>::max())
449  {
450  return drawText(imOut, x, y, 0, txt, font, size, value);
451  }
452 
453  #endif // USE_FREETYPE
454 
472  // TODO Extend to 3D
473  template <class T>
474  RES_T copyPattern(const Image<T> &imIn, int x0, int y0, int width, int height, Image<T> &imOut, int nbr_along_x, int nbr_along_y)
475  {
476  ASSERT_ALLOCATED(&imIn, &imOut)
477 
478  typename ImDtTypes<T>::sliceType linesIn = imIn.getSlices()[0];
479  typename ImDtTypes<T>::sliceType linesOut = imOut.getSlices()[0];
480 
481  size_t imSize[3];
482  imOut.getSize(imSize);
483 
484  int nX = min( int(ceil(double(imSize[0])/width)), nbr_along_x );
485  int xPad = imSize[0] % width;
486  int nXfull = xPad==0 ? nX : nX-1;
487 
488  int nY = min( int(ceil(double(imSize[1])/height)), nbr_along_y );
489  int yPad = imSize[1] % height;
490  int nYfull = yPad==0 ? nY : nY-1;
491 
492  size_t cpLen = nXfull*width + xPad;
493 
494 #ifdef USE_OPEN_MP
495  int nthreads = Core::getInstance()->getNumberOfThreads();
496  #pragma omp parallel num_threads(nthreads)
497 #endif // USE_OPEN_MP
498  {
499  // Copy along X
500 
501 #ifdef USE_OPEN_MP
502  #pragma omp for
503 #endif // USE_OPEN_MP
504  for (int j=0;j<height;j++)
505  {
506  typename ImDtTypes<T>::lineType lineIn = linesIn[y0+j] + x0;
507  typename ImDtTypes<T>::lineType lineOut = linesOut[j];
508 
509  for (int i=0;i<nXfull;i++)
510  {
511  copyLine<T>(lineIn, width, lineOut);
512  lineOut += width;
513  }
514  copyLine<T>(lineIn, xPad, lineOut);
515  }
516 
517 #ifdef USE_OPEN_MP
518  #pragma omp barrier
519 #endif // USE_OPEN_MP
520 
521  // Copy along Y
522 
523  for (int n=1;n<nYfull;n++)
524  {
525 #ifdef USE_OPEN_MP
526  #pragma omp for
527 #endif // USE_OPEN_MP
528  for (int j=0;j<height;j++)
529  {
530  typename ImDtTypes<T>::lineType lineIn = linesOut[j];
531  typename ImDtTypes<T>::lineType lineOut = linesOut[n*height + j];
532 
533  copyLine<T>(lineIn, cpLen, lineOut);
534  }
535  }
536  for (int n=nYfull;n<nY;n++)
537  {
538 #ifdef USE_OPEN_MP
539  #pragma omp for
540 #endif // USE_OPEN_MP
541  for (int j=0;j<yPad;j++)
542  {
543  typename ImDtTypes<T>::lineType lineIn = linesOut[j];
544  typename ImDtTypes<T>::lineType lineOut = linesOut[n*height + j];
545 
546  copyLine<T>(lineIn, cpLen, lineOut);
547  }
548  }
549  }
550 
551 
552  return RES_OK;
553 
554  }
555 
556  template <class T>
557  RES_T copyPattern(const Image<T> &imIn, int x0, int y0, int width, int height, Image<T> &imOut)
558  {
559  return copyPattern(imIn, x0, y0, width, height, imOut, numeric_limits<int>::max(), numeric_limits<int>::max());
560  }
561 
562  template <class T>
563  RES_T copyPattern(const Image<T> &imIn, Image<T> &imOut, int nbr_along_x, int nbr_along_y)
564  {
565  return copyPattern(imIn, 0, 0, imIn.getWidth(), imIn.getHeight(), imOut, nbr_along_x, nbr_along_y);
566  }
567 
568  template <class T>
569  RES_T copyPattern(const Image<T> &imIn, Image<T> &imOut)
570  {
571  return copyPattern(imIn, 0, 0, imIn.getWidth(), imIn.getHeight(), imOut, numeric_limits<int>::max(), numeric_limits<int>::max());
572  }
573 
574 
577 } // namespace smil
578 
579 
580 #endif // _D_IMAGE_DRAW_HPP
581 
RES_T drawRectangles(Image< T > &imOut, const map< MapT, vector< size_t > > &coordsVectMap, bool fill=false)
Draw a list of rectangles.
Definition: DImageDraw.hpp:170
Definition: DColorConvert.h:38
sliceType getLines() const
Get an array containing the start offset of each line.
Definition: DImage.hpp:114
Definition: DBaseImage.h:235
RES_T drawSphere(Image< T > &imOut, int x0, int y0, int z0, int radius, T value=ImDtTypes< T >::max())
Draw a sphere.
Definition: DImageDraw.hpp:253
RES_T drawRectangle(Image< T > &imOut, int x0, int y0, size_t width, size_t height, T value=ImDtTypes< T >::max(), bool fill=false, size_t zSlice=0)
Draw a rectangle.
Definition: DImageDraw.hpp:113
RES_T fill(Image< T > &imOut, const T &value)
Fill an image with a given value.
Definition: DImageArith.hpp:62
RES_T drawText(Image< T > &imOut, size_t x, size_t y, size_t z, string txt, string font, UINT size=20, T value=ImDtTypes< T >::max())
Draw text on image.
Definition: DImageDraw.hpp:382
bool isAllocated() const
Check if the image is allocated.
Definition: DBaseImage.h:163
RES_T drawDisc(Image< T > &imOut, int x0, int y0, size_t zSlice, int radius, T value=ImDtTypes< T >::max())
Draw a disc.
Definition: DImageDraw.hpp:306
RES_T drawLine(Image< T > &imOut, vector< UINT > coords, T value=ImDtTypes< T >::max())
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: DImageDraw.hpp:92
size_t getHeight() const
Get image height.
Definition: DBaseImage.h:91
Definition: DBaseImageOperations.hxx:39
RES_T drawCircle(Image< T > &imOut, int x0, int y0, int radius, T value=ImDtTypes< T >::max(), size_t zSlice=0)
Draw a circle.
Definition: DImageDraw.hpp:202
RES_T copyPattern(const Image< T > &imIn, int x0, int y0, int width, int height, Image< T > &imOut, int nbr_along_x, int nbr_along_y)
Copy a given pattern (zone of input image) several times in an output image.
Definition: DImageDraw.hpp:474
virtual void modified()
Trigger modified event (allows to force display update)
Definition: DImage.hxx:223
size_t getWidth() const
Get image width.
Definition: DBaseImage.h:87
Definition: DTypes.hpp:78
RES_T drawBox(Image< T > &imOut, size_t x0, size_t y0, size_t z0, size_t width, size_t height, size_t depth, T value=ImDtTypes< T >::max(), bool fill=false)
Draw a box (3D)
Definition: DImageDraw.hpp:358
Main Image class.
Definition: DQVtkViewer.hpp:44
volType getSlices() const
Get an array containing the start offset of each slice.
Definition: DImage.hpp:118
size_t getDepth() const
Get image depth (Z)
Definition: DBaseImage.h:95