1 /*
2 * ValidRect.cpp
3 * Copyright 1999-2000 Y.Takagi. All Rights Reserved.
4 * Copyright 2005 Michael Pfeiffer. All Rights Reserved.
5 * - Rewrote get_valid_rect from scratch.
6 */
7
8 #include <Bitmap.h>
9 #include "ValidRect.h"
10
11 #define INLINE inline
12
13 class BoundsCalculator
14 {
15 public:
16 bool getValidRect(BBitmap *bitmap, RECT *rect);
17
18 private:
19 const uchar *fBits;
20 int fBPR;
21 int fLeft;
22 int fRight;
23 int fTop;
24 int fBottom;
25 int fWidth;
26
27 int fLeftBound;
28 int fRightBound;
29
30 INLINE bool isEmpty(const rgb_color *pixel);
31
32 INLINE bool isRowEmpty(const rgb_color *row);
33
34 INLINE const uchar *getRow(int x, int y);
35
36 int getTop();
37
38 int getBottom();
39
40 INLINE void updateLeftBound(const rgb_color *row);
41 INLINE void updateRightBound(const rgb_color *row);
42 };
43
44
45 bool
isEmpty(const rgb_color * pixel)46 BoundsCalculator::isEmpty(const rgb_color *pixel)
47 {
48 return pixel->red == 0xff && pixel->green == 0xff && pixel->blue == 0xff;
49 }
50
51
52 bool
isRowEmpty(const rgb_color * row)53 BoundsCalculator::isRowEmpty(const rgb_color *row)
54 {
55 for (int x = 0; x < fWidth; x ++) {
56 if (!isEmpty(row)) {
57 return false;
58 }
59 row ++;
60 }
61 return true;
62 }
63
64
65 const uchar *
getRow(int x,int y)66 BoundsCalculator::getRow(int x, int y)
67 {
68 return fBits + x + fBPR * y;
69 }
70
71
72 int
getTop()73 BoundsCalculator::getTop()
74 {
75 const uchar* row = getRow(fLeft, fTop);
76
77 int top;
78 for (top = fTop; top <= fBottom; top ++) {
79 if (!isRowEmpty((const rgb_color*)row)) {
80 break;
81 }
82 row += fBPR;
83 }
84
85 return top;
86 }
87
88
89 int
getBottom()90 BoundsCalculator::getBottom()
91 {
92 const uchar *row = getRow(fLeft, fBottom);
93
94 int bottom;
95 for (bottom = fBottom; bottom >= fTop; bottom --) {
96 if (!isRowEmpty((const rgb_color*)row)) {
97 break;
98 }
99 row -= fBPR;
100 }
101
102 return bottom;
103 }
104
105
106 void
updateLeftBound(const rgb_color * row)107 BoundsCalculator::updateLeftBound(const rgb_color *row)
108 {
109 for (int x = fLeft; x < fLeftBound; x ++) {
110 if (!isEmpty(row)) {
111 fLeftBound = x;
112 return;
113 }
114 row ++;
115 }
116 }
117
118
119 void
updateRightBound(const rgb_color * row)120 BoundsCalculator::updateRightBound(const rgb_color *row)
121 {
122 row += fWidth - 1;
123 for (int x = fRight; x > fRightBound; x --) {
124 if (!isEmpty(row)) {
125 fRightBound = x;
126 return;
127 }
128 row --;
129 }
130 }
131
132
133 // returns false if the bitmap is empty or has wrong color space.
134 bool
getValidRect(BBitmap * bitmap,RECT * rect)135 BoundsCalculator::getValidRect(BBitmap *bitmap, RECT *rect)
136 {
137 enum {
138 kRectIsInvalid = false,
139 kRectIsEmpty = false,
140 kRectIsValid = true
141 };
142
143 switch (bitmap->ColorSpace()) {
144 case B_RGB32:
145 case B_RGB32_BIG:
146 break;
147 default:
148 return kRectIsInvalid;
149 break;
150 };
151
152 // initialize member variables
153 fBits = (uchar*)bitmap->Bits();
154 fBPR = bitmap->BytesPerRow();
155
156 fLeft = rect->left;
157 fRight = rect->right;
158 fTop = rect->top;
159 fBottom = rect->bottom;
160
161 fWidth = fRight - fLeft + 1;
162
163 // get top bound
164 fTop = getTop();
165 if (fTop > fBottom) {
166 return kRectIsEmpty;
167 }
168
169 // get bottom bound
170 fBottom = getBottom();
171
172 // calculate left and right bounds
173 fLeftBound = fRight + 1;
174 fRightBound = fLeft - 1;
175
176 const uchar *row = getRow(fLeft, fTop);
177 for (int y = fTop; y <= fBottom; y ++) {
178 updateLeftBound((const rgb_color*)row);
179 updateRightBound((const rgb_color*)row);
180 if (fLeft == fLeftBound && fRight == fRightBound) {
181 break;
182 }
183 row += fBPR;
184 }
185
186 // return bounds in rectangle
187 rect->left = fLeftBound;
188 rect->right = fRightBound;
189 rect->top = fTop;
190 rect->bottom = fBottom;
191
192 return kRectIsValid;
193 }
194
195
get_valid_rect(BBitmap * a_bitmap,RECT * rc)196 bool get_valid_rect(BBitmap *a_bitmap, RECT *rc)
197 {
198 BoundsCalculator calculator;
199 return calculator.getValidRect(a_bitmap, rc);
200 }
201
202
color_space2pixel_depth(color_space cs)203 int color_space2pixel_depth(color_space cs)
204 {
205 int pixel_depth;
206
207 switch (cs) {
208 case B_GRAY1: /* Y0[0],Y1[0],Y2[0],Y3[0],Y4[0],Y5[0],Y6[0],Y7[0] */
209 pixel_depth = 1;
210 break;
211 case B_GRAY8: /* Y[7:0] */
212 case B_CMAP8: /* D[7:0] */
213 pixel_depth = 8;
214 break;
215 case B_RGB15: /* G[2:0],B[4:0] -[0],R[4:0],G[4:3] */
216 case B_RGB15_BIG: /* -[0],R[4:0],G[4:3] G[2:0],B[4:0] */
217 pixel_depth = 16;
218 break;
219 case B_RGB32: /* B[7:0] G[7:0] R[7:0] -[7:0] */
220 case B_RGB32_BIG: /* -[7:0] R[7:0] G[7:0] B[7:0] */
221 pixel_depth = 32;
222 break;
223 default:
224 pixel_depth = 0;
225 break;
226 }
227 return pixel_depth;
228 }
229