g4tools  5.4.0
img
Go to the documentation of this file.
1 // Copyright (C) 2010, Guy Barrand. All rights reserved.
2 // See the file tools.license for terms.
3 
4 #ifndef tools_img
5 #define tools_img
6 
7 #ifdef TOOLS_MEM
8 #include "mem"
9 #endif
10 
11 #include <string> //memcpy
12 #include <cstring> //memcpy
13 #include "mnmx"
14 #include "S_STRING"
15 
16 #include <vector> //concatenate
17 
18 namespace tools {
19 
20 template <class T>
21 class img {
22 public:
24 public:
25  img()
26  :m_w(0),m_h(0),m_n(0)
27  ,m_buffer(0)
28  ,m_owner(false)
29  {
30 #ifdef TOOLS_MEM
31  mem::increment(s_class().c_str());
32 #endif
33  }
34  img(unsigned int a_w,unsigned int a_h,unsigned int a_n,T* a_buffer,bool a_owner)
35  :m_w(a_w),m_h(a_h),m_n(a_n)
36  ,m_buffer(a_buffer)
37  ,m_owner(a_owner)
38  {
39 #ifdef TOOLS_MEM
40  mem::increment(s_class().c_str());
41 #endif
42  }
43  virtual ~img() {
44  if(m_owner) delete [] m_buffer;
45 #ifdef TOOLS_MEM
46  mem::decrement(s_class().c_str());
47 #endif
48  }
49 public:
50  img(const img& a_from)
51  :m_w(a_from.m_w),m_h(a_from.m_h),m_n(a_from.m_n)
52  ,m_buffer(0)
53  ,m_owner(a_from.m_owner)
54  {
55 #ifdef TOOLS_MEM
56  mem::increment(s_class().c_str());
57 #endif
58  if(m_owner) {
59  unsigned int sz = m_w*m_h*m_n;
60  if(!sz) return;
61  m_buffer = new T[sz];
62  if(!m_buffer) {
63  m_w = 0;m_h = 0;m_n = 0;m_owner = false;
64  return; //throw
65  }
66  ::memcpy(m_buffer,a_from.m_buffer,sz*sizeof(T));
67  } else {
68  m_buffer = a_from.m_buffer;
69  }
70  }
71  img& operator=(const img& a_from){
72  if(&a_from==this) return *this;
73  if(m_owner) delete [] m_buffer;
74  m_buffer = 0;
75  m_w = a_from.m_w;
76  m_h = a_from.m_h;
77  m_n = a_from.m_n;
78  m_owner = a_from.m_owner;
79  if(m_owner) {
80  unsigned int sz = m_w*m_h*m_n;
81  if(!sz) return *this;
82  m_buffer = new T[sz];
83  if(!m_buffer) {
84  m_w = 0;m_h = 0;m_n = 0;m_owner = false;
85  return *this; //throw
86  }
87  ::memcpy(m_buffer,a_from.m_buffer,sz*sizeof(T));
88  } else {
89  m_buffer = a_from.m_buffer;
90  }
91  return *this;
92  }
93 public:
94  bool operator==(const img& a_from) const {return equal(a_from);}
95  bool operator!=(const img& a_from) const {return !operator==(a_from);}
96 public:
97  void transfer(img& a_from) {
98  if(m_owner) delete [] m_buffer;
99  m_w = a_from.m_w;
100  m_h = a_from.m_h;
101  m_n = a_from.m_n;
102  m_buffer = a_from.m_buffer;
103  m_owner = a_from.m_owner;
104  // empty a_from :
105  a_from.m_w = 0;
106  a_from.m_h = 0;
107  a_from.m_buffer = 0;
108  a_from.m_owner = false;
109  }
110 
111  void clear() {
112  if(m_owner) delete [] m_buffer;
113  m_w = 0;
114  m_h = 0;
115  m_n = 0;
116  m_buffer = 0;
117  m_owner = false;
118  }
119  void set(unsigned int a_w,unsigned int a_h,unsigned int a_n,T* a_buffer,bool a_owner) {
120  if(m_owner) delete [] m_buffer;
121  m_w = a_w;
122  m_h = a_h;
123  m_n = a_n;
124  m_buffer = a_buffer;
125  m_owner = a_owner;
126  }
127  bool copy(unsigned int a_w,unsigned int a_h,unsigned int a_n,T* a_buffer) {
128  if(m_owner) delete [] m_buffer;
129  m_buffer = 0;
130  m_w = a_w;
131  m_h = a_h;
132  m_n = a_n;
133  unsigned int sz = m_w*m_h*m_n;
134  if(!sz) {
135  m_w = 0;m_h = 0;m_n = 0;m_owner = false;
136  return false;
137  }
138  m_buffer = new T[sz];
139  if(!m_buffer) {
140  m_w = 0;m_h = 0;m_n = 0;m_owner = false;
141  return false;
142  }
143  ::memcpy(m_buffer,a_buffer,sz*sizeof(T));
144  m_owner = true;
145  return true;
146  }
147  bool copy(const img& a_from){
148  if(m_owner) delete [] m_buffer;
149  m_buffer = 0;
150  m_w = a_from.m_w;
151  m_h = a_from.m_h;
152  m_n = a_from.m_n;
153  unsigned int sz = m_w*m_h*m_n;
154  if(!sz) {
155  m_w = 0;m_h = 0;m_n = 0;m_owner = false;
156  return false;
157  }
158  m_buffer = new T[sz];
159  if(!m_buffer) {
160  m_w = 0;m_h = 0;m_n = 0;m_owner = false;
161  return false;
162  }
163  ::memcpy(m_buffer,a_from.m_buffer,sz*sizeof(T));
164  m_owner = true;
165  return true;
166  }
167  bool allocate(unsigned int a_w,unsigned int a_h,unsigned int a_n){
168  if(m_owner) delete [] m_buffer;
169  m_buffer = 0;
170  unsigned int sz = a_w*a_h*a_n;
171  if(!sz) {
172  m_w = 0;m_h = 0;m_n = 0;m_owner = false;
173  return false;
174  }
175  m_w = a_w;
176  m_h = a_h;
177  m_n = a_n;
178  m_buffer = new T[sz];
179  if(!m_buffer) {
180  m_w = 0;m_h = 0;m_n = 0;m_owner = false;
181  return false;
182  }
183  m_owner = true;
184  return true;
185  }
186  void make_empty(bool a_delete = true) {
187  if(m_owner && a_delete) delete [] m_buffer;
188  m_w = 0;
189  m_h = 0;
190  m_n = 0;
191  m_buffer = 0;
192  m_owner = false;
193  }
194  bool is_empty() const {
195  if(!m_w) return true;
196  if(!m_h) return true;
197  if(!m_n) return true;
198  if(!m_buffer) return true;
199  return false;
200  }
201  bool equal(const img& a_from) const {
202  if(m_w!=a_from.m_w) return false;
203  if(m_h!=a_from.m_h) return false;
204  if(m_n!=a_from.m_n) return false;
205  //don't test ownership.
206  unsigned int sz = m_w*m_h*m_n;
207  T* pos = m_buffer;
208  T* fpos = a_from.m_buffer;
209  for(unsigned int index=0;index<sz;index++,pos++,fpos++) {
210  if((*pos)!=(*fpos)) return false;
211  }
212  return true;
213  }
214  unsigned int width() const {return m_w;}
215  unsigned int height() const {return m_h;}
216  unsigned int bytes_per_pixel() const {return m_n;}
217  unsigned int bpp() const {return m_n;}
218  const T* buffer() const {return m_buffer;}
219  T* buffer() {return m_buffer;}
220  bool owner() const {return m_owner;}
221  unsigned int size() const {return m_w*m_h*m_n*sizeof(T);} //bytes.
222 public:
223  bool pixel(unsigned int a_i,unsigned a_j,std::vector<T>& a_pixel) const {
224  if((!m_w)||(!m_h)||(a_i>=m_w)||(a_j>=m_h)) {
225  a_pixel.clear();
226  return false;
227  }
228  a_pixel.resize(m_n);
229  T* pos = m_buffer + a_j * (m_w * m_n) + a_i*m_n;
230  for(unsigned int ipix=0;ipix<m_n;ipix++) {
231  a_pixel[ipix] = *(pos+ipix);
232  }
233  return true;
234  }
235 
236  bool expand(unsigned int a_factor,img<T>& a_res,bool a_res_force_owner = true) const {
237  if(a_factor==1) {
238  if(a_res_force_owner) {
239  a_res.copy(m_w,m_h,m_n,m_buffer);
240  } else {
241  a_res.set(m_w,m_h,m_n,m_buffer,false);
242  }
243  return true;
244  }
245 
246  unsigned int nw = m_w*a_factor;
247  unsigned int nh = m_h*a_factor;
248  unsigned int sz = nh*nw*m_n;
249  if(!sz) {
250  a_res.make_empty();
251  return false;
252  }
253 
254  T* nb = new T[sz];
255  if(!nb) {
256  a_res.make_empty();
257  return false;
258  }
259 
260  for(unsigned int j=0;j<m_h;j++) {
261  for(unsigned int i=0;i<m_w;i++) {
262  //position in the original image.
263  T* pos = m_buffer + j * (m_w * m_n) + i*m_n;
264 
265  for(unsigned int fr=0;fr<a_factor;fr++) {
266  for(unsigned int fc=0;fc<a_factor;fc++) {
267  //position in the new image.
268  T* npos = nb + (j*a_factor+fr) * (nw * m_n) + (i*a_factor+fc)*m_n;
269  for(unsigned int ipix=0;ipix<m_n;ipix++) {
270  *(npos+ipix) = *(pos+ipix);
271  }
272  }
273  }
274 
275  }
276  }
277 
278  a_res.set(nw,nh,m_n,nb,true);
279  return true;
280  }
281 
282  bool contract_raw(unsigned int a_w,unsigned int a_h,img<T>& a_res,bool a_force_res_owner = true) const {
283  if((a_w==m_w)&&(a_h==m_h)) {
284  if(a_force_res_owner) {
285  a_res.copy(m_w,m_h,m_n,m_buffer);
286  } else {
287  a_res.set(m_w,m_h,m_n,m_buffer,false);
288  }
289  return true;
290  }
291 
292  unsigned int sz = a_h*a_w*m_n;
293  if(!sz) {
294  a_res.make_empty();
295  return false;
296  }
297 
298  T* rb = new T[sz];
299  if(!rb) {
300  a_res.make_empty();
301  return false;
302  }
303 
304  double* pixels = new double[m_n]; //for mean value.
305  if(!pixels) {
306  delete [] rb;
307  a_res.make_empty();
308  return false;
309  }
310 
311  unsigned int wfac = double(m_w)/double(a_w);
312  unsigned int hfac = double(m_h)/double(a_h);
313  if(!wfac) wfac = 1;
314  if(!hfac) hfac = 1;
315 
316  unsigned int wfac_hfac = wfac*hfac;
317 
318  T* hpos;T* pos;
319  for(unsigned int j=0;j<a_h;j++) {
320  for(unsigned int i=0;i<a_w;i++) {
321 
322  // take mean value of wfac*hfac pixels :
323  {for(unsigned int ipix=0;ipix<m_n;ipix++) pixels[ipix] = 0;}
324 
325  for(unsigned int fr=0;fr<hfac;fr++) {
326  hpos = m_buffer + (j*hfac+fr)*(m_w*m_n);
327  for(unsigned int fc=0;fc<wfac;fc++) {
328  pos = hpos + (i*wfac+fc)*m_n;
329  for(unsigned int ipix=0;ipix<m_n;ipix++) {
330  pixels[ipix] += double(*pos)/double(wfac_hfac);pos++;
331  }
332  }
333  }
334 
335  //position in the result image.
336  T* rpos = rb + j * (a_w * m_n) + i*m_n;
337  {for(unsigned int ipix=0;ipix<m_n;ipix++) {*rpos = T(pixels[ipix]);rpos++;}}
338  }
339  }
340 
341  delete [] pixels;
342 
343  a_res.set(a_w,a_h,m_n,rb,true);
344  return true;
345  }
346 
347  bool contract(unsigned int a_w,unsigned int a_h,img<T>& a_res,bool a_force_res_owner = true) const {
348  //optimized version of contract_raw().
349 
350  if((a_w==m_w)&&(a_h==m_h)) {
351  if(a_force_res_owner) {
352  a_res.copy(m_w,m_h,m_n,m_buffer);
353  } else {
354  a_res.set(m_w,m_h,m_n,m_buffer,false);
355  }
356  return true;
357  }
358 
359  size_t sz = a_h*a_w*m_n;
360  if(!sz) {
361  a_res.make_empty();
362  return false;
363  }
364 
365  T* rb = new T[sz];
366  if(!rb) {
367  a_res.make_empty();
368  return false;
369  }
370 
371  double* pixels = new double[m_n]; //for mean value.
372  if(!pixels) {
373  delete [] rb;
374  a_res.make_empty();
375  return false;
376  }
377  {for(unsigned int ipix=0;ipix<m_n;ipix++) pixels[ipix] = 0;}
378 
379  unsigned int wfac = (unsigned int)(double(m_w)/double(a_w));
380  unsigned int hfac = (unsigned int)(double(m_h)/double(a_h));
381  if(!wfac) wfac = 1;
382  if(!hfac) hfac = 1;
383 
384  double wfac_hfac = wfac*hfac;
385 
386  //::printf("debug : %d %d, %d %d\n",a_h,a_w,hfac,wfac);
387 
388  T* hpos;T* pos;T* hrpos;T* rpos;T* hhpos;T* _pos;double* ppos;
389  unsigned int i,j,fr,fc,ipix,i0;
390  unsigned int astride = a_w * m_n;
391  unsigned int mstride = m_w * m_n;
392  unsigned int wfacstride = wfac * m_n;
393 
394  for(j=0;j<a_h;j++) {
395  hrpos = rb + j * astride;
396  hhpos = m_buffer + j*hfac*mstride;
397  for(i=0;i<a_w;i++) {
398 
399  // take mean value of wfac*hfac pixels :
400 
401  i0 = i*wfacstride;
402 
403  hpos = hhpos;
404  for(fr=0;fr<hfac;fr++,hpos+=mstride) {
405  _pos = hpos + i0;
406  for(fc=0;fc<wfac;fc++,_pos+=m_n) {
407  pos = _pos;
408  ppos = pixels;
409  for(ipix=0;ipix<m_n;ipix++,pos++,ppos++) {
410  *ppos += double(*pos)/wfac_hfac;
411 // *ppos += double(*pos); //NOTE : doing the wfac_hfac division in the below loop is slower !
412  }
413  }
414  }
415 
416  //position in the result image.
417  rpos = hrpos + i*m_n;
418  ppos = pixels;
419  for(ipix=0;ipix<m_n;ipix++,rpos++,ppos++) {
420  *rpos = T(*ppos);
421 // *rpos = T((*ppos)/wfac_hfac); //slower !
422  *ppos = 0;
423  }
424  }
425  }
426 
427  delete [] pixels;
428 
429  a_res.set(a_w,a_h,m_n,rb,true);
430  return true;
431  }
432 
433  bool contract(unsigned int a_factor,img<T>& a_res,bool a_force_res_owner = true) const {
434  // a_factor pixels are contracted in one.
435  unsigned int nw = m_w/a_factor;
436  unsigned int nh = m_h/a_factor;
437  return contract(nw,nh,a_res,a_force_res_owner);
438  }
439 
440  template <class TTO>
441  bool convert(img<TTO>& a_res) const {
442  a_res.make_empty();
443 
444  unsigned int sz = m_w*m_h*m_n;
445  if(!sz) return false;
446 
447  TTO* _buffer = new TTO[sz];
448  if(!_buffer) return false;
449 
450  unsigned int i,j,ipix,imn;
451  unsigned int mwn = m_w*m_n;
452  T* _pos;T* pos;
453  TTO* _rpos;TTO* rpos;
454 
455  for(j=0;j<m_h;j++) {
456  _pos = m_buffer + j*mwn;
457  _rpos = _buffer + j*mwn;
458  for(i=0;i<m_w;i++) {
459  imn = i*m_n;
460  pos = _pos + imn;
461  rpos = _rpos + imn;
462  for(ipix=0;ipix<m_n;ipix++,pos++,rpos++) *rpos = *pos;
463  }
464  }
465 
466  a_res.set(m_w,m_h,m_n,_buffer,true);
467  return true;
468  }
469 
470  bool get_part(unsigned int a_sx,unsigned int a_sy,unsigned int a_sw,unsigned int a_sh,img<T>& a_res) const {
471 
472  if((a_sx>=m_w)||(a_sy>=m_h)){
473  a_res.make_empty();
474  return false;
475  }
476 
477  // 012345
478  unsigned int rw = min_of<unsigned int>(m_w-a_sx,a_sw);
479  unsigned int rh = min_of<unsigned int>(m_h-a_sy,a_sh);
480  unsigned int sz = rh*rw*m_n;
481  if(!sz) {
482  a_res.make_empty();
483  return false;
484  }
485 
486  T* rb = new T[sz];
487  if(!rb) {
488  a_res.make_empty();
489  return false;
490  }
491 
492  unsigned int rstride = rw * m_n;
493  T* rpos = rb;
494 
495  unsigned int stride = m_w * m_n;
496  T* pos = m_buffer+a_sy*stride+a_sx*m_n;
497 
498  //T* mx = m_buffer+size();
499  //T* rmx = rb+sz*sizeof(T);
500 
501  for(unsigned int j=0;j<rh;j++,rpos+=rstride,pos+=stride) {//j=0 -> bottom.
502 /*
503  if((pos+rstride*sizeof(T))>mx) {
504  ::printf("debug : get_part : buffer overflow\n");
505  delete [] rb;
506  a_res.make_empty();
507  return false;
508  }
509  if((rpos+rstride*sizeof(T))>rmx) {
510  ::printf("debug : get_part : result buffer overflow\n");
511  delete [] rb;
512  a_res.make_empty();
513  return false;
514  }
515 */
516  ::memcpy(rpos,pos,rstride*sizeof(T));
517  }
518 
519  a_res.set(rw,rh,m_n,rb,true);
520  return true;
521  }
522 
523  bool to_texture(bool a_expand,
524  const T a_pixel[], //size shoulde be a_img.m_n.
525  img<T>& a_res,bool a_res_force_owner = true) const {
526 
527  //NOTE : pixels of the original image are not expanded or shrinked.
528 
529  if((!m_w)||(!m_h)) {
530  a_res.make_empty();
531  return false;
532  }
533 
534  // in case (m_w==1)||(m_h==1), expand the pixel
535  // up to the closest power of 2 ?
536 
537  if((m_w==1)||(m_h==1)||a_expand) {
538  // find closest power of two upper than m_w, m_h :
539  unsigned int rw = 2;
540  while(true) {if(rw>=m_w) break;rw *=2;}
541  unsigned int rh = 2;
542  while(true) {if(rh>=m_h) break;rh *=2;}
543 
544  if((rw==m_w)&&(rh==m_h)) { //exact match.
545  if(a_res_force_owner) {
546  a_res.copy(m_w,m_h,m_n,m_buffer);
547  } else {
548  a_res.set(m_w,m_h,m_n,m_buffer,false); //WARNING owner=false.
549  }
550  return true;
551  }
552 
553  // we expand the image and fill new spaces with a_pixel.
554 
555  T* rb = 0;
556  bool res_set = true;
557  if(a_res.owner()&&(a_res.size()==(rh*rw*m_n))) {
558  // a_res has already the right allocation.
559  rb = a_res.buffer();
560  res_set = false;
561  } else {
562  rb = new T[rh*rw*m_n];
563  if(!rb) {
564  a_res.make_empty();
565  return false;
566  }
567  }
568 
569  unsigned int num = rw*m_n;
570 
571  // initialize with given color :
572  {T* pos = rb;
573  for(unsigned int i=0;i<rw;i++,pos+=m_n) {
574  ::memcpy(pos,a_pixel,m_n*sizeof(T));
575  }
576  unsigned int sz = num*sizeof(T);
577  for(unsigned int j=1;j<rh;j++,pos+=num) { //j=0 -> bottom.
578  ::memcpy(pos,rb,sz);
579  }}
580 
581  // center :
582  unsigned int col = (rw-m_w)/2;
583  unsigned int row = (rh-m_h)/2;
584 
585  unsigned int mnum = m_w*m_n;
586 
587  // copy original image in a centered part of the new one :
588  {T* pos = m_buffer;
589  T* rpos = rb+row*num+col*m_n;
590  unsigned int sz = mnum*sizeof(T);
591  for(unsigned int j=0;j<m_h;j++,pos+=mnum,rpos+=num) {
592  ::memcpy(rpos,pos,sz);
593  }}
594 
595  if(res_set) a_res.set(rw,rh,m_n,rb,true);
596 
597  return true;
598  } else {
599  // then m_w>=2 and m_h>=2
600 
601  // find closest power of two lower than m_w, m_h :
602  unsigned int sw = 2;
603  while(true) {if((sw*2)>m_w) break;sw *=2;}
604  unsigned int sh = 2;
605  while(true) {if((sh*2)>m_h) break;sh *=2;}
606 
607  if((sw==m_w)&&(sh==m_h)) { //exact match.
608  if(a_res_force_owner) {
609  a_res.copy(m_w,m_h,m_n,m_buffer);
610  } else {
611  a_res.set(m_w,m_h,m_n,m_buffer,false); //WARNING owner=false.
612  }
613  return true;
614  }
615 
616  unsigned int sx = (m_w-sw)/2;
617  unsigned int sy = (m_h-sh)/2;
618 
619  return get_part(sx,sy,sw,sh,a_res);
620  }
621 
622  }
623 
624  bool check_gl_limit(unsigned int a_GL_MAX_TEXTURE_SIZE,img<T>& a_res) const {
625  // if ret true and a_res.is_empty(), "this" does not exceeds the limit.
626  // if ret true and !a_res.is_empty(), "this" exceeds the limit and a new fitting image is returned in a_res.
627  // if ret false, "this" exceeds the limit but something went wrong in building a_res.
628  unsigned int tw = m_w;
629  unsigned int th = m_h;
630  if((tw<=a_GL_MAX_TEXTURE_SIZE)&&(th<=a_GL_MAX_TEXTURE_SIZE)) {
631  a_res.make_empty();
632  return true;
633  }
634  unsigned int fac = 2;
635  while(true) {
636  unsigned int pw = tw/fac;
637  unsigned int ph = th/fac;
638  if((pw<=a_GL_MAX_TEXTURE_SIZE)&&(ph<=a_GL_MAX_TEXTURE_SIZE)) {
639  //unsigned int sx = (tw-pw)/2;
640  //unsigned int sy = (th-ph)/2;
641  //if(!get_part(sx,sy,pw,ph,a_res)) {
642  if(!contract(fac,a_res)) {
643  a_res.make_empty();
644  return false;
645  }
646  return true;
647  }
648  fac *= 2;
649  }
650  a_res.make_empty();
651  return false;
652  }
653 
654  bool bw2x(unsigned int a_n,img<T>& a_res) const {
655  //expect a bw img.
656  if(m_n!=1) return false;
657 
658  a_res.make_empty();
659  if(a_n<m_n) return false;
660  unsigned int sz = m_w*m_h*a_n;
661  if(!sz) return false;
662 
663  a_res.m_buffer = new T[sz];
664  if(!a_res.m_buffer) return false;
665  a_res.m_owner = true;
666  a_res.m_w = m_w;
667  a_res.m_h = m_h;
668  a_res.m_n = a_n;
669 
670  for(unsigned int j=0;j<m_h;j++) {
671  for(unsigned int i=0;i<m_w;i++) {
672  //position in the original image.
673  T* pos = m_buffer + j * (m_w * m_n) + i*m_n;
674 
675  T* rpos = a_res.m_buffer + j * (m_w * a_n) + i*a_n;
676 
677  for(unsigned int ipix=0;ipix<a_n;ipix++) {
678  *(rpos+ipix) = *pos;
679  }
680 
681  }
682  }
683 
684  return true;
685  }
686 
687  bool yswap(img<T>& a_res) const {
688  a_res.make_empty();
689 
690  a_res.m_buffer = new T[size()];
691  if(!a_res.m_buffer) return false;
692  a_res.m_owner = true;
693  a_res.m_w = m_w;
694  a_res.m_h = m_h;
695  a_res.m_n = m_n;
696 
697  unsigned int stride = m_w * m_n;
698 
699  for(unsigned int j=0;j<m_h;j++) {
700  T* pos = m_buffer + j * stride;
701  T* rpos = a_res.m_buffer + (m_h-j-1) * stride;
702  ::memcpy(rpos,pos,stride*sizeof(T));
703  }
704 
705  return true;
706  }
707 
708  bool rgba2rgb(img<T>& a_res) const {
709  if(m_n!=4) return false;
710 
711  unsigned int a_n = 3;
712 
713  a_res.make_empty();
714  unsigned int sz = m_w*m_h*a_n;
715  if(!sz) return false;
716 
717  a_res.m_buffer = new T[sz];
718  if(!a_res.m_buffer) return false;
719  a_res.m_owner = true;
720  a_res.m_w = m_w;
721  a_res.m_h = m_h;
722  a_res.m_n = a_n;
723 
724  for(unsigned int j=0;j<m_h;j++) {
725  for(unsigned int i=0;i<m_w;i++) {
726  //position in the original image.
727  T* pos = m_buffer + j * (m_w * m_n) + i*m_n;
728 
729  T* rpos = a_res.m_buffer + j * (m_w * a_n) + i*a_n;
730 
731  for(unsigned int ipix=0;ipix<a_n;ipix++) {
732  *(rpos+ipix) = *(pos+ipix);
733  }
734 
735  }
736  }
737 
738  return true;
739  }
740 
741  bool rgb2rgba(img<T>& a_res,const T& a_pixel) const {
742  if(m_n!=3) return false;
743 
744  unsigned int n = 4;
745 
746  a_res.make_empty();
747  unsigned int sz = m_w*m_h*n;
748  if(!sz) return false;
749 
750  a_res.m_buffer = new T[sz];
751  if(!a_res.m_buffer) return false;
752  a_res.m_owner = true;
753  a_res.m_w = m_w;
754  a_res.m_h = m_h;
755  a_res.m_n = n;
756 
757  for(unsigned int j=0;j<m_h;j++) {
758  for(unsigned int i=0;i<m_w;i++) {
759  //position in the original image.
760  T* pos = m_buffer + j * (m_w * m_n) + i*m_n;
761 
762  T* rpos = a_res.m_buffer + j * (m_w * n) + i*n;
763 
764  *(rpos+0) = *(pos+0);
765  *(rpos+1) = *(pos+1);
766  *(rpos+2) = *(pos+2);
767  *(rpos+3) = a_pixel;
768 
769  }
770  }
771 
772  return true;
773  }
774 
775  bool rgba2bgra() {
776  if(m_n!=4) return false;
777  for(unsigned int j=0;j<m_h;j++) {
778  for(unsigned int i=0;i<m_w;i++) {
779  T* pos = m_buffer + j * (m_w * m_n) + i*m_n;
780  T r = *(pos+0);
781  T g = *(pos+1);
782  T b = *(pos+2);
783  T a = *(pos+3);
784  *(pos+0) = b;
785  *(pos+1) = g;
786  *(pos+2) = r;
787  *(pos+3) = a;
788  }
789  }
790  return true;
791  }
792 
793 public:
794  static bool concatenate(const std::vector< img<T> >& a_imgs,
795  unsigned int a_cols,unsigned int a_rows,
796  unsigned int a_bw,unsigned int a_bh,
797  T a_bc, //border grey level.
798  img<T>& a_res){
799  // We assume that a_imgs.size() is a_cols*a_rows and that all images have same (w,h,bpp).
800 
801  unsigned int num = a_cols*a_rows;
802  if(!num) {a_res.make_empty();return false;}
803 
804  unsigned int aw = a_imgs[0].m_w;
805  unsigned int ah = a_imgs[0].m_h;
806  unsigned int an = a_imgs[0].m_n;
807 
808  for(unsigned int index=1;index<num;index++) {
809  if(a_imgs[index].m_n!=an) {
810  a_res.make_empty();
811  return false;
812  }
813  if(a_imgs[index].m_w!=aw) {
814  a_res.make_empty();
815  return false;
816  }
817  if(a_imgs[index].m_h!=ah) {
818  a_res.make_empty();
819  return false;
820  }
821  }
822 
823  unsigned int wbw = aw + 2*a_bw;
824  unsigned int hbh = ah + 2*a_bh;
825 
826  unsigned int rw = wbw * a_cols;
827  unsigned int rh = hbh * a_rows;
828  unsigned int rn = an;
829 
830  //printf("debug : %d %d\n",rw,rh);
831 
832  // on big concatenated image the below may fail :
833  unsigned int rsz = rh*rw*rn;
834  T* rb = new T[rsz];
835  if(!rb) {
836  a_res.make_empty();
837  return false;
838  }
839 
840  bool has_border = a_bw||a_bh?true:false;
841  if(has_border) {
842  ::memset(rb,a_bc,rsz*sizeof(T));
843  }
844 
845  //optimize :
846  //unsigned int wbwn = wbw*an;
847  unsigned int awn = aw*an;
848  unsigned int rwn = rw*an;
849  unsigned int i,j,r;
850  //unsigned int c;
851  T* pos;T* ptile;T* _pos;
852 
853  //copy tiles :
854  unsigned int index = 0;
855  for(j=0;j<a_rows;j++) {
856  for(i=0;i<a_cols;i++) {
857  // index = a_cols*j+i
858  const T* tile = a_imgs[index].buffer();
859 
860  //if(has_border) {
861  // for(unsigned int r=0;r<hbh;r++) {
862  // T* pos = rb + (j*hbh+r)*rwn + i*wbwn;
863  // ::memset(pos,a_bc,wbwn*sizeof(T));
864  // }
865  //}
866 
867  _pos = rb + (j*hbh+a_bh)*rwn + (i*wbw+a_bw)*rn;
868  {for(r=0;r<ah;r++) {
869 // pos = _pos + r*rwn;
870 // ptile = tile + r*awn;
871 // for(c=0;c<awn;c++,pos++,ptile++) *pos = *ptile;
872  ::memcpy(_pos+r*rwn,tile+r*awn,awn*sizeof(T)); //optimize. (bof, we do not gain a lot).
873  }}
874 
875  index++;
876  }
877  }
878 
879  a_res.set(rw,rh,rn,rb,true);
880  return true;
881  }
882 
883 protected:
884  unsigned int m_w;
885  unsigned int m_h;
886  unsigned int m_n;
888  bool m_owner;
889 
890 private: static void check_instantiation() {img<float> dummy;}
891 };
892 
893 
895 
896 // NOTE : img_byte is ready for OpenGL glTexImage2D UNSIGNED_BYTE RGB.
897 // For glTexImage2D, first row in m_buffer is bottom of image.
898 
899 inline void tex_expand_size(unsigned int a_w,unsigned int& a_h,
900  unsigned int& a_ew,unsigned int& a_eh){
901  // find closest power of two upper than a_w, a_h :
902  a_ew = 2;
903  while(true) {if(a_ew>=a_w) break;a_ew *=2;}
904  a_eh = 2;
905  while(true) {if(a_eh>=a_h) break;a_eh *=2;}
906 }
907 
908 }
909 
910 #endif
tools::img::buffer
T * buffer()
Definition: img:219
tools::img_byte
img< unsigned char > img_byte
Definition: img:894
tools::img
Definition: img:21
tools::img::operator!=
bool operator!=(const img &a_from) const
Definition: img:95
tools::img::m_buffer
T * m_buffer
Definition: img:887
tools::img::~img
virtual ~img()
Definition: img:43
tools::img::equal
bool equal(const img &a_from) const
Definition: img:201
tools::img::convert
bool convert(img< TTO > &a_res) const
Definition: img:441
tools::img::bw2x
bool bw2x(unsigned int a_n, img< T > &a_res) const
Definition: img:654
tools::img::rgba2rgb
bool rgba2rgb(img< T > &a_res) const
Definition: img:708
tools::img::img
img()
Definition: img:25
tools::img::transfer
void transfer(img &a_from)
Definition: img:97
tools::img::width
unsigned int width() const
Definition: img:214
tools::img::operator==
bool operator==(const img &a_from) const
Definition: img:94
tools::img::copy
bool copy(const img &a_from)
Definition: img:147
mem
tools::img::pixel
bool pixel(unsigned int a_i, unsigned a_j, std::vector< T > &a_pixel) const
Definition: img:223
tools::img::is_empty
bool is_empty() const
Definition: img:194
tools::img::contract
bool contract(unsigned int a_w, unsigned int a_h, img< T > &a_res, bool a_force_res_owner=true) const
Definition: img:347
tools::img::yswap
bool yswap(img< T > &a_res) const
Definition: img:687
mnmx
tools::img::m_w
unsigned int m_w
Definition: img:884
tools::img::contract_raw
bool contract_raw(unsigned int a_w, unsigned int a_h, img< T > &a_res, bool a_force_res_owner=true) const
Definition: img:282
tools::img::operator=
img & operator=(const img &a_from)
Definition: img:71
tools::tex_expand_size
void tex_expand_size(unsigned int a_w, unsigned int &a_h, unsigned int &a_ew, unsigned int &a_eh)
Definition: img:899
tools::img::to_texture
bool to_texture(bool a_expand, const T a_pixel[], img< T > &a_res, bool a_res_force_owner=true) const
Definition: img:523
tools
inlined C code : ///////////////////////////////////
Definition: aida_ntuple:26
tools::img::copy
bool copy(unsigned int a_w, unsigned int a_h, unsigned int a_n, T *a_buffer)
Definition: img:127
tools::img::get_part
bool get_part(unsigned int a_sx, unsigned int a_sy, unsigned int a_sw, unsigned int a_sh, img< T > &a_res) const
Definition: img:470
tools::img::img
img(const img &a_from)
Definition: img:50
tools::img::m_h
unsigned int m_h
Definition: img:885
S_STRING
tools::img::owner
bool owner() const
Definition: img:220
tools::img::allocate
bool allocate(unsigned int a_w, unsigned int a_h, unsigned int a_n)
Definition: img:167
tools::img::make_empty
void make_empty(bool a_delete=true)
Definition: img:186
tools::img::contract
bool contract(unsigned int a_factor, img< T > &a_res, bool a_force_res_owner=true) const
Definition: img:433
tools::img::bpp
unsigned int bpp() const
Definition: img:217
TOOLS_T_SCLASS
#define TOOLS_T_SCLASS(a_T, a_name)
Definition: S_STRING:48
tools::img::height
unsigned int height() const
Definition: img:215
tools::img::expand
bool expand(unsigned int a_factor, img< T > &a_res, bool a_res_force_owner=true) const
Definition: img:236
tools::img::bytes_per_pixel
unsigned int bytes_per_pixel() const
Definition: img:216
tools::img::set
void set(unsigned int a_w, unsigned int a_h, unsigned int a_n, T *a_buffer, bool a_owner)
Definition: img:119
tools::img::buffer
const T * buffer() const
Definition: img:218
tools::img::rgba2bgra
bool rgba2bgra()
Definition: img:775
tools::img::m_n
unsigned int m_n
Definition: img:886
tools::img::img
img(unsigned int a_w, unsigned int a_h, unsigned int a_n, T *a_buffer, bool a_owner)
Definition: img:34
tools::img::clear
void clear()
Definition: img:111
tools::img::check_gl_limit
bool check_gl_limit(unsigned int a_GL_MAX_TEXTURE_SIZE, img< T > &a_res) const
Definition: img:624
tools::img::size
unsigned int size() const
Definition: img:221
tools::img::m_owner
bool m_owner
Definition: img:888
tools::img::concatenate
static bool concatenate(const std::vector< img< T > > &a_imgs, unsigned int a_cols, unsigned int a_rows, unsigned int a_bw, unsigned int a_bh, T a_bc, img< T > &a_res)
Definition: img:794
tools::img::rgb2rgba
bool rgb2rgba(img< T > &a_res, const T &a_pixel) const
Definition: img:741