framework2
1526 строк · 39.4 Кб
1#include "ofGraphicsConstants.h"
2#include "ofPixels.h"
3#include "ofColor.h"
4
5#define GLM_FORCE_CTOR_INIT
6#include "glm/common.hpp"
7#include <cstring>
8
9static ofImageType getImageTypeFromChannels(size_t channels){
10switch(channels){
11case 1:
12return OF_IMAGE_GRAYSCALE;
13case 3:
14return OF_IMAGE_COLOR;
15case 4:
16return OF_IMAGE_COLOR_ALPHA;
17default:
18return OF_IMAGE_UNDEFINED;
19}
20}
21
22template<typename PixelType>
23size_t ofPixels_<PixelType>::pixelBitsFromPixelFormat(ofPixelFormat format){
24switch(format){
25case OF_PIXELS_RGB:
26case OF_PIXELS_BGR:
27return 3 * sizeof(PixelType) * 8;
28
29case OF_PIXELS_RGBA:
30case OF_PIXELS_BGRA:
31return 4 * sizeof(PixelType) * 8;
32
33case OF_PIXELS_GRAY:
34case OF_PIXELS_Y:
35case OF_PIXELS_U:
36case OF_PIXELS_V:
37return 1 * sizeof(PixelType) * 8;
38
39case OF_PIXELS_NV12:
40case OF_PIXELS_NV21:
41case OF_PIXELS_YV12:
42case OF_PIXELS_I420:
43return 12;
44
45case OF_PIXELS_UV:
46case OF_PIXELS_VU:
47case OF_PIXELS_GRAY_ALPHA:
48return 2 * sizeof(PixelType) * 8;
49
50case OF_PIXELS_YUY2:
51case OF_PIXELS_UYVY:
52case OF_PIXELS_RGB565:
53return 16;
54break;
55default:
56return 0;
57}
58
59}
60
61template<>
62std::string ofToString(const ofPixelFormat & p) {
63switch (p){
64case OF_PIXELS_GRAY:
65return "OF_PIXELS_GRAY";
66break;
67case OF_PIXELS_GRAY_ALPHA:
68return "OF_PIXELS_GRAY_ALPHA";
69break;
70case OF_PIXELS_RGB:
71return "OF_PIXELS_RGB";
72break;
73case OF_PIXELS_BGR:
74return "OF_PIXELS_BGR";
75break;
76case OF_PIXELS_RGBA:
77return "OF_PIXELS_RGBA";
78break;
79case OF_PIXELS_BGRA:
80return "OF_PIXELS_BGRA";
81break;
82case OF_PIXELS_RGB565:
83return "OF_PIXELS_RGB565";
84break;
85case OF_PIXELS_NV12:
86return "OF_PIXELS_NV12";
87break;
88case OF_PIXELS_NV21:
89return "OF_PIXELS_NV21";
90break;
91case OF_PIXELS_YV12:
92return "OF_PIXELS_YV12";
93break;
94case OF_PIXELS_I420:
95return "OF_PIXELS_I420";
96break;
97case OF_PIXELS_YUY2:
98return "OF_PIXELS_YUY2";
99break;
100case OF_PIXELS_UYVY:
101return "OF_PIXELS_UYVY";
102break;
103case OF_PIXELS_Y:
104return "OF_PIXELS_Y";
105break;
106case OF_PIXELS_U:
107return "OF_PIXELS_U";
108break;
109case OF_PIXELS_V:
110return "OF_PIXELS_V";
111break;
112case OF_PIXELS_UV:
113return "OF_PIXELS_UV";
114break;
115case OF_PIXELS_VU:
116return "OF_PIXELS_VU";
117break;
118case OF_PIXELS_NUM_FORMATS:
119return "OF_PIXELS_NUM_FORMATS";
120break;
121case OF_PIXELS_UNKNOWN:
122return "OF_PIXELS_UNKNOWN";
123break;
124case OF_PIXELS_NATIVE:
125return "OF_PIXELS_NATIVE";
126break;
127}
128return "OF_PIXELS_UNKNOWN";
129}
130
131template<typename PixelType>
132size_t ofPixels_<PixelType>::bytesFromPixelFormat(size_t w, size_t h, ofPixelFormat format){
133return w * h * pixelBitsFromPixelFormat(format) / 8;
134}
135
136static size_t channelsFromPixelFormat(ofPixelFormat format){
137switch(format){
138case OF_PIXELS_RGB:
139case OF_PIXELS_BGR:
140return 3;
141break;
142case OF_PIXELS_RGBA:
143case OF_PIXELS_BGRA:
144return 4;
145break;
146case OF_PIXELS_GRAY:
147return 1;
148break;
149case OF_PIXELS_GRAY_ALPHA:
150case OF_PIXELS_RGB565:
151return 2;
152break;
153case OF_PIXELS_NV12:
154case OF_PIXELS_NV21:
155case OF_PIXELS_YV12:
156case OF_PIXELS_I420:
157return 1;
158break;
159case OF_PIXELS_YUY2:
160case OF_PIXELS_UYVY:
161return 2;
162break;
163case OF_PIXELS_Y:
164case OF_PIXELS_U:
165case OF_PIXELS_V:
166return 1;
167break;
168case OF_PIXELS_UV:
169case OF_PIXELS_VU:
170return 2;
171break;
172default:
173ofLog(OF_LOG_ERROR,"ofPixels: format doesn't support channels");
174return 1;
175}
176}
177
178static ofPixelFormat ofPixelFormatFromImageType(ofImageType type){
179switch(type){
180case OF_IMAGE_GRAYSCALE:
181return OF_PIXELS_GRAY;
182break;
183case OF_IMAGE_COLOR:
184return OF_PIXELS_RGB;
185break;
186case OF_IMAGE_COLOR_ALPHA:
187return OF_PIXELS_RGBA;
188break;
189default:
190ofLog(OF_LOG_ERROR,"ofPixels: image type not supported");
191return OF_PIXELS_UNKNOWN;
192}
193}
194
195static ofImageType ofImageTypeFromPixelFormat(ofPixelFormat pixelFormat){
196switch(pixelFormat){
197case OF_PIXELS_GRAY:
198return OF_IMAGE_GRAYSCALE;
199break;
200case OF_PIXELS_BGR:
201case OF_PIXELS_RGB:
202case OF_PIXELS_RGB565:
203return OF_IMAGE_COLOR;
204break;
205case OF_PIXELS_BGRA:
206case OF_PIXELS_RGBA:
207return OF_IMAGE_COLOR_ALPHA;
208break;
209case OF_PIXELS_UNKNOWN:
210return OF_IMAGE_UNDEFINED;
211default:
212ofLog(OF_LOG_ERROR,"ofPixels: image type not supported");
213return OF_IMAGE_UNDEFINED;
214}
215}
216
217std::string ofToString(ofPixelFormat pixelFormat){
218switch(pixelFormat){
219case OF_PIXELS_RGB:
220return "RGB";
221case OF_PIXELS_BGR:
222return "BGR";
223case OF_PIXELS_RGBA:
224return "RGBA";
225case OF_PIXELS_BGRA:
226return "BGRA";
227case OF_PIXELS_GRAY:
228return "GRAY";
229case OF_PIXELS_RGB565:
230return "RGB565";
231case OF_PIXELS_NV12:
232return "NV12";
233case OF_PIXELS_NV21:
234return "NV21";
235case OF_PIXELS_YV12:
236return "YV12";
237case OF_PIXELS_I420:
238return "I420";
239case OF_PIXELS_YUY2:
240return "YUY2";
241case OF_PIXELS_UYVY:
242return "UYVY";
243default:
244return "UNKOWN";
245}
246}
247
248static ofPixelFormat pixelFormatFromNumChannels(size_t channels){
249switch(channels){
250case 1: return OF_PIXELS_GRAY;
251case 2: return OF_PIXELS_GRAY_ALPHA;
252case 3: return OF_PIXELS_RGB;
253case 4: return OF_PIXELS_RGBA;
254default: return OF_PIXELS_UNKNOWN;
255}
256}
257
258template<typename PixelType>
259ofPixels_<PixelType>::ofPixels_(){}
260
261
262template<typename PixelType>
263ofPixels_<PixelType>::~ofPixels_(){
264clear();
265}
266
267template<typename PixelType>
268ofPixels_<PixelType>::ofPixels_(const ofPixels_<PixelType> & mom){
269copyFrom( mom );
270}
271
272template<typename PixelType>
273ofPixels_<PixelType>::ofPixels_(ofPixels_<PixelType> && mom)
274:pixels(mom.pixels)
275,width(mom.width)
276,height(mom.height)
277,pixelsSize(mom.pixelsSize)
278,bAllocated(mom.bAllocated)
279,pixelsOwner(mom.pixelsOwner)
280,pixelFormat(mom.pixelFormat){
281mom.pixelsOwner = false;
282}
283
284
285template<typename PixelType>
286void ofPixels_<PixelType>::swap(ofPixels_<PixelType> & pix){
287std::swap(pixels,pix.pixels);
288std::swap(width, pix.width);
289std::swap(height,pix.height);
290std::swap(pixelsSize,pix.pixelsSize);
291std::swap(bAllocated, pix.bAllocated);
292std::swap(pixelsOwner, pix.pixelsOwner);
293std::swap(pixelFormat,pix.pixelFormat);
294}
295
296
297template<typename PixelType>
298ofPixels_<PixelType>& ofPixels_<PixelType>::operator=(const ofPixels_<PixelType> & mom){
299if(this==&mom) {
300return * this;
301}
302copyFrom( mom );
303return *this;
304}
305
306template<typename PixelType>
307ofPixels_<PixelType>& ofPixels_<PixelType>::operator=(ofPixels_<PixelType> && mom){
308if(this==&mom) {
309return * this;
310}
311clear();
312pixels = mom.pixels;
313width = mom.width;
314height = mom.height;
315pixelsSize = mom.pixelsSize;
316bAllocated = mom.bAllocated;
317pixelsOwner = mom.pixelsOwner;
318pixelFormat = mom.pixelFormat;
319mom.pixelsOwner = false;
320return *this;
321}
322
323template<typename PixelType>
324void ofPixels_<PixelType>::copyFrom(const ofPixels_<PixelType> & mom){
325if(mom.isAllocated()) {
326allocate(mom.getWidth(), mom.getHeight(), mom.getPixelFormat());
327memcpy(pixels, mom.getData(), getTotalBytes());
328}
329}
330
331template<typename PixelType>
332void ofPixels_<PixelType>::set(PixelType val){
333iterator _end = end();
334for(iterator i=begin();i<_end;++i){
335*i = val;
336}
337}
338
339template<typename PixelType>
340void ofPixels_<PixelType>::set(size_t channel,PixelType val){
341switch(pixelFormat){
342case OF_PIXELS_RGB:
343case OF_PIXELS_BGR:
344case OF_PIXELS_RGBA:
345case OF_PIXELS_BGRA:
346case OF_PIXELS_GRAY:
347case OF_PIXELS_GRAY_ALPHA:
348case OF_PIXELS_UV:
349case OF_PIXELS_VU:{
350for(auto pixel: getPixelsIter()){
351pixel[channel] = val;
352}
353}
354break;
355case OF_PIXELS_RGB565:
356case OF_PIXELS_NV12:
357case OF_PIXELS_NV21:
358case OF_PIXELS_YV12:
359case OF_PIXELS_I420:
360case OF_PIXELS_YUY2:
361case OF_PIXELS_UYVY:
362case OF_PIXELS_Y:
363case OF_PIXELS_U:
364case OF_PIXELS_V:
365case OF_PIXELS_UNKNOWN:
366default:
367ofLogWarning() << "setting channels not supported for " << ofToString(pixelFormat) << " format";
368break;
369}
370}
371
372template<typename PixelType>
373void ofPixels_<PixelType>::setFromPixels(const PixelType * newPixels, size_t w, size_t h, size_t channels){
374allocate(w, h, channels);
375memcpy(pixels, newPixels, getTotalBytes());
376}
377
378template<typename PixelType>
379void ofPixels_<PixelType>::setFromPixels(const PixelType * newPixels, size_t w, size_t h, ofImageType type){
380allocate(w,h,type);
381setFromPixels(newPixels,w,h,ofPixelFormatFromImageType(type));
382}
383
384template<typename PixelType>
385void ofPixels_<PixelType>::setFromPixels(const PixelType * newPixels, size_t w, size_t h, ofPixelFormat format){
386allocate(w,h,format);
387memcpy(pixels, newPixels, getTotalBytes());
388}
389
390
391template<typename PixelType>
392void ofPixels_<PixelType>::setFromExternalPixels(PixelType * newPixels, size_t w, size_t h, size_t channels){
393setFromExternalPixels(newPixels,w,h,pixelFormatFromNumChannels(channels));
394}
395
396template<typename PixelType>
397void ofPixels_<PixelType>::setFromExternalPixels(PixelType * newPixels, size_t w, size_t h, ofPixelFormat _pixelFormat){
398clear();
399pixelFormat = _pixelFormat;
400width= w;
401height = h;
402
403pixelsSize = bytesFromPixelFormat(w,h,_pixelFormat) / sizeof(PixelType);
404
405pixels = newPixels;
406pixelsOwner = false;
407bAllocated = true;
408}
409
410template<typename PixelType>
411void ofPixels_<PixelType>::setFromAlignedPixels(const PixelType * newPixels, size_t width, size_t height, size_t channels, size_t stride){
412setFromAlignedPixels(newPixels,width,height,pixelFormatFromNumChannels(channels),stride);
413}
414
415template<typename PixelType>
416void ofPixels_<PixelType>::setFromAlignedPixels(const PixelType * newPixels, size_t width, size_t height, ofPixelFormat _pixelFormat, size_t stride) {
417size_t channels = channelsFromPixelFormat(_pixelFormat);
418if(channels==0) return;
419
420if(width*channels==stride){
421setFromPixels(newPixels,width,height,_pixelFormat);
422return;
423}
424allocate(width, height, _pixelFormat);
425size_t dstStride = width * pixelBitsFromPixelFormat(_pixelFormat)/8;
426const unsigned char* src = (unsigned char*) newPixels;
427unsigned char* dst = (unsigned char*) pixels;
428for(size_t i = 0; i < height; i++) {
429memcpy(dst, src, dstStride);
430src += stride;
431dst += dstStride;
432}
433}
434
435template<typename PixelType>
436void ofPixels_<PixelType>::setFromAlignedPixels(const PixelType * newPixels, size_t width, size_t height, ofPixelFormat _pixelFormat, std::vector<size_t> strides) {
437size_t channels = channelsFromPixelFormat(_pixelFormat);
438if(channels==0) return;
439
440switch(_pixelFormat){
441case OF_PIXELS_I420: {
442if(strides.size() != 3){
443ofLogError("ofPixels") << "number of planes for I420 should be 3";
444break;
445}
446
447if(width==strides[0] && width/2==strides[1] && width/2==strides[2]){
448setFromPixels(newPixels,width,height,_pixelFormat);
449return;
450}
451
452allocate(width, height, _pixelFormat);
453
454const unsigned char* src = (unsigned char*) newPixels;
455unsigned char* dst = (unsigned char*) pixels;
456// Y Plane
457for(size_t i = 0; i < height; i++) {
458memcpy(dst, src, width);
459src += strides[0];
460dst += width;
461}
462// U Plane
463for(size_t i = 0; i < height /2; i++){
464memcpy(dst,src,width/2);
465src += strides[1];
466dst += width/2;
467}
468// V Plane
469for(size_t i = 0; i < height /2; i++){
470memcpy(dst,src,width/2);
471src += strides[2];
472dst += width/2;
473}
474break;
475}
476case OF_PIXELS_RGB:
477case OF_PIXELS_RGBA:
478case OF_PIXELS_GRAY:
479case OF_PIXELS_GRAY_ALPHA:
480setFromAlignedPixels(newPixels,width,height,_pixelFormat,strides[0]);
481return;
482default:
483ofLogError("ofPixels") << "setFromAlignedPixels with planes strides: pixel format not supported yet";
484break;
485}
486return;
487}
488
489template<typename PixelType>
490PixelType * ofPixels_<PixelType>::getPixels(){
491return pixels;
492}
493
494template<typename PixelType>
495const PixelType * ofPixels_<PixelType>::getPixels() const{
496return pixels;
497}
498
499template<typename PixelType>
500PixelType * ofPixels_<PixelType>::getData(){
501return pixels;
502}
503
504template<typename PixelType>
505const PixelType * ofPixels_<PixelType>::getData() const{
506return pixels;
507}
508
509template<typename PixelType>
510void ofPixels_<PixelType>::allocate(size_t w, size_t h, size_t _channels){
511allocate(w,h,pixelFormatFromNumChannels(_channels));
512}
513
514template<typename PixelType>
515void ofPixels_<PixelType>::allocate(size_t w, size_t h, ofPixelFormat format){
516if (w == 0 || h == 0 || format == OF_PIXELS_UNKNOWN) {
517return;
518}
519
520size_t newSize = bytesFromPixelFormat(w,h,format);
521size_t oldSize = getTotalBytes();
522//we check if we are already allocated at the right size
523if(bAllocated && newSize==oldSize){
524pixelFormat = format;
525width = w;
526height = h;
527return; //we don't need to allocate
528}
529
530//we do need to allocate, clear the data
531clear();
532
533pixelFormat = format;
534width = w;
535height = h;
536
537pixelsSize = newSize / sizeof(PixelType);
538
539pixels = new PixelType[pixelsSize];
540bAllocated = true;
541pixelsOwner = true;
542}
543
544template<typename PixelType>
545void ofPixels_<PixelType>::allocate(size_t w, size_t h, ofImageType type){
546allocate(w,h,ofPixelFormatFromImageType(type));
547}
548
549template<typename PixelType>
550void ofPixels_<PixelType>::swapRgb(){
551switch(pixelFormat){
552case OF_PIXELS_RGB:
553case OF_PIXELS_BGR:
554case OF_PIXELS_RGBA:
555case OF_PIXELS_BGRA:{
556for(auto pixel: getPixelsIter()){
557std::swap(pixel[0],pixel[2]);
558}
559}
560break;
561default:
562ofLogWarning("ofPixels") << "rgb swap not supported for this pixel format";
563break;
564}
565switch(pixelFormat){
566case OF_PIXELS_RGB:
567pixelFormat = OF_PIXELS_BGR;
568break;
569case OF_PIXELS_BGR:
570pixelFormat = OF_PIXELS_RGB;
571break;
572case OF_PIXELS_RGBA:
573pixelFormat = OF_PIXELS_BGRA;
574break;
575case OF_PIXELS_BGRA:
576pixelFormat = OF_PIXELS_RGBA;
577break;
578default:
579break;
580}
581}
582
583template<typename PixelType>
584void ofPixels_<PixelType>::clear(){
585if(pixels){
586if(pixelsOwner) delete[] pixels;
587pixels = nullptr;
588}
589
590width = 0;
591height = 0;
592pixelFormat = OF_PIXELS_UNKNOWN;
593pixelsSize = 0;
594bAllocated = false;
595}
596
597template<typename PixelType>
598size_t ofPixels_<PixelType>::getPixelIndex(size_t x, size_t y) const {
599if( !bAllocated ){
600return 0;
601}else{
602size_t pixelStride;
603switch(pixelFormat){
604case OF_PIXELS_RGB:
605case OF_PIXELS_BGR:
606pixelStride = 3;
607return ( x + y * width ) * pixelStride;
608break;
609case OF_PIXELS_RGBA:
610case OF_PIXELS_BGRA:
611pixelStride = 4;
612return ( x + y * width ) * pixelStride;
613break;
614case OF_PIXELS_GRAY:
615case OF_PIXELS_Y:
616case OF_PIXELS_U:
617case OF_PIXELS_V:
618pixelStride = 1;
619return ( x + y * width ) * pixelStride;
620break;
621case OF_PIXELS_GRAY_ALPHA:
622case OF_PIXELS_UV:
623case OF_PIXELS_VU:
624case OF_PIXELS_YUY2:
625case OF_PIXELS_UYVY:
626pixelStride = 2;
627return ( x + y * width ) * pixelStride;
628break;
629case OF_PIXELS_RGB565:
630pixelStride = 2;
631return ( x + y * width ) * pixelStride;
632break;
633case OF_PIXELS_NV12:
634case OF_PIXELS_YV12:
635case OF_PIXELS_I420:
636case OF_PIXELS_UNKNOWN:
637default:
638ofLogWarning() << "getting pixel index not supported for " << ofToString(pixelFormat) << " format";
639return 0;
640break;
641}
642}
643}
644
645template<typename PixelType>
646ofColor_<PixelType> ofPixels_<PixelType>::getColor(size_t index) const {
647return (Pixel(pixels + index, getNumChannels(), pixelFormat)).getColor();
648}
649
650template<typename PixelType>
651ofColor_<PixelType> ofPixels_<PixelType>::getColor(size_t x, size_t y) const {
652return getColor(getPixelIndex(x, y));
653}
654
655template<typename PixelType>
656void ofPixels_<PixelType>::setColor(size_t index, const ofColor_<PixelType>& color) {
657
658switch(pixelFormat){
659case OF_PIXELS_RGB:
660pixels[index] = color.r;
661pixels[index+1] = color.g;
662pixels[index+2] = color.b;
663break;
664case OF_PIXELS_BGR:
665pixels[index] = color.b;
666pixels[index+1] = color.g;
667pixels[index+2] = color.r;
668break;
669case OF_PIXELS_RGBA:
670pixels[index] = color.r;
671pixels[index+1] = color.g;
672pixels[index+2] = color.b;
673pixels[index+3] = color.a;
674break;
675case OF_PIXELS_BGRA:
676pixels[index] = color.b;
677pixels[index+1] = color.g;
678pixels[index+2] = color.r;
679pixels[index+3] = color.a;
680break;
681case OF_PIXELS_GRAY:
682pixels[index] = color.getBrightness();
683break;
684case OF_PIXELS_GRAY_ALPHA:
685pixels[index] = color.getBrightness();
686pixels[index+1] = color.a;
687break;
688case OF_PIXELS_RGB565:
689case OF_PIXELS_NV12:
690case OF_PIXELS_NV21:
691case OF_PIXELS_YV12:
692case OF_PIXELS_I420:
693case OF_PIXELS_YUY2:
694case OF_PIXELS_UYVY:
695case OF_PIXELS_Y:
696case OF_PIXELS_U:
697case OF_PIXELS_V:
698case OF_PIXELS_UV:
699case OF_PIXELS_VU:
700case OF_PIXELS_UNKNOWN:
701default:
702ofLogWarning("ofPixels") << "setting color not supported yet for " << ofToString(pixelFormat) << " format";
703break;
704}
705}
706
707template<typename PixelType>
708void ofPixels_<PixelType>::setColor(size_t x, size_t y, const ofColor_<PixelType>& color) {
709setColor(getPixelIndex(x, y), color);
710}
711
712template<typename PixelType>
713void ofPixels_<PixelType>::setColor(const ofColor_<PixelType>& color) {
714switch(pixelFormat){
715case OF_PIXELS_RGB:{
716for(auto pixel: getPixelsIter()){
717pixel[0] = color.r;
718pixel[1] = color.g;
719pixel[2] = color.b;
720}
721}
722break;
723case OF_PIXELS_BGR:{
724for(auto pixel: getPixelsIter()){
725pixel[0] = color.b;
726pixel[1] = color.g;
727pixel[2] = color.r;
728}
729}
730break;
731case OF_PIXELS_RGBA:{
732for(auto pixel: getPixelsIter()){
733pixel[0] = color.r;
734pixel[1] = color.g;
735pixel[2] = color.b;
736pixel[3] = color.a;
737}
738}
739break;
740case OF_PIXELS_BGRA:{
741for(auto pixel: getPixelsIter()){
742pixel[0] = color.b;
743pixel[1] = color.g;
744pixel[2] = color.r;
745pixel[3] = color.a;
746}
747}
748break;
749case OF_PIXELS_GRAY:{
750PixelType b = color.getBrightness();
751for(iterator i=begin();i!=end();++i){
752*i = b;
753}
754}
755break;
756case OF_PIXELS_GRAY_ALPHA:{
757PixelType b = color.getBrightness();
758for(auto pixel: getPixelsIter()){
759pixel[0] = b;
760pixel[1] = color.a;
761}
762}
763break;
764case OF_PIXELS_RGB565:
765case OF_PIXELS_NV12:
766case OF_PIXELS_NV21:
767case OF_PIXELS_YV12:
768case OF_PIXELS_I420:
769case OF_PIXELS_YUY2:
770case OF_PIXELS_UYVY:
771case OF_PIXELS_Y:
772case OF_PIXELS_U:
773case OF_PIXELS_V:
774case OF_PIXELS_UV:
775case OF_PIXELS_VU:
776case OF_PIXELS_UNKNOWN:
777default:
778ofLogWarning("ofPixels") << "setting color not supported yet for " << ofToString(pixelFormat) << " format";
779break;
780}
781}
782
783template<typename PixelType>
784PixelType & ofPixels_<PixelType>::operator[](size_t pos){
785return pixels[pos];
786}
787
788template<typename PixelType>
789const PixelType & ofPixels_<PixelType>::operator[](size_t pos) const{
790return pixels[pos];
791}
792
793template<typename PixelType>
794bool ofPixels_<PixelType>::isAllocated() const{
795return bAllocated;
796}
797
798template<typename PixelType>
799size_t ofPixels_<PixelType>::getWidth() const{
800return width;
801}
802
803template<typename PixelType>
804size_t ofPixels_<PixelType>::getHeight() const{
805return height;
806}
807
808template<typename PixelType>
809size_t ofPixels_<PixelType>::getBytesPerPixel() const{
810return pixelBitsFromPixelFormat(pixelFormat)/8;
811}
812
813template<typename PixelType>
814size_t ofPixels_<PixelType>::getBitsPerPixel() const{
815return pixelBitsFromPixelFormat(pixelFormat);
816}
817
818template<typename PixelType>
819size_t ofPixels_<PixelType>::getBytesPerChannel() const{
820return sizeof(PixelType);
821}
822
823template<typename PixelType>
824size_t ofPixels_<PixelType>::getBitsPerChannel() const{
825return getBytesPerChannel() * 8;
826}
827
828template<typename PixelType>
829size_t ofPixels_<PixelType>::getBytesStride() const{
830return pixelBitsFromPixelFormat(pixelFormat) * width / 8;
831}
832
833template<typename PixelType>
834size_t ofPixels_<PixelType>::getNumChannels() const{
835return channelsFromPixelFormat(pixelFormat);
836}
837
838template<typename PixelType>
839
840size_t ofPixels_<PixelType>::getTotalBytes() const{
841return bytesFromPixelFormat(width,height,pixelFormat);
842}
843
844template<typename PixelType>
845size_t ofPixels_<PixelType>::getNumPlanes() const{
846switch(pixelFormat){
847case OF_PIXELS_RGB:
848case OF_PIXELS_BGR:
849case OF_PIXELS_RGB565:
850case OF_PIXELS_RGBA:
851case OF_PIXELS_BGRA:
852case OF_PIXELS_GRAY:
853case OF_PIXELS_GRAY_ALPHA:
854case OF_PIXELS_YUY2:
855case OF_PIXELS_UYVY:
856case OF_PIXELS_Y:
857case OF_PIXELS_U:
858case OF_PIXELS_V:
859case OF_PIXELS_UV:
860case OF_PIXELS_VU:
861return 1;
862case OF_PIXELS_NV12:
863case OF_PIXELS_NV21:
864return 2;
865case OF_PIXELS_YV12:
866case OF_PIXELS_I420:
867return 3;
868case OF_PIXELS_NUM_FORMATS:
869case OF_PIXELS_NATIVE:
870case OF_PIXELS_UNKNOWN:
871return 0;
872}
873return 0;
874}
875
876template<typename PixelType>
877ofPixels_<PixelType> ofPixels_<PixelType>::getPlane(size_t planeIdx){
878planeIdx = glm::clamp(planeIdx, size_t(0), getNumPlanes());
879ofPixels_<PixelType> plane;
880switch(pixelFormat){
881case OF_PIXELS_RGB:
882case OF_PIXELS_BGR:
883case OF_PIXELS_RGB565:
884case OF_PIXELS_RGBA:
885case OF_PIXELS_BGRA:
886case OF_PIXELS_GRAY:
887case OF_PIXELS_GRAY_ALPHA:
888case OF_PIXELS_YUY2:
889case OF_PIXELS_UYVY:
890case OF_PIXELS_Y:
891case OF_PIXELS_U:
892case OF_PIXELS_V:
893case OF_PIXELS_UV:
894case OF_PIXELS_VU:
895plane.setFromExternalPixels(pixels,width,height,pixelFormat);
896break;
897case OF_PIXELS_NV12:
898switch(planeIdx){
899case 0:
900plane.setFromExternalPixels(pixels,width,height,OF_PIXELS_Y);
901break;
902case 1:
903plane.setFromExternalPixels(pixels+width*height,width/2,height/2,OF_PIXELS_UV);
904break;
905}
906break;
907case OF_PIXELS_NV21:
908switch(planeIdx){
909case 0:
910plane.setFromExternalPixels(pixels,width,height,OF_PIXELS_Y);
911break;
912case 1:
913plane.setFromExternalPixels(pixels+width*height,width/2,height/2,OF_PIXELS_VU);
914break;
915}
916break;
917case OF_PIXELS_YV12:
918switch(planeIdx){
919case 0:
920plane.setFromExternalPixels(pixels,width,height,OF_PIXELS_Y);
921break;
922case 1:
923plane.setFromExternalPixels(pixels+width*height,width/2,height/2,OF_PIXELS_V);
924break;
925case 2:
926plane.setFromExternalPixels(pixels + (width*height+width/2*height/2), width/2, height/2, OF_PIXELS_U);
927break;
928}
929break;
930case OF_PIXELS_I420:
931switch(planeIdx){
932case 0:
933plane.setFromExternalPixels(pixels,width,height,OF_PIXELS_Y);
934break;
935case 1:
936plane.setFromExternalPixels(pixels+width*height,width/2,height/2,OF_PIXELS_U);
937break;
938case 2:
939plane.setFromExternalPixels(pixels + (width*height+width/2*height/2), width/2, height/2, OF_PIXELS_V);
940break;
941}
942break;
943case OF_PIXELS_NUM_FORMATS:
944case OF_PIXELS_NATIVE:
945case OF_PIXELS_UNKNOWN:
946break;
947}
948return plane;
949}
950
951template<typename PixelType>
952ofImageType ofPixels_<PixelType>::getImageType() const{
953return ofImageTypeFromPixelFormat(pixelFormat);
954}
955
956template<typename PixelType>
957void ofPixels_<PixelType>::setImageType(ofImageType imageType){
958if(!isAllocated() || imageType==getImageType()) return;
959ofPixels_<PixelType> dst;
960dst.allocate(width,height,imageType);
961PixelType * dstPtr = &dst[0];
962PixelType * srcPtr = &pixels[0];
963size_t dstNumChannels = dst.getNumChannels();
964size_t srcNumChannels = getNumChannels();
965size_t diffNumChannels = 0;
966if(dstNumChannels<srcNumChannels){
967diffNumChannels = srcNumChannels-dstNumChannels;
968}
969for(size_t i=0;i<width*height;i++){
970const PixelType & gray = *srcPtr;
971for(size_t j=0;j<dstNumChannels;j++){
972if(j<srcNumChannels){
973*dstPtr++ = *srcPtr++;
974}else if(j<3){
975*dstPtr++ = gray;
976}else{
977*dstPtr++ = ofColor_<PixelType>::limit();
978}
979}
980srcPtr+=diffNumChannels;
981}
982swap(dst);
983}
984
985template<typename PixelType>
986ofPixelFormat ofPixels_<PixelType>::getPixelFormat() const{
987return pixelFormat;
988}
989
990template<typename PixelType>
991void ofPixels_<PixelType>::setNumChannels(size_t numChannels){
992if(!isAllocated() || numChannels==getNumChannels()) return;
993setImageType(getImageTypeFromChannels(numChannels));
994}
995
996template<typename PixelType>
997size_t ofPixels_<PixelType>::size() const{
998return pixelsSize;
999}
1000
1001template<typename PixelType>
1002ofPixels_<PixelType> ofPixels_<PixelType>::getChannel(size_t channel) const{
1003ofPixels_<PixelType> channelPixels;
1004size_t channels = channelsFromPixelFormat(pixelFormat);
1005if(channels==0) return channelPixels;
1006
1007channelPixels.allocate(width,height,1);
1008channel = glm::clamp(channel, size_t(0), channels-1);
1009iterator channelPixel = channelPixels.begin();
1010for(auto p: getConstPixelsIter()){
1011*channelPixel++ = p[channel];
1012}
1013return channelPixels;
1014}
1015
1016template<typename PixelType>
1017void ofPixels_<PixelType>::setChannel(size_t channel, const ofPixels_<PixelType> channelPixels){
1018size_t channels = channelsFromPixelFormat(pixelFormat);
1019if(channels==0) return;
1020
1021channel = glm::clamp(channel, size_t(0), channels-1);
1022const_iterator channelPixel = channelPixels.begin();
1023for(auto p: getPixelsIter()){
1024p[channel] = *channelPixel++;
1025}
1026
1027}
1028
1029//From ofPixelsUtils
1030//----------------------------------------------------------------------
1031template<typename PixelType>
1032void ofPixels_<PixelType>::crop(size_t x, size_t y, size_t _width, size_t _height){
1033if (bAllocated){
1034ofPixels_<PixelType> crop;
1035cropTo(crop,x,y,_width,_height);
1036swap(crop);
1037}
1038}
1039
1040//----------------------------------------------------------------------
1041template<typename PixelType>
1042void ofPixels_<PixelType>::cropTo(ofPixels_<PixelType> &toPix, size_t x, size_t y, size_t _width, size_t _height) const{
1043if (bAllocated){
1044
1045if(&toPix == this){
1046toPix.crop(x,y,_width,_height);
1047return;
1048}
1049
1050_width = glm::clamp(_width, size_t(1), getWidth());
1051_height = glm::clamp(_height, size_t(1), getHeight());
1052
1053if ((toPix.width != _width) || (toPix.height != _height) || (toPix.pixelFormat != pixelFormat)){
1054toPix.allocate(_width, _height, pixelFormat);
1055}
1056
1057// this prevents having to do a check for bounds in the for loop;
1058size_t minX = std::max(x, static_cast<size_t>(0));
1059size_t maxX = std::min(x + _width, width);
1060size_t minY = std::max(y, static_cast<size_t>(0));
1061size_t maxY = std::min(y + _height, height);
1062
1063auto newPixel = toPix.getPixelsIter().begin();
1064for(auto line: getConstLines(minY, maxY - minY)){
1065for(auto pixel: line.getPixels(minX, maxX - minX)){
1066newPixel++ = pixel;
1067}
1068}
1069}
1070}
1071
1072//----------------------------------------------------------------------
1073template<typename PixelType>
1074void ofPixels_<PixelType>::rotate90To(ofPixels_<PixelType> & dst, int nClockwiseRotations) const{
1075size_t channels = channelsFromPixelFormat(pixelFormat);
1076
1077if (bAllocated == false || channels==0){
1078return;
1079}
1080
1081if(&dst == this){
1082dst.rotate90(nClockwiseRotations);
1083return;
1084}
1085
1086// first, figure out which type of rotation we have
1087int rotation = nClockwiseRotations;
1088while (rotation < 0){
1089rotation+=4;
1090}
1091rotation %= 4;
1092
1093// if it's 0, just make a copy. if it's 2, do it by a mirror operation.
1094if (rotation == 0) {
1095dst = *this;
1096return;
1097// do nothing!
1098} else if (rotation == 2) {
1099mirrorTo(dst, true, true);
1100return;
1101}
1102
1103// otherwise, we will need to do some new allocaiton.
1104dst.allocate(height,width,getImageType());
1105
1106size_t strideSrc = width * channels;
1107size_t strideDst = dst.width * channels;
1108
1109if(rotation == 1){
1110PixelType * srcPixels = pixels;
1111PixelType * startPixels = dst.getData() + strideDst;
1112for (size_t i = 0; i < height; ++i){
1113startPixels -= channels;
1114PixelType * dstPixels = startPixels;
1115for (size_t j = 0; j < width; ++j){
1116for (size_t k = 0; k < channels; ++k){
1117dstPixels[k] = srcPixels[k];
1118}
1119srcPixels += channels;
1120dstPixels += strideDst;
1121}
1122}
1123} else if(rotation == 3){
1124PixelType * dstPixels = dst.pixels;
1125PixelType * startPixels = pixels + strideSrc;
1126for (size_t i = 0; i < dst.height; ++i){
1127startPixels -= channels;
1128PixelType * srcPixels = startPixels;
1129for (size_t j = 0; j < dst.width; ++j){
1130for (size_t k = 0; k < channels; ++k){
1131dstPixels[k] = srcPixels[k];
1132}
1133srcPixels += strideSrc;
1134dstPixels += channels;
1135}
1136}
1137}
1138}
1139
1140//----------------------------------------------------------------------
1141template<typename PixelType>
1142void ofPixels_<PixelType>::rotate90(int nClockwiseRotations){
1143size_t channels = channelsFromPixelFormat(pixelFormat);
1144
1145if (bAllocated == false || channels==0){
1146return;
1147}
1148
1149// first, figure out which type of rotation we have
1150int rotation = nClockwiseRotations;
1151while (rotation < 0){
1152rotation+=4;
1153}
1154rotation %= 4;
1155
1156// if it's 0, do nothing. if it's 2, do it by a mirror operation.
1157if (rotation == 0) {
1158return;
1159// do nothing!
1160} else if (rotation == 2) {
1161mirror(true, true);
1162return;
1163}
1164
1165ofPixels_<PixelType> newPixels;
1166rotate90To(newPixels,nClockwiseRotations);
1167std::swap(newPixels.pixels,pixels);
1168width = newPixels.width;
1169height = newPixels.height;
1170pixelsSize = newPixels.size();
1171
1172}
1173
1174//----------------------------------------------------------------------
1175template<typename PixelType>
1176void ofPixels_<PixelType>::mirror(bool vertically, bool horizontal){
1177size_t channels = channelsFromPixelFormat(pixelFormat);
1178
1179if ((!vertically && !horizontal) || channels==0){
1180return;
1181}
1182
1183size_t bytesPerPixel = channels;
1184PixelType * oldPixels = pixels;
1185PixelType tempVal;
1186
1187if (! (vertically && horizontal)){
1188size_t wToDo = horizontal ? width/2 : width;
1189size_t hToDo = vertically ? height/2 : height;
1190
1191for (size_t i = 0; i < wToDo; i++){
1192for (size_t j = 0; j < hToDo; j++){
1193
1194size_t pixelb = (vertically ? (height - j - 1) : j) * width + (horizontal ? (width - i - 1) : i);
1195size_t pixela = j*width + i;
1196for (size_t k = 0; k < bytesPerPixel; k++){
1197
1198tempVal = oldPixels[pixela*bytesPerPixel + k];
1199oldPixels[pixela*bytesPerPixel + k] = oldPixels[pixelb*bytesPerPixel + k];
1200oldPixels[pixelb*bytesPerPixel + k] = tempVal;
1201
1202}
1203}
1204}
1205} else {
1206// I couldn't think of a good way to do this in place. I'm sure there is.
1207mirror(true, false);
1208mirror(false, true);
1209}
1210
1211}
1212
1213//----------------------------------------------------------------------
1214template<typename PixelType>
1215void ofPixels_<PixelType>::mirrorTo(ofPixels_<PixelType> & dst, bool vertically, bool horizontal) const{
1216if(&dst == this){
1217dst.mirror(vertically,horizontal);
1218return;
1219}
1220
1221if (!vertically && !horizontal){
1222dst = *this;
1223return;
1224}
1225
1226size_t bytesPerPixel = getNumChannels();
1227dst.allocate(width, height, getPixelFormat());
1228
1229if(vertically && !horizontal){
1230auto dstLines = dst.getLines();
1231auto lineSrc = getConstLines().begin();
1232auto line = --dstLines.end();
1233auto stride = line.getStride();
1234
1235for(; line>=dstLines.begin(); --line, ++lineSrc){
1236memcpy(line.begin(), lineSrc.begin(), stride);
1237}
1238}else if (!vertically && horizontal){
1239size_t wToDo = width/2;
1240size_t hToDo = height;
1241for (size_t i = 0; i < wToDo; i++){
1242for (size_t j = 0; j < hToDo; j++){
1243size_t pixelb = j*width + (width - 1 - i);
1244size_t pixela = j*width + i;
1245for (size_t k = 0; k < bytesPerPixel; k++){
1246dst[pixela*bytesPerPixel + k] = pixels[pixelb*bytesPerPixel + k];
1247dst[pixelb*bytesPerPixel + k] = pixels[pixela*bytesPerPixel + k];
1248
1249}
1250}
1251}
1252} else {
1253// I couldn't think of a good way to do this in place. I'm sure there is.
1254mirrorTo(dst,true, false);
1255dst.mirror(false, true);
1256}
1257
1258}
1259
1260//----------------------------------------------------------------------
1261template<typename PixelType>
1262bool ofPixels_<PixelType>::resize(size_t dstWidth, size_t dstHeight, ofInterpolationMethod interpMethod){
1263
1264if ((dstWidth == 0) || (dstHeight == 0) || !(isAllocated())) return false;
1265
1266ofPixels_<PixelType> dstPixels;
1267dstPixels.allocate(dstWidth, dstHeight, getPixelFormat());
1268
1269if(!resizeTo(dstPixels,interpMethod)) return false;
1270
1271delete [] pixels;
1272pixels = dstPixels.getData();
1273width = dstWidth;
1274height = dstHeight;
1275pixelsSize = dstPixels.size();
1276dstPixels.pixelsOwner = false;
1277return true;
1278}
1279
1280//----------------------------------------------------------------------
1281template<typename PixelType>
1282float ofPixels_<PixelType>::bicubicInterpolate (const float *patch, float x,float y, float x2,float y2, float x3,float y3) {
1283// adapted from http://www.paulinternet.nl/?page=bicubic
1284// Note that this code can produce values outside of 0...255, due to cubic overshoot.
1285// The ofClamp() prevents this from happening.
1286
1287float p00 = patch[ 0];
1288float p10 = patch[ 4];
1289float p20 = patch[ 8];
1290float p30 = patch[12];
1291
1292float p01 = patch[ 1];
1293float p11 = patch[ 5];
1294float p21 = patch[ 9];
1295float p31 = patch[13];
1296
1297float p02 = patch[ 2];
1298float p12 = patch[ 6];
1299float p22 = patch[10];
1300float p32 = patch[14];
1301
1302float p03 = patch[ 3];
1303float p13 = patch[ 7];
1304float p23 = patch[11];
1305float p33 = patch[15];
1306
1307float a00 = p11;
1308float a01 = -p10 + p12;
1309float a02 = 2.0f*p10 - 2.0f*p11 + p12 - p13;
1310float a03 = -p10 + p11 - p12 + p13;
1311float a10 = -p01 + p21;
1312float a11 = p00 - p02 - p20 + p22;
1313float a12 = -2.0f*p00 + 2.0f*p01 - p02 + p03 + 2.0f*p20 - 2.0f*p21 + p22 - p23;
1314float a13 = p00 - p01 + p02 - p03 - p20 + p21 - p22 + p23;
1315float a20 = 2.0f*p01 - 2.0f*p11 + p21 - p31;
1316float a21 = -2.0f*p00 + 2.0f*p02 + 2.0f*p10 - 2.0f*p12 - p20 + p22 + p30 - p32;
1317float a22 = 4*p00 - 4*p01 + 2.0f*p02 - 2.0f*p03 - 4*p10 + 4*p11 - 2.0f*p12 + 2.0f*p13 + 2.0f*p20 - 2.0f*p21 + p22 - p23 - 2.0f*p30 + 2.0f*p31 - p32 + p33;
1318float a23 = -2.0f*p00 + 2.0f*p01 - 2.0f*p02 + 2.0f*p03 + 2.0f*p10 - 2.0f*p11 + 2.0f*p12 - 2.0f*p13 - p20 + p21 - p22 + p23 + p30 - p31 + p32 - p33;
1319float a30 = -p01 + p11 - p21 + p31;
1320float a31 = p00 - p02 - p10 + p12 + p20 - p22 - p30 + p32;
1321float a32 = -2.0f*p00 + 2.0f*p01 - p02 + p03 + 2.0f*p10 - 2.0f*p11 + p12 - p13 - 2.0f*p20 + 2.0f*p21 - p22 + p23 + 2.0f*p30 - 2.0f*p31 + p32 - p33;
1322float a33 = p00 - p01 + p02 - p03 - p10 + p11 - p12 + p13 + p20 - p21 + p22 - p23 - p30 + p31 - p32 + p33;
1323
1324float out =
1325a00 + a01 * y + a02 * y2 + a03 * y3 +
1326a10 * x + a11 * x * y + a12 * x * y2 + a13 * x * y3 +
1327a20 * x2 + a21 * x2 * y + a22 * x2 * y2 + a23 * x2 * y3 +
1328a30 * x3 + a31 * x3 * y + a32 * x3 * y2 + a33 * x3 * y3;
1329
1330return std::min(static_cast<size_t>(255), std::max(static_cast<size_t>(out), static_cast<size_t>(0)));
1331}
1332
1333//----------------------------------------------------------------------
1334template<typename PixelType>
1335bool ofPixels_<PixelType>::resizeTo(ofPixels_<PixelType>& dst, ofInterpolationMethod interpMethod) const{
1336if(&dst == this){
1337return true;
1338}
1339
1340if (!(isAllocated()) || !(dst.isAllocated()) || getBytesPerPixel() != dst.getBytesPerPixel()) return false;
1341
1342size_t srcWidth = getWidth();
1343size_t srcHeight = getHeight();
1344size_t dstWidth = dst.getWidth();
1345size_t dstHeight = dst.getHeight();
1346size_t bytesPerPixel = getBytesPerPixel();
1347
1348
1349PixelType * dstPixels = dst.getData();
1350
1351switch (interpMethod){
1352
1353//----------------------------------------
1354case OF_INTERPOLATE_NEAREST_NEIGHBOR:{
1355size_t dstIndex = 0;
1356float srcxFactor = (float)srcWidth/dstWidth;
1357float srcyFactor = (float)srcHeight/dstHeight;
1358float srcy = 0.5;
1359for (size_t dsty=0; dsty<dstHeight; dsty++){
1360float srcx = 0.5;
1361size_t srcIndex = static_cast<size_t>(srcy) * srcWidth;
1362for (size_t dstx=0; dstx<dstWidth; dstx++){
1363size_t pixelIndex = static_cast<size_t>(srcIndex + srcx) * bytesPerPixel;
1364for (size_t k=0; k<bytesPerPixel; k++){
1365dstPixels[dstIndex] = pixels[pixelIndex];
1366dstIndex++;
1367pixelIndex++;
1368}
1369srcx+=srcxFactor;
1370}
1371srcy+=srcyFactor;
1372}
1373}break;
1374
1375//----------------------------------------
1376case OF_INTERPOLATE_BILINEAR:
1377// not implemented yet
1378ofLogError("ofPixels") << "resizeTo(): bilinear resize not implemented, not resizing";
1379break;
1380
1381//----------------------------------------
1382case OF_INTERPOLATE_BICUBIC:
1383float px1, py1;
1384float px2, py2;
1385float px3, py3;
1386
1387float srcColor = 0;
1388float interpCol;
1389size_t patchRow;
1390size_t patchIndex;
1391float patch[16];
1392
1393size_t srcRowBytes = srcWidth*bytesPerPixel;
1394size_t loIndex = (srcRowBytes)+1;
1395size_t hiIndex = (srcWidth*srcHeight*bytesPerPixel)-(srcRowBytes)-1;
1396
1397for (size_t dsty=0; dsty<dstHeight; dsty++){
1398for (size_t dstx=0; dstx<dstWidth; dstx++){
1399
1400size_t dstIndex0 = (dsty*dstWidth + dstx) * bytesPerPixel;
1401float srcxf = srcWidth * (float)dstx/(float)dstWidth;
1402float srcyf = srcHeight * (float)dsty/(float)dstHeight;
1403size_t srcx = static_cast<size_t>(std::min(srcWidth-1, static_cast<size_t>(srcxf)));
1404size_t srcy = static_cast<size_t>(std::min(srcHeight-1, static_cast<size_t>(srcyf)));
1405size_t srcIndex0 = (srcy*srcWidth + srcx) * bytesPerPixel;
1406
1407px1 = srcxf - srcx;
1408py1 = srcyf - srcy;
1409px2 = px1 * px1;
1410px3 = px2 * px1;
1411py2 = py1 * py1;
1412py3 = py2 * py1;
1413
1414for (size_t k=0; k<bytesPerPixel; k++){
1415size_t dstIndex = dstIndex0+k;
1416size_t srcIndex = srcIndex0+k;
1417
1418for (size_t dy=0; dy<4; dy++) {
1419patchRow = srcIndex + ((dy-1)*srcRowBytes);
1420for (size_t dx=0; dx<4; dx++) {
1421patchIndex = patchRow + (dx-1)*bytesPerPixel;
1422if ((patchIndex >= loIndex) && (patchIndex < hiIndex)) {
1423srcColor = pixels[patchIndex];
1424}
1425patch[dx*4 + dy] = srcColor;
1426}
1427}
1428
1429interpCol = (PixelType)bicubicInterpolate(patch, px1,py1, px2,py2, px3,py3);
1430dstPixels[dstIndex] = interpCol;
1431}
1432
1433}
1434}
1435break;
1436}
1437
1438return true;
1439}
1440
1441//----------------------------------------------------------------------
1442template<typename PixelType>
1443bool ofPixels_<PixelType>::pasteInto(ofPixels_<PixelType> &dst, size_t xTo, size_t yTo) const{
1444if (!(isAllocated()) || !(dst.isAllocated()) || getBytesPerPixel() != dst.getBytesPerPixel() || xTo + getWidth()>dst.getWidth() || yTo + getHeight()>dst.getHeight()) return false;
1445
1446size_t bytesToCopyPerRow = (xTo + getWidth()<=dst.getWidth() ? getWidth() : dst.getWidth()-xTo) * getBytesPerPixel();
1447size_t columnsToCopy = yTo + getHeight() <= dst.getHeight() ? getHeight() : dst.getHeight()-yTo;
1448PixelType * dstPix = dst.getData() + ((xTo + yTo*dst.getWidth())*dst.getBytesPerPixel());
1449const PixelType * srcPix = getData();
1450size_t srcStride = getWidth()*getBytesPerPixel();
1451size_t dstStride = dst.getWidth()*dst.getBytesPerPixel();
1452
1453for(size_t y=0;y<columnsToCopy; y++){
1454memcpy(dstPix,srcPix,bytesToCopyPerRow);
1455dstPix += dstStride;
1456srcPix += srcStride;
1457}
1458
1459return true;
1460}
1461
1462
1463template<typename A, typename B>
1464inline A clampedAdd(const A& a, const B& b) {
1465return glm::clamp((float) a + (float) b, 0.f, ofColor_<A>::limit());
1466}
1467
1468
1469//----------------------------------------------------------------------
1470template<typename PixelType>
1471bool ofPixels_<PixelType>::blendInto(ofPixels_<PixelType> &dst, size_t xTo, size_t yTo) const{
1472if (!(isAllocated()) || !(dst.isAllocated()) || getBytesPerPixel() != dst.getBytesPerPixel() || xTo + getWidth()>dst.getWidth() || yTo + getHeight()>dst.getHeight() || getNumChannels()==0) return false;
1473
1474std::function<void(const ConstPixel&,Pixel&)> blendFunc;
1475switch(getNumChannels()){
1476case 1:
1477blendFunc = [](const ConstPixel&src, Pixel&dst){
1478dst[0] = clampedAdd(src[0], dst[0]);
1479};
1480break;
1481case 2:
1482blendFunc = [](const ConstPixel&src, Pixel&dst){
1483dst[0] = clampedAdd(src[0], dst[0] / ofColor_<PixelType>::limit() * (ofColor_<PixelType>::limit() - src[1]));
1484dst[1] = clampedAdd(src[1], dst[1] / ofColor_<PixelType>::limit() * (ofColor_<PixelType>::limit() - src[1]));
1485};
1486break;
1487case 3:
1488blendFunc = [](const ConstPixel&src, Pixel&dst){
1489dst[0] = clampedAdd(src[0], dst[0]);
1490dst[1] = clampedAdd(src[1], dst[1]);
1491dst[2] = clampedAdd(src[2], dst[2]);
1492};
1493break;
1494case 4:
1495blendFunc = [](const ConstPixel&src, Pixel&dst){
1496dst[0] = clampedAdd(src[0], dst[0] / ofColor_<PixelType>::limit() * (ofColor_<PixelType>::limit() - src[3]));
1497dst[1] = clampedAdd(src[1], dst[1] / ofColor_<PixelType>::limit() * (ofColor_<PixelType>::limit() - src[3]));
1498dst[2] = clampedAdd(src[2], dst[2] / ofColor_<PixelType>::limit() * (ofColor_<PixelType>::limit() - src[3]));
1499dst[3] = clampedAdd(src[3], dst[3] / ofColor_<PixelType>::limit() * (ofColor_<PixelType>::limit() - src[3]));
1500};
1501break;
1502}
1503auto dstLine = dst.getLine(yTo);
1504for(auto line: getConstLines()){
1505auto dstPixel = dstLine.getPixels().begin() + xTo;
1506for(auto p: line.getPixels()){
1507blendFunc(p,dstPixel);
1508dstPixel++;
1509}
1510dstLine++;
1511}
1512
1513return true;
1514}
1515
1516
1517template class ofPixels_<char>;
1518template class ofPixels_<unsigned char>;
1519template class ofPixels_<short>;
1520template class ofPixels_<unsigned short>;
1521template class ofPixels_<int>;
1522template class ofPixels_<unsigned int>;
1523template class ofPixels_<long>;
1524template class ofPixels_<unsigned long>;
1525template class ofPixels_<float>;
1526template class ofPixels_<double>;
1527