Rewrote get_valid_rect because it contained bugs.

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@11437 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Pfeiffer 2005-02-21 17:33:16 +00:00
parent acc60ee067
commit 5d4b78560b

View File

@ -1,110 +1,194 @@
/* /*
* ValidRect.cpp * ValidRect.cpp
* Copyright 1999-2000 Y.Takagi. All Rights Reserved. * Copyright 1999-2000 Y.Takagi. All Rights Reserved.
* Copyright 2005 Michael Pfeiffer. All Rights Reserved.
* - Rewrote get_valid_rect from scratch.
*/ */
#include <Bitmap.h> #include <Bitmap.h>
#include "ValidRect.h" #include "ValidRect.h"
bool get_valid_line_RGB32( #define INLINE inline
const uchar *bits,
int width, class BoundsCalculator
int *left,
int *right)
{ {
int i = 0; public:
rgb_color c; bool getValidRect(BBitmap *bitmap, RECT *rect);
const rgb_color *ptr = (const rgb_color *)bits;
while (i < *left) { private:
c = *ptr++; const uchar *fBits;
if (c.red != 0xff || c.green != 0xff || c.blue != 0xff) { int fBPR;
*left = i; int fLeft;
break; int fRight;
} int fTop;
i++; int fBottom;
} int fWidth;
if (i == width) { int fLeftBound;
int fRightBound;
INLINE bool isEmpty(const rgb_color *pixel);
INLINE bool isRowEmpty(const rgb_color *row);
INLINE const uchar *getRow(int x, int y);
int getTop();
int getBottom();
INLINE void updateLeftBound(const rgb_color *row);
INLINE void updateRightBound(const rgb_color *row);
};
bool
BoundsCalculator::isEmpty(const rgb_color *pixel)
{
return pixel->red == 0xff && pixel->green == 0xff && pixel->blue == 0xff;
}
bool
BoundsCalculator::isRowEmpty(const rgb_color *row)
{
for (int x = 0; x < fWidth; x ++) {
if (!isEmpty(row)) {
return false; return false;
} }
row ++;
i = width - 1;
ptr = (const rgb_color *)bits + width - 1;
while (i > *right) {
c = *ptr--;
if (c.red != 0xff || c.green != 0xff || c.blue != 0xff) {
*right = i;
break;
}
i--;
} }
return true; return true;
} }
typedef bool (*PFN_GET_VALID_LINE)(const uchar *, int, int *, int *); const uchar *
BoundsCalculator::getRow(int x, int y)
bool get_valid_rect(BBitmap *a_bitmap, RECT *rc)
{ {
int width = rc->right - rc->left + 1; return fBits + x + fBPR * y;
int height = rc->bottom - rc->top + 1; }
int delta = a_bitmap->BytesPerRow();
int left = width; int
int right = 0; BoundsCalculator::getTop()
int top = 0; {
int bottom = 0; const uchar* row = getRow(fLeft, fTop);
PFN_GET_VALID_LINE get_valid_line; int top;
for (top = fTop; top <= fBottom; top ++) {
if (!isRowEmpty((const rgb_color*)row)) {
break;
}
row += fBPR;
}
switch (a_bitmap->ColorSpace()) { return top;
}
int
BoundsCalculator::getBottom()
{
const uchar *row = getRow(fLeft, fBottom);
int bottom;
for (bottom = fBottom; bottom >= fTop; bottom --) {
if (!isRowEmpty((const rgb_color*)row)) {
break;
}
row -= fBPR;
}
return bottom;
}
void
BoundsCalculator::updateLeftBound(const rgb_color *row)
{
for (int x = fLeft; x < fLeftBound; x ++) {
if (!isEmpty(row)) {
fLeftBound = x;
return;
}
row ++;
}
}
void
BoundsCalculator::updateRightBound(const rgb_color *row)
{
row += fWidth - 1;
for (int x = fRight; x > fRightBound; x --) {
if (!isEmpty(row)) {
fRightBound = x;
return;
}
row --;
}
}
// returns false if the bitmap is empty or has wrong color space.
bool
BoundsCalculator::getValidRect(BBitmap *bitmap, RECT *rect)
{
enum {
kRectIsInvalid = false,
kRectIsEmpty = false,
kRectIsValid = true
};
switch (bitmap->ColorSpace()) {
case B_RGB32: case B_RGB32:
case B_RGB32_BIG: case B_RGB32_BIG:
get_valid_line = get_valid_line_RGB32;
break; break;
default: default:
return false; return kRectIsInvalid;
break; break;
}; };
int i = 0; // initialize member variables
uchar *ptr = (uchar *)a_bitmap->Bits(); fBits = (uchar*)bitmap->Bits();
fBPR = bitmap->BytesPerRow();
while (i < height) { fLeft = rect->left;
if (get_valid_line(ptr, width, &left, &right)) { fRight = rect->right;
top = i; fTop = rect->top;
fBottom = rect->bottom;
fWidth = fRight - fLeft + 1;
// get top bound
fTop = getTop();
if (fTop > fBottom) {
return kRectIsEmpty;
}
// get bottom bound
fBottom = getBottom();
// calculate left and right bounds
fLeftBound = fRight + 1;
fRightBound = fLeft - 1;
const uchar *row = getRow(fLeft, fTop);
for (int y = fTop; y <= fBottom; y ++) {
updateLeftBound((const rgb_color*)row);
updateRightBound((const rgb_color*)row);
if (fLeft == fLeftBound && fRight == fRightBound) {
break; break;
} }
ptr += delta; row += fBPR;
i++;
} }
if (i == height) { // return bounds in rectangle
return false; rect->left = fLeftBound;
} rect->right = fRightBound;
rect->top = fTop;
rect->bottom = fBottom;
int j = height - 1; return kRectIsValid;
ptr = (uchar *)a_bitmap->Bits() + (height - 1) * delta; }
bool found_boundary = false;
while (j >= i) { bool get_valid_rect(BBitmap *a_bitmap, RECT *rc)
if (get_valid_line(ptr, width, &left, &right)) { {
if (!found_boundary) { BoundsCalculator calculator;
bottom = j; return calculator.getValidRect(a_bitmap, rc);
found_boundary = true;
}
}
ptr -= delta;
j--;
}
rc->left = left;
rc->top = top;
rc->right = right;
rc->bottom = bottom;
return true;
} }
int color_space2pixel_depth(color_space cs) int color_space2pixel_depth(color_space cs)