Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/externals/g4tools/include/tools/img

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  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:
 23   TOOLS_T_SCLASS(T,tools::img)
 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;
887   T* m_buffer;
888   bool m_owner;
889 
890 private: static void check_instantiation() {img<float> dummy;}
891 };
892 
893 
894 typedef img<unsigned char> img_byte;
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