2 * Copyright 2003-2006, Haiku, Inc. All rights reserved.
3 * Copyright 2004-2005 yellowTAB GmbH. All Rights Reserved.
4 * Copyright 2006 Bernd Korz. All Rights Reserved
5 * Distributed under the terms of the MIT License.
8 * Michael Pfeiffer, laplace@haiku-os.org
9 * Ryan Leavengood, leavengood@gmail.com
14 #include <scheduler.h>
23 // Implementation of FilterThread
24 FilterThread::FilterThread(Filter
* filter
, int32 i
, int32 n
,
25 bool runInCurrentThread
)
31 if (runInCurrentThread
)
35 tid
= spawn_thread(worker_thread
, "filter",
36 suggest_thread_priority(B_STATUS_RENDERING
), this);
45 FilterThread::~FilterThread()
47 fFilter
->FilterThreadDone();
52 FilterThread::worker_thread(void* data
)
54 FilterThread
* thread
= (FilterThread
*)data
;
64 // create destination image in first thread
65 bm
= fFilter
->GetBitmap();
67 fFilter
->FilterThreadInitFailed();
70 // and start other filter threads
71 for (int32 i
= fI
+ 1; i
< fN
; i
++) {
72 new FilterThread(fFilter
, i
, fN
);
75 if (fFilter
->GetBitmap())
82 // Implementation of Filter
83 Filter::Filter(BBitmap
* image
, BMessenger listener
, uint32 what
)
92 fDestImageInitialized(false),
95 fCPUCount
= NumberOfActiveCPUs();
97 fWaitForThreads
= create_sem(0, "wait_for_threads");
108 delete_sem(fWaitForThreads
);
115 if (!fDestImageInitialized
) {
116 fDestImageInitialized
= true;
117 fDestImage
= CreateDestImage(fSrcImage
);
124 Filter::DetachBitmap()
126 BBitmap
* image
= fDestImage
;
133 Filter::Start(bool async
)
135 if (fStarted
|| fSrcImage
== NULL
) return;
138 fStopWatch
= new BStopWatch("Filter Time");
141 fN
= NumberOfThreads();
142 fNumberOfThreads
= fN
;
146 // start first filter thread
147 new FilterThread(this, 0, fN
, !async
);
158 // wait for threads to exit
159 while (acquire_sem_etc(fWaitForThreads
, fN
, 0, 0) == B_INTERRUPTED
);
160 // ready to start again
169 // tell FilterThreads to stop calculations
176 Filter::IsRunning() const
189 Filter::FilterThreadDone()
191 if (atomic_add(&fNumberOfThreads
, -1) == 1) {
193 delete fStopWatch
; fStopWatch
= NULL
;
197 fListener
.SendMessage(fWhat
);
201 release_sem(fWaitForThreads
);
206 Filter::FilterThreadInitFailed()
208 ASSERT(fNumberOfThreads
== fN
);
209 fNumberOfThreads
= 0;
212 release_sem_etc(fWaitForThreads
, fN
, 0);
217 Filter::IsBitmapValid(BBitmap
* bitmap
) const
219 return bitmap
!= NULL
&& bitmap
->InitCheck() == B_OK
&& bitmap
->IsValid();
224 Filter::NumberOfThreads()
226 const int32 units
= GetNumberOfUnits();
228 n
= units
/ 32; // at least 32 units per CPU
232 n
= 1; // at least one thread!
239 Filter::GetSrcImage()
246 Filter::GetDestImage()
253 Filter::NumberOfActiveCPUs() const
257 get_system_info(&info
);
258 count
= info
.cpu_count
;
260 for (int i
= 0; i
< count
; i
++) {
261 if (_kern_cpu_enabled(i
))
271 // Implementation of (bilinear) Scaler
272 Scaler::Scaler(BBitmap
* image
, BRect rect
, BMessenger listener
, uint32 what
,
275 Filter(image
, listener
, what
),
285 if (GetDestImage() != fScaledImage
) {
293 Scaler::CreateDestImage(BBitmap
* srcImage
)
295 if (srcImage
== NULL
|| (srcImage
->ColorSpace() != B_RGB32
296 && srcImage
->ColorSpace() != B_RGBA32
))
299 BRect
dest(0, 0, fRect
.IntegerWidth(), fRect
.IntegerHeight());
300 BBitmap
* destImage
= new BBitmap(dest
,
301 fDither
? B_CMAP8
: srcImage
->ColorSpace());
303 if (!IsBitmapValid(destImage
)) {
310 BRect
dest_rect(0, 0, fRect
.IntegerWidth(), fRect
.IntegerHeight());
311 fScaledImage
= new BBitmap(dest_rect
, srcImage
->ColorSpace());
312 if (!IsBitmapValid(fScaledImage
)) {
319 fScaledImage
= destImage
;
326 Scaler::Matches(BRect rect
, bool dither
) const
328 return fRect
.IntegerWidth() == rect
.IntegerWidth()
329 && fRect
.IntegerHeight() == rect
.IntegerHeight()
330 && fDither
== dither
;
334 // Scale bilinear using floating point calculations
343 Scaler::ScaleBilinear(intType fromRow
, int32 toRow
)
348 intType destW
, destH
;
350 ColumnData
* columnData
;
352 const uchar
* srcBits
;
354 intType srcBPR
, destBPR
;
355 const uchar
* srcData
;
358 const int32 kBPP
= 4;
363 srcW
= src
->Bounds().IntegerWidth();
364 srcH
= src
->Bounds().IntegerHeight();
365 destW
= dest
->Bounds().IntegerWidth();
366 destH
= dest
->Bounds().IntegerHeight();
368 srcBits
= (uchar
*)src
->Bits();
369 destBits
= (uchar
*)dest
->Bits();
370 srcBPR
= src
->BytesPerRow();
371 destBPR
= dest
->BytesPerRow();
373 columnData
= new ColumnData
[destW
];
375 for (i
= 0; i
< destW
; i
++, cd
++) {
376 float column
= (float)i
* (float)srcW
/ (float)destW
;
377 cd
->srcColumn
= (intType
)column
;
378 cd
->alpha1
= column
- cd
->srcColumn
;
379 cd
->alpha0
= 1.0 - cd
->alpha1
;
382 destDataRow
= destBits
+ fromRow
* destBPR
;
384 for (y
= fromRow
; IsRunning() && y
<= toRow
; y
++, destDataRow
+= destBPR
) {
387 float alpha0
, alpha1
;
392 row
= (float)y
* (float)srcH
/ (float)destH
;
394 srcRow
= (intType
)row
;
395 alpha1
= row
- srcRow
;
396 alpha0
= 1.0 - alpha1
;
398 srcData
= srcBits
+ srcRow
* srcBPR
;
399 destData
= destDataRow
;
403 const uchar
*a
, *b
, *c
, *d
;
405 for (x
= 0; x
< destW
; x
++, destData
+= kBPP
) {
406 a
= srcData
+ columnData
[x
].srcColumn
* kBPP
;
411 a0
= columnData
[x
].alpha0
;
412 a1
= columnData
[x
].alpha1
;
414 destData
[0] = static_cast<uchar
>(
415 (a
[0] * a0
+ b
[0] * a1
) * alpha0
+
416 (c
[0] * a0
+ d
[0] * a1
) * alpha1
);
417 destData
[1] = static_cast<uchar
>(
418 (a
[1] * a0
+ b
[1] * a1
) * alpha0
+
419 (c
[1] * a0
+ d
[1] * a1
) * alpha1
);
420 destData
[2] = static_cast<uchar
>(
421 (a
[2] * a0
+ b
[2] * a1
) * alpha0
+
422 (c
[2] * a0
+ d
[2] * a1
) * alpha1
);
423 destData
[3] = static_cast<uchar
>(
424 (a
[3] * a0
+ b
[3] * a1
) * alpha0
+
425 (c
[3] * a0
+ d
[3] * a1
) * alpha1
);
429 a
= srcData
+ srcW
* kBPP
;
432 destData
[0] = static_cast<uchar
>(a
[0] * alpha0
+ c
[0] * alpha1
);
433 destData
[1] = static_cast<uchar
>(a
[1] * alpha0
+ c
[1] * alpha1
);
434 destData
[2] = static_cast<uchar
>(a
[2] * alpha0
+ c
[2] * alpha1
);
435 destData
[3] = static_cast<uchar
>(a
[3] * alpha0
+ c
[3] * alpha1
);
439 for (x
= 0; x
< destW
; x
++, destData
+= kBPP
) {
440 a
= srcData
+ columnData
[x
].srcColumn
* kBPP
;
443 a0
= columnData
[x
].alpha0
;
444 a1
= columnData
[x
].alpha1
;
446 destData
[0] = static_cast<uchar
>(a
[0] * a0
+ b
[0] * a1
);
447 destData
[1] = static_cast<uchar
>(a
[1] * a0
+ b
[1] * a1
);
448 destData
[2] = static_cast<uchar
>(a
[2] * a0
+ b
[2] * a1
);
449 destData
[3] = static_cast<uchar
>(a
[3] * a0
+ b
[3] * a1
);
452 // bottom, right pixel
453 a
= srcData
+ srcW
* kBPP
;
467 // Scale bilinear using fixed point calculations
468 // Is already more than two times faster than floating point version
469 // on AMD Athlon 1 GHz and Dual Intel Pentium III 866 MHz.
479 Scaler::ScaleBilinearFP(intType fromRow
, int32 toRow
)
484 intType destW
, destH
;
486 ColumnDataFP
* columnData
;
488 const uchar
* srcBits
;
490 intType srcBPR
, destBPR
;
491 const uchar
* srcData
;
494 const int32 kBPP
= 4;
499 srcW
= src
->Bounds().IntegerWidth();
500 srcH
= src
->Bounds().IntegerHeight();
501 destW
= dest
->Bounds().IntegerWidth();
502 destH
= dest
->Bounds().IntegerHeight();
504 srcBits
= (uchar
*)src
->Bits();
505 destBits
= (uchar
*)dest
->Bits();
506 srcBPR
= src
->BytesPerRow();
507 destBPR
= dest
->BytesPerRow();
509 fixed_point fpSrcW
= to_fixed_point(srcW
);
510 fixed_point fpDestW
= to_fixed_point(destW
);
511 fixed_point fpSrcH
= to_fixed_point(srcH
);
512 fixed_point fpDestH
= to_fixed_point(destH
);
514 columnData
= new ColumnDataFP
[destW
];
516 for (i
= 0; i
< destW
; i
++, cd
++) {
517 fixed_point column
= to_fixed_point(i
) * (long_fixed_point
)fpSrcW
519 cd
->srcColumn
= from_fixed_point(column
);
520 cd
->alpha1
= tail_value(column
); // weigth for left pixel value
521 cd
->alpha0
= kFPOne
- cd
->alpha1
; // weigth for right pixel value
524 destDataRow
= destBits
+ fromRow
* destBPR
;
526 for (y
= fromRow
; IsRunning() && y
<= toRow
; y
++, destDataRow
+= destBPR
) {
529 fixed_point alpha0
, alpha1
;
534 row
= to_fixed_point(y
) * (long_fixed_point
)fpSrcH
/ fpDestH
;
536 srcRow
= from_fixed_point(row
);
537 alpha1
= tail_value(row
); // weight for row y + 1
538 alpha0
= kFPOne
- alpha1
; // weight for row y
540 srcData
= srcBits
+ srcRow
* srcBPR
;
541 destData
= destDataRow
;
543 // Need mult_correction for "outer" multiplication only
544 #define I4(i) from_fixed_point(mult_correction(\
545 (a[i] * a0 + b[i] * a1) * alpha0 + \
546 (c[i] * a0 + d[i] * a1) * alpha1))
547 #define V2(i) from_fixed_point(a[i] * alpha0 + c[i] * alpha1);
548 #define H2(i) from_fixed_point(a[i] * a0 + b[i] * a1);
552 const uchar
*a
, *b
, *c
, *d
;
554 for (x
= 0; x
< destW
; x
++, destData
+= kBPP
) {
555 a
= srcData
+ columnData
[x
].srcColumn
* kBPP
;
560 a0
= columnData
[x
].alpha0
;
561 a1
= columnData
[x
].alpha1
;
570 a
= srcData
+ srcW
* kBPP
;
580 for (x
= 0; x
< destW
; x
++, destData
+= kBPP
) {
581 a
= srcData
+ columnData
[x
].srcColumn
* kBPP
;
584 a0
= columnData
[x
].alpha0
;
585 a1
= columnData
[x
].alpha1
;
593 // bottom, right pixel
594 a
= srcData
+ srcW
* kBPP
;
608 Scaler::RowValues(float* sum
, const uchar
* src
, intType srcW
, intType fromX
,
609 intType toX
, const float a0X
, const float a1X
, const int32 kBPP
)
611 sum
[0] = a0X
* src
[0];
612 sum
[1] = a0X
* src
[1];
613 sum
[2] = a0X
* src
[2];
617 for (int32 x
= fromX
+ 1; x
< toX
; x
++, src
+= kBPP
) {
624 sum
[0] += a1X
* src
[0];
625 sum
[1] += a1X
* src
[1];
626 sum
[2] += a1X
* src
[2];
636 } DownScaleColumnData
;
640 Scaler::DownScaleBilinear(intType fromRow
, int32 toRow
)
645 intType destW
, destH
;
647 const uchar
* srcBits
;
649 intType srcBPR
, destBPR
;
650 const uchar
* srcData
;
653 const int32 kBPP
= 4;
654 DownScaleColumnData
* columnData
;
659 srcW
= src
->Bounds().IntegerWidth();
660 srcH
= src
->Bounds().IntegerHeight();
661 destW
= dest
->Bounds().IntegerWidth();
662 destH
= dest
->Bounds().IntegerHeight();
664 srcBits
= (uchar
*)src
->Bits();
665 destBits
= (uchar
*)dest
->Bits();
666 srcBPR
= src
->BytesPerRow();
667 destBPR
= dest
->BytesPerRow();
669 destDataRow
= destBits
+ fromRow
* destBPR
;
671 const float deltaX
= (srcW
+ 1.0) / (destW
+ 1.0);
672 const float deltaY
= (srcH
+ 1.0) / (destH
+ 1.0);
673 const float deltaXY
= deltaX
* deltaY
;
675 columnData
= new DownScaleColumnData
[destW
+ 1];
676 DownScaleColumnData
* cd
= columnData
;
677 for (x
= 0; x
<= destW
; x
++, cd
++) {
678 const float fFromX
= x
* deltaX
;
679 const float fToX
= fFromX
+ deltaX
;
681 cd
->from
= (intType
)fFromX
;
682 cd
->to
= (intType
)fToX
;
684 cd
->alpha0
= 1.0 - (fFromX
- cd
->from
);
685 cd
->alpha1
= fToX
- cd
->to
;
688 for (y
= fromRow
; IsRunning() && y
<= toRow
; y
++, destDataRow
+= destBPR
) {
689 const float fFromY
= y
* deltaY
;
690 const float fToY
= fFromY
+ deltaY
;
692 const intType fromY
= (intType
)fFromY
;
693 const intType toY
= (intType
)fToY
;
695 const float a0Y
= 1.0 - (fFromY
- fromY
);
696 const float a1Y
= fToY
- toY
;
698 const uchar
* srcDataRow
= srcBits
+ fromY
* srcBPR
;
699 destData
= destDataRow
;
702 for (x
= 0; x
<= destW
; x
++, destData
+= kBPP
, cd
++) {
703 const intType fromX
= cd
->from
;
704 const intType toX
= cd
->to
;
706 const float a0X
= cd
->alpha0
;
707 const float a1X
= cd
->alpha1
;
709 srcData
= srcDataRow
+ fromX
* kBPP
;
714 RowValues(sum
, srcData
, srcW
, fromX
, toX
, a0X
, a1X
, kBPP
);
715 totalSum
[0] = a0Y
* sum
[0];
716 totalSum
[1] = a0Y
* sum
[1];
717 totalSum
[2] = a0Y
* sum
[2];
721 for (int32 r
= fromY
+ 1; r
< toY
; r
++, srcData
+= srcBPR
) {
722 RowValues(sum
, srcData
, srcW
, fromX
, toX
, a0X
, a1X
, kBPP
);
723 totalSum
[0] += sum
[0];
724 totalSum
[1] += sum
[1];
725 totalSum
[2] += sum
[2];
729 RowValues(sum
, srcData
, srcW
, fromX
, toX
, a0X
, a1X
, kBPP
);
730 totalSum
[0] += a1Y
* sum
[0];
731 totalSum
[1] += a1Y
* sum
[1];
732 totalSum
[2] += a1Y
* sum
[2];
735 destData
[0] = static_cast<uchar
>(totalSum
[0] / deltaXY
);
736 destData
[1] = static_cast<uchar
>(totalSum
[1] / deltaXY
);
737 destData
[2] = static_cast<uchar
>(totalSum
[2] / deltaXY
);
745 // Flyod-Steinberg Dithering
746 // Filter (distribution of error to adjacent pixels, X is current pixel):
752 } DitheringColumnData
;
756 Scaler::Limit(intType value
)
768 Scaler::Dither(int32 fromRow
, int32 toRow
)
784 const int32 kBPP
= 4;
785 DitheringColumnData
* columnData0
;
786 DitheringColumnData
* columnData
;
787 DitheringColumnData
* cd
;
789 intType error
[3], err
[3];
792 dest
= GetDestImage();
794 ASSERT(src
->ColorSpace() == B_RGB32
|| src
->ColorSpace() == B_RGBA32
);
795 ASSERT(dest
->ColorSpace() == B_CMAP8
);
796 ASSERT(src
->Bounds().IntegerWidth() == dest
->Bounds().IntegerWidth());
797 ASSERT(src
->Bounds().IntegerHeight() == dest
->Bounds().IntegerHeight());
799 destW
= dest
->Bounds().IntegerWidth();
801 srcBits
= (uchar
*)src
->Bits();
802 srcBPR
= src
->BytesPerRow();
803 destBits
= (uchar
*)dest
->Bits();
804 destBPR
= dest
->BytesPerRow();
806 // Allocate space for sentinel at left and right bounds,
807 // so that columnData[-1] and columnData[destW + 1] can be safely accessed
808 columnData0
= new DitheringColumnData
[destW
+ 3];
809 columnData
= columnData0
+ 1;
813 for (x
= destW
; x
>= 0; x
--, cd
++) {
814 cd
->error
[0] = cd
->error
[1] = cd
->error
[2] = 0;
817 srcDataRow
= srcBits
+ fromRow
* srcBPR
;
818 destDataRow
= destBits
+ fromRow
* destBPR
;
819 for (y
= fromRow
; IsRunning() && y
<= toRow
; y
++, srcDataRow
+= srcBPR
,
820 destDataRow
+= destBPR
) {
822 error
[0] = error
[1] = error
[2] = 0;
823 srcData
= srcDataRow
;
824 destData
= destDataRow
;
825 for (x
= 0; x
<= destW
; x
++, srcData
+= kBPP
, destData
+= 1) {
826 rgb_color color
, actualColor
;
829 color
.red
= Limit(srcData
[2] + error
[0] / 16);
830 color
.green
= Limit(srcData
[1] + error
[1] / 16);
831 color
.blue
= Limit(srcData
[0] + error
[2] / 16);
832 color
.alpha
= UINT8_MAX
;
834 index
= screen
.IndexForColor(color
);
835 actualColor
= screen
.ColorForIndex(index
);
839 err
[0] = color
.red
- actualColor
.red
;
840 err
[1] = color
.green
- actualColor
.green
;
841 err
[2] = color
.blue
- actualColor
.blue
;
844 // get error for next pixel
845 cd
= &columnData
[x
+ 1];
846 error
[0] = cd
->error
[0] + 7 * err
[0];
847 error
[1] = cd
->error
[1] + 7 * err
[1];
848 error
[2] = cd
->error
[2] + 7 * err
[2];
850 // set error for right pixel below current pixel
851 cd
->error
[0] = err
[0];
852 cd
->error
[1] = err
[1];
853 cd
->error
[2] = err
[2];
855 // add error for pixel below current pixel
857 cd
->error
[0] += 5 * err
[0];
858 cd
->error
[1] += 5 * err
[1];
859 cd
->error
[2] += 5 * err
[2];
861 // add error for left pixel below current pixel
863 cd
->error
[0] += 3 * err
[0];
864 cd
->error
[1] += 3 * err
[1];
865 cd
->error
[2] += 3 * err
[2];
867 // Note: Alogrithm has good results with "left to right" already
868 // Optionally remove code to end of block:
870 srcDataRow
+= srcBPR
; destDataRow
+= destBPR
;
871 if (y
> toRow
) break;
873 error
[0] = error
[1] = error
[2] = 0;
874 srcData
= srcDataRow
+ destW
* kBPP
;
875 destData
= destDataRow
+ destW
;
876 for (x
= 0; x
<= destW
; x
++, srcData
-= kBPP
, destData
-= 1) {
877 rgb_color color
, actualColor
;
880 color
.red
= Limit(srcData
[2] + error
[0] / 16);
881 color
.green
= Limit(srcData
[1] + error
[1] / 16);
882 color
.blue
= Limit(srcData
[0] + error
[2] / 16);
883 color
.alpha
= UINT8_MAX
;
885 index
= screen
.IndexForColor(color
);
886 actualColor
= screen
.ColorForIndex(index
);
890 err
[0] = color
.red
- actualColor
.red
;
891 err
[1] = color
.green
- actualColor
.green
;
892 err
[2] = color
.blue
- actualColor
.blue
;
895 // get error for next pixel
896 cd
= &columnData
[x
- 1];
897 error
[0] = cd
->error
[0] + 7 * err
[0];
898 error
[1] = cd
->error
[1] + 7 * err
[1];
899 error
[2] = cd
->error
[2] + 7 * err
[2];
901 // set error for left pixel below current pixel
902 cd
->error
[0] = err
[0];
903 cd
->error
[1] = err
[1];
904 cd
->error
[2] = err
[2];
906 // add error for pixel below current pixel
908 cd
->error
[0] += 5 * err
[0];
909 cd
->error
[1] += 5 * err
[1];
910 cd
->error
[2] += 5 * err
[2];
912 // add error for right pixel below current pixel
914 cd
->error
[0] += 3 * err
[0];
915 cd
->error
[1] += 3 * err
[1];
916 cd
->error
[2] += 3 * err
[2];
920 delete[] columnData0
;
925 Scaler::GetNumberOfUnits()
927 return fRect
.IntegerHeight() + 1;
932 Scaler::Run(int32 i
, int32 n
)
934 int32 from
, to
, height
, imageHeight
;
935 imageHeight
= GetDestImage()->Bounds().IntegerHeight() + 1;
936 height
= imageHeight
/ n
;
939 to
= imageHeight
- 1;
941 to
= from
+ height
- 1;
943 if (GetDestImage()->Bounds().Width() >= GetSrcImage()->Bounds().Width())
944 ScaleBilinearFP(from
, to
);
946 DownScaleBilinear(from
, to
);
957 if (GetDestImage() != fScaledImage
)
964 // Implementation of ImageProcessor
965 ImageProcessor::ImageProcessor(enum operation op
, BBitmap
* image
,
966 BMessenger listener
, uint32 what
)
968 Filter(image
, listener
, what
),
980 ImageProcessor::CreateDestImage(BBitmap
* /* srcImage */)
986 if (GetSrcImage() == NULL
)
989 cs
= GetSrcImage()->ColorSpace();
990 fBPP
= BytesPerPixel(cs
);
994 fWidth
= GetSrcImage()->Bounds().IntegerWidth();
995 fHeight
= GetSrcImage()->Bounds().IntegerHeight();
997 if (fOp
== kRotateClockwise
|| fOp
== kRotateCounterClockwise
)
998 rect
.Set(0, 0, fHeight
, fWidth
);
1000 rect
.Set(0, 0, fWidth
, fHeight
);
1002 bm
= new BBitmap(rect
, cs
);
1003 if (!IsBitmapValid(bm
)) {
1008 fSrcBPR
= GetSrcImage()->BytesPerRow();
1009 fDestBPR
= bm
->BytesPerRow();
1016 ImageProcessor::GetNumberOfUnits()
1018 return GetSrcImage()->Bounds().IntegerHeight() + 1;
1023 ImageProcessor::BytesPerPixel(color_space cs
) const
1026 case B_RGB32
: // fall through
1027 case B_RGB32_BIG
: // fall through
1028 case B_RGBA32
: // fall through
1029 case B_RGBA32_BIG
: return 4;
1031 case B_RGB24_BIG
: // fall through
1032 case B_RGB24
: return 3;
1034 case B_RGB16
: // fall through
1035 case B_RGB16_BIG
: // fall through
1036 case B_RGB15
: // fall through
1037 case B_RGB15_BIG
: // fall through
1038 case B_RGBA15
: // fall through
1039 case B_RGBA15_BIG
: return 2;
1041 case B_GRAY8
: // fall through
1042 case B_CMAP8
: return 1;
1043 case B_GRAY1
: return 0;
1050 ImageProcessor::CopyPixel(uchar
* dest
, int32 destX
, int32 destY
,
1051 const uchar
* src
, int32 x
, int32 y
)
1053 // Note: On my systems (Dual Intel P3 866MHz and AMD Athlon 1GHz),
1054 // replacing the multiplications below with pointer arithmethics showed
1055 // no speedup at all!
1056 dest
+= fDestBPR
* destY
+ destX
* fBPP
;
1057 src
+= fSrcBPR
* y
+ x
* fBPP
;
1058 // Replacing memcpy with this switch statement is slightly faster
1073 // Note: For B_CMAP8 InvertPixel inverts the color index not the color value!
1075 ImageProcessor::InvertPixel(int32 x
, int32 y
, uchar
* dest
, const uchar
* src
)
1077 dest
+= fDestBPR
* y
+ x
* fBPP
;
1078 src
+= fSrcBPR
* y
+ x
* fBPP
;
1081 // dest[3] = ~src[3]; DON'T invert alpha channel
1093 // Note: On my systems, the operation kInvert shows a speedup on
1094 // multiple CPUs only!
1096 ImageProcessor::Run(int32 i
, int32 n
)
1099 int32 height
= (fHeight
+ 1) / n
;
1104 to
= from
+ height
- 1;
1106 int32 x
, y
, destX
, destY
;
1107 const uchar
* src
= (uchar
*)GetSrcImage()->Bits();
1108 uchar
* dest
= (uchar
*)GetDestImage()->Bits();
1111 case kRotateClockwise
:
1112 for (y
= from
; y
<= to
; y
++) {
1113 for (x
= 0; x
<= fWidth
; x
++) {
1114 destX
= fHeight
- y
;
1116 CopyPixel(dest
, destX
, destY
, src
, x
, y
);
1120 case kRotateCounterClockwise
:
1121 for (y
= from
; y
<= to
; y
++) {
1122 for (x
= 0; x
<= fWidth
; x
++) {
1125 CopyPixel(dest
, destX
, destY
, src
, x
, y
);
1129 case kFlipTopToBottom
:
1130 for (y
= from
; y
<= to
; y
++) {
1131 for (x
= 0; x
<= fWidth
; x
++) {
1133 destY
= fHeight
- y
;
1134 CopyPixel(dest
, destX
, destY
, src
, x
, y
);
1138 case kFlipLeftToRight
:
1139 for (y
= from
; y
<= to
; y
++) {
1140 for (x
= 0; x
<= fWidth
; x
++) {
1143 CopyPixel(dest
, destX
, destY
, src
, x
, y
);
1148 for (y
= from
; y
<= to
; y
++) {
1149 for (x
= 0; x
<= fWidth
; x
++) {
1150 InvertPixel(x
, y
, dest
, src
);