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
13class BoundsCalculator
14{
15public:
16	bool getValidRect(BBitmap *bitmap, RECT *rect);
17
18private:
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
45bool
46BoundsCalculator::isEmpty(const rgb_color *pixel)
47{
48	return pixel->red == 0xff && pixel->green == 0xff && pixel->blue == 0xff;
49}
50
51
52bool
53BoundsCalculator::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
65const uchar *
66BoundsCalculator::getRow(int x, int y)
67{
68	return fBits + x + fBPR * y;
69}
70
71
72int
73BoundsCalculator::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
89int
90BoundsCalculator::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
106void
107BoundsCalculator::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
119void
120BoundsCalculator::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.
134bool
135BoundsCalculator::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
196bool get_valid_rect(BBitmap *a_bitmap, RECT *rc)
197{
198	BoundsCalculator calculator;
199	return calculator.getValidRect(a_bitmap, rc);
200}
201
202
203int 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