diff --git a/artpaint/Utilities/BitmapUtilities.cpp b/artpaint/Utilities/BitmapUtilities.cpp index 1d5d68f7..03e55313 100644 --- a/artpaint/Utilities/BitmapUtilities.cpp +++ b/artpaint/Utilities/BitmapUtilities.cpp @@ -149,11 +149,7 @@ BitmapUtilities::ConvertToMask(BBitmap* inBitmap, uint8 color) for (int32 y = 0; y < out_map->Bounds().IntegerHeight() + 1; y++) { for (int32 x = 0; x < out_map->Bounds().IntegerWidth() + 1; x++) { c.word = *(in_bits + x + y * in_bpr); - // revert this change when the rest of ArtPaint understands - // selections with alpha - float alpha = 0; - if (c.bytes[3] > 0x00) - alpha = 1; + float alpha = (float)c.bytes[3] / 255.; *(out_bits + x + y * out_bpr) = (uint8)((float)color * alpha); } diff --git a/artpaint/Utilities/ScaleUtilities.cpp b/artpaint/Utilities/ScaleUtilities.cpp index 31c1d37d..9248a68d 100644 --- a/artpaint/Utilities/ScaleUtilities.cpp +++ b/artpaint/Utilities/ScaleUtilities.cpp @@ -193,14 +193,18 @@ ScaleUtilities::ScaleVerticallyGray(float width, float height, BPoint offset, BB uint8* source_bits = (uint8*)source->Bits(); int32 source_bpr = source->BytesPerRow(); - for (int32 y = 0; y <= (int32)height; y++) { + int32 max_width = width; + int32 max_height = height; + + for (int32 y = 0; y <= (int32)max_height; y++) { int32 low = floor(ratio * y); int32 high = ceil(ratio * y); float weight = (ratio * y) - low; + uint8* src_bits_low = source_bits + (int32)offset.x + (low + (int32)ceil(offset.y + 0.5)) * source_bpr; uint8* src_bits_high = source_bits + (int32)offset.x + (high + (int32)ceil(offset.y + 0.5)) * source_bpr; - for (int32 x = 0; x <= width; x++) { + for (int32 x = 0; x <= max_width; x++) { *(target_bits + x + y * target_bpr) = linear_interpolation(*(src_bits_low + x), *(src_bits_high + x), weight); diff --git a/artpaint/application/PixelOperations.h b/artpaint/application/PixelOperations.h index d8aaf1da..483496bc 100644 --- a/artpaint/application/PixelOperations.h +++ b/artpaint/application/PixelOperations.h @@ -715,6 +715,12 @@ inline uint32 linear_interpolation(uint32 p1, uint32 p2, float t) } +inline uint8 linear_interpolation(uint8 p1, uint8 p2, float t) +{ + return (p1 * (1.0 - t)) + (p2 * t); +} + + inline uint32 mitchell_netravali(uint32 p0, uint32 p1, uint32 p2, uint32 p3, float t, float B, float C) { diff --git a/artpaint/application/Selection.cpp b/artpaint/application/Selection.cpp index 47e255aa..7ec954fe 100644 --- a/artpaint/application/Selection.cpp +++ b/artpaint/application/Selection.cpp @@ -824,7 +824,12 @@ Selection::Invert() uint8* bits = (uint8*)selection_map->Bits(); int32 bits_length = selection_map->BitsLength(); for (int32 i = 0; i < bits_length; i++) { - *bits = ~(*bits); + union color_conversion pixel; + pixel.word = *bits; + for (int i = 0; i < 4; ++i) + pixel.bytes[i] = 255 - pixel.bytes[i]; + + *bits = pixel.word; ++bits; } selection_bounds = BRect(0, 0, -1, -1); diff --git a/artpaint/application/Selection.h b/artpaint/application/Selection.h index 21bb6df8..7f10a187 100644 --- a/artpaint/application/Selection.h +++ b/artpaint/application/Selection.h @@ -185,6 +185,9 @@ class Selection { // GetBoundingRect-function. inline bool ContainsPoint(BPoint); inline bool ContainsPoint(int32, int32); + + inline uint8 Value(BPoint); + inline uint8 Value(int32, int32); }; @@ -207,6 +210,26 @@ Selection::ContainsPoint(int32 x, int32 y) } +uint8 +Selection::Value(BPoint p) +{ + return Value((int32)p.x, (int32)p.y); +} + + +uint8 +Selection::Value(int32 x, int32 y) +{ + if (x < 0 || y < 0) + return 0; + + if (selection_bits == NULL || image_bounds.Contains(BPoint(x, y)) == false) + return 0; + + return *(selection_bits + y * selection_bpr + x); +} + + // This class contains the vital data that describe selection. A selection // can be archived with such data and selection can also be modified to // represent the same selection as the SelectionData represents. diff --git a/artpaint/paintwindow/ImageView.cpp b/artpaint/paintwindow/ImageView.cpp index e557dfb2..58d64d65 100644 --- a/artpaint/paintwindow/ImageView.cpp +++ b/artpaint/paintwindow/ImageView.cpp @@ -2114,9 +2114,6 @@ ImageView::ManipulatorFinisherThread() the_image->SetImageSize(); the_image->Render(); - // also recalculate the selection - selection->Recalculate(); - // Change the selection for the undo-queue if necessary. if ((new_event != NULL) && !(undo_queue->ReturnSelectionMap() == selection->ReturnSelectionMap())) { diff --git a/artpaint/tools/BitmapDrawer.cpp b/artpaint/tools/BitmapDrawer.cpp index bf1d3002..bef66247 100644 --- a/artpaint/tools/BitmapDrawer.cpp +++ b/artpaint/tools/BitmapDrawer.cpp @@ -1216,6 +1216,10 @@ BitmapDrawer::SetPixel( BPoint location, uint32 color, Selection* sel, uint32 (*composite_func)(uint32, uint32)) { if (sel == NULL || sel->ContainsPoint(location)) { + float sel_alpha = 1.0; + if (sel != NULL && sel->IsEmpty() == false) + sel_alpha = sel->Value(location) / 255.; + if (bitmap_bounds.Contains(location)) { if (composite_func) { union { @@ -1224,14 +1228,24 @@ BitmapDrawer::SetPixel( } norm_color, target_color; norm_color.word = color; + norm_color.bytes[3] *= sel_alpha; uint32 target = GetPixel(location); target_color.word = target; *(bitmap_bits + (int32)location.x + (int32)location.y * bitmap_bpr) = (*composite_func)(target_color.word, norm_color.word); - } else - *(bitmap_bits + (int32)location.x + (int32)location.y * bitmap_bpr) = color; + } else { + union { + unsigned char bytes[4]; + uint32 word; + } norm_color; + + norm_color.word = color; + norm_color.bytes[3] *= sel_alpha; + + *(bitmap_bits + (int32)location.x + (int32)location.y * bitmap_bpr) = norm_color.word; + } return B_OK; } else diff --git a/artpaint/tools/Brush.cpp b/artpaint/tools/Brush.cpp index 218ef2f2..2d21f5f1 100644 --- a/artpaint/tools/Brush.cpp +++ b/artpaint/tools/Brush.cpp @@ -491,11 +491,16 @@ Brush::draw(BBitmap* buffer, BPoint point, Selection* selection) target_bits = bits + (y + py) * bpr + left; for (int32 x = left; x <= right; ++x) { if (selection->IsEmpty() || selection->ContainsPoint(x, y + py)) { + float sel_alpha = 1.0; + if (selection->IsEmpty() == false && selection->ContainsPoint(x, y + py)) + sel_alpha = selection->Value(x, y + py) / 255.; + union color_conversion brush_color, target_color, result; brush_color.word = *(brush_bits + (x - px) + y * brush_bpr); brush_color.bytes[0] = 0xFF; brush_color.bytes[1] = 0xFF; brush_color.bytes[2] = 0xFF; + brush_color.bytes[3] *= sel_alpha; target_color.word = *target_bits; diff --git a/artpaint/tools/FillTool.cpp b/artpaint/tools/FillTool.cpp index e9763fbd..dc7cbb8f 100644 --- a/artpaint/tools/FillTool.cpp +++ b/artpaint/tools/FillTool.cpp @@ -197,7 +197,7 @@ FillTool::NormalFill(ImageView* view, uint32 buttons, BPoint start, Selection* s if ((sel == NULL || sel->IsEmpty() == true || sel->ContainsPoint(x, y)) && compare_2_pixels_with_variance( old_color, drawer->GetPixel(x, y), tolerance)) { - drawer->SetPixel(x, y, color); + drawer->SetPixel(x, y, color, sel); } } } @@ -246,7 +246,7 @@ FillTool::CheckSpans(BPoint span_start, BitmapDrawer* drawer, PointStack& stack, } else if (binary_bits != NULL) *(binary_bits + y * binary_bpr + (x / 8)) |= (0x01 << (7 - x % 8)); - drawer->SetPixel(x, y, new_color); + drawer->SetPixel(x, y, new_color, sel); if (spans == BOTH || spans == LOWER) { if ((inside_lower_span == FALSE) @@ -303,7 +303,7 @@ FillTool::CheckSpans(BPoint span_start, BitmapDrawer* drawer, PointStack& stack, } else if (binary_bits != NULL) *(binary_bits + y * binary_bpr + (x / 8)) |= (0x01 << (7 - x % 8)); - drawer->SetPixel(x, y, new_color); + drawer->SetPixel(x, y, new_color, sel); if (spans == BOTH || spans == LOWER) { if ((inside_lower_span == FALSE) @@ -364,7 +364,7 @@ FillTool::FillSpan(BPoint span_start, BitmapDrawer* drawer, int32 min_x, int32 m // Then go from start towards the left side of the bitmap. while ((sel == NULL || sel->IsEmpty() || sel->ContainsPoint(x, y)) && (x >= min_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x, y), old_color, tolerance))) { - drawer->SetPixel(x, y, new_color); + drawer->SetPixel(x, y, new_color, sel); if (binary_bits != NULL) *(binary_bits + y * binary_bpr + (x / 8)) = *(binary_bits + y * binary_bpr + (x / 8)) | (0x01 << (7 - x % 8)); @@ -375,7 +375,7 @@ FillTool::FillSpan(BPoint span_start, BitmapDrawer* drawer, int32 min_x, int32 m x = start_x + 1; while ((sel == NULL || sel->IsEmpty() || sel->ContainsPoint(x, y)) && (x <= max_x) && (compare_2_pixels_with_variance(drawer->GetPixel(x, y), old_color, tolerance))) { - drawer->SetPixel(x, y, new_color); + drawer->SetPixel(x, y, new_color, sel); if (binary_bits != NULL) *(binary_bits + y * binary_bpr + (x / 8)) = *(binary_bits + y * binary_bpr + (x / 8)) | (0x01 << (7 - x % 8)); @@ -523,16 +523,16 @@ FillTool::GradientFill( if (fToolSettings.shape == GRADIENT_CONIC) { FillGradientConic(drawer, binary_map, start, new_point, min_x, max_x, min_y, - max_y, color, gradient_color); + max_y, color, gradient_color, 2, sel); } else if (fToolSettings.shape == GRADIENT_RADIAL) { FillGradientRadial(drawer, binary_map, start, new_point, min_x, max_x, - min_y, max_y, color, gradient_color, 2); + min_y, max_y, color, gradient_color, 2, sel); } else if (fToolSettings.shape == GRADIENT_SQUARE) { FillGradientSquare(drawer, binary_map, start, new_point, min_x, max_x, - min_y, max_y, color, gradient_color, 2); + min_y, max_y, color, gradient_color, 2, sel); } else { FillGradientLinear(drawer, binary_map, start, new_point, min_x, max_x, - min_y, max_y, color, gradient_color, 2); + min_y, max_y, color, gradient_color, 2, sel); } bitmap->Lock(); @@ -560,16 +560,16 @@ FillTool::GradientFill( // Here calculate the final gradient. if (fToolSettings.shape == GRADIENT_CONIC) { FillGradientConic(drawer, binary_map, start, new_point, min_x, max_x, min_y, max_y, - color, gradient_color); + color, gradient_color, 1, sel); } else if (fToolSettings.shape == GRADIENT_RADIAL) { FillGradientRadial(drawer, binary_map, start, new_point, min_x, max_x, min_y, max_y, - color, gradient_color); + color, gradient_color, 1, sel); } else if (fToolSettings.shape == GRADIENT_SQUARE) { FillGradientSquare(drawer, binary_map, start, new_point, min_x, max_x, min_y, max_y, - color, gradient_color); + color, gradient_color, 1, sel); } else { FillGradientLinear(drawer, binary_map, start, new_point, min_x, max_x, min_y, max_y, - color, gradient_color); + color, gradient_color, 1, sel); } // Update the image-view. bitmap->Lock(); @@ -773,7 +773,7 @@ FillTool::MakeFloodBinaryMap(BitmapDrawer* drawer, int32 min_x, int32 max_x, int void FillTool::FillGradientLinear(BitmapDrawer* drawer, BBitmap* binary_map, BPoint start, BPoint end, int32 min_x, int32 max_x, int32 min_y, int32 max_y, uint32 new_color, uint32 gradient_color, - uint8 skip) + uint8 skip, Selection* sel) { uchar* binary_bits = (uchar*)binary_map->Bits(); int32 binary_bpr = binary_map->BytesPerRow(); @@ -838,7 +838,7 @@ FillTool::FillGradientLinear(BitmapDrawer* drawer, BBitmap* binary_map, BPoint s for (int dy = 0; dy < skip; ++dy) { for (int dx = 0; dx < skip; ++dx) - drawer->SetPixel(x + dx, y + dy, out_color.word); + drawer->SetPixel(x + dx, y + dy, out_color.word, sel); } } } @@ -849,7 +849,7 @@ FillTool::FillGradientLinear(BitmapDrawer* drawer, BBitmap* binary_map, BPoint s void FillTool::FillGradientRadial(BitmapDrawer* drawer, BBitmap* binary_map, BPoint start, BPoint end, int32 min_x, int32 max_x, int32 min_y, int32 max_y, uint32 new_color, uint32 gradient_color, - uint8 skip) + uint8 skip, Selection* sel) { uchar* binary_bits = (uchar*)binary_map->Bits(); int32 binary_bpr = binary_map->BytesPerRow(); @@ -901,7 +901,7 @@ FillTool::FillGradientRadial(BitmapDrawer* drawer, BBitmap* binary_map, BPoint s for (int dy = 0; dy < skip; ++dy) { for (int dx = 0; dx < skip; ++dx) - drawer->SetPixel(x + dx, y + dy, out_color.word); + drawer->SetPixel(x + dx, y + dy, out_color.word, sel); } } } @@ -912,7 +912,7 @@ FillTool::FillGradientRadial(BitmapDrawer* drawer, BBitmap* binary_map, BPoint s void FillTool::FillGradientSquare(BitmapDrawer* drawer, BBitmap* binary_map, BPoint start, BPoint end, int32 min_x, int32 max_x, int32 min_y, int32 max_y, uint32 new_color, uint32 gradient_color, - uint8 skip) + uint8 skip, Selection* sel) { uchar* binary_bits = (uchar*)binary_map->Bits(); int32 binary_bpr = binary_map->BytesPerRow(); @@ -971,7 +971,7 @@ FillTool::FillGradientSquare(BitmapDrawer* drawer, BBitmap* binary_map, BPoint s for (int dy = 0; dy < skip; ++dy) { for (int dx = 0; dx < skip; ++dx) - drawer->SetPixel(x + dx, y + dy, out_color.word); + drawer->SetPixel(x + dx, y + dy, out_color.word, sel); } } } @@ -982,7 +982,7 @@ FillTool::FillGradientSquare(BitmapDrawer* drawer, BBitmap* binary_map, BPoint s void FillTool::FillGradientConic(BitmapDrawer* drawer, BBitmap* binary_map, BPoint start, BPoint end, int32 min_x, int32 max_x, int32 min_y, int32 max_y, uint32 new_color, uint32 gradient_color, - uint8 skip) + uint8 skip, Selection* sel) { uchar* binary_bits = (uchar*)binary_map->Bits(); int32 binary_bpr = binary_map->BytesPerRow(); @@ -1043,7 +1043,7 @@ FillTool::FillGradientConic(BitmapDrawer* drawer, BBitmap* binary_map, BPoint st for (int dy = 0; dy < skip; ++dy) { for (int dx = 0; dx < skip; ++dx) - drawer->SetPixel(x + dx, y + dy, out_color.word); + drawer->SetPixel(x + dx, y + dy, out_color.word, sel); } } } diff --git a/artpaint/tools/FillTool.h b/artpaint/tools/FillTool.h index bf74c77d..c8f40a7c 100644 --- a/artpaint/tools/FillTool.h +++ b/artpaint/tools/FillTool.h @@ -83,16 +83,16 @@ class FillTool : public DrawingTool { Selection* = NULL); void FillGradientLinear(BitmapDrawer*, BBitmap*, BPoint, BPoint, int32, int32, int32, int32, uint32, - uint32, uint8 skip = 1); + uint32, uint8 skip = 1, Selection* sel = NULL); void FillGradientRadial(BitmapDrawer*, BBitmap*, BPoint, BPoint, int32, int32, int32, int32, uint32, - uint32, uint8 skip = 1); + uint32, uint8 skip = 1, Selection* sel = NULL); void FillGradientSquare(BitmapDrawer*, BBitmap*, BPoint, BPoint, int32, int32, int32, int32, uint32, - uint32, uint8 skip = 1); + uint32, uint8 skip = 1, Selection* sel = NULL); void FillGradientConic(BitmapDrawer*, BBitmap*, BPoint, BPoint, int32, int32, int32, int32, uint32, - uint32, uint8 skip = 1); + uint32, uint8 skip = 1, Selection* sel = NULL); BRect calcBinaryMapBounds(BBitmap *boolean_map); }; diff --git a/artpaint/viewmanipulators/RotationManipulator.cpp b/artpaint/viewmanipulators/RotationManipulator.cpp index 2aec36d9..e91158f1 100644 --- a/artpaint/viewmanipulators/RotationManipulator.cpp +++ b/artpaint/viewmanipulators/RotationManipulator.cpp @@ -365,8 +365,8 @@ RotationManipulator::ManipulateBitmap( } // We must make a copy of the selection in order to be able to rotate it - selection->RotateTo(center, the_angle); - selection->Recalculate(); + BBitmap* selmap = ManipulateSelectionMap(new_settings); + selection->ReplaceSelection(selmap); BRect selection_bounds = selection->GetBoundingRect(); int32 sel_top = (int32)selection_bounds.top; @@ -693,7 +693,6 @@ RotationManipulator::PreviewBitmap(bool full_quality, BRegion* updated_region) void RotationManipulator::Reset() { - selection->RotateTo(settings->origo, 0); settings->angle = 0; previous_angle = 0; diff --git a/artpaint/viewmanipulators/ScaleManipulator.cpp b/artpaint/viewmanipulators/ScaleManipulator.cpp index e829a589..7ce09d63 100644 --- a/artpaint/viewmanipulators/ScaleManipulator.cpp +++ b/artpaint/viewmanipulators/ScaleManipulator.cpp @@ -306,14 +306,10 @@ ScaleManipulator::ManipulateBitmap( target_bits = (uint32*)final_bitmap->Bits(); uint32 target_bpr = final_bitmap->BytesPerRow() / 4; - if (selection != NULL && selection->IsEmpty() == FALSE) - final_bounds = bounds; - else { - final_bounds.top = settings->top; - final_bounds.bottom = settings->bottom; - final_bounds.left = settings->left; - final_bounds.right = settings->right; - } + final_bounds.top = settings->top; + final_bounds.bottom = settings->bottom; + final_bounds.left = settings->left; + final_bounds.right = settings->right; if (source_bits != NULL) { for (int32 y = final_bounds.top; y <= final_bounds.bottom; y++) { @@ -329,7 +325,7 @@ ScaleManipulator::ManipulateBitmap( if (selection == NULL || selection->IsEmpty() == TRUE || selection->ContainsPoint(x, y)) { int32 src_x = x - final_bounds.left; - if (src_x >= target_bpr || src_x >= source_bpr) + if (src_x >= source_bpr) break; if (x < 0) continue; @@ -408,8 +404,12 @@ ScaleManipulator::ManipulateSelectionMap(ManipulatorSettings* set) BBitmap* scale_x_bitmap = NULL; BBitmap* scale_y_bitmap = NULL; + BRect scale_x_frame(bitmap_frame); + if (new_width != starting_width) { - scale_x_bitmap = new BBitmap(bitmap_frame, B_GRAY8); + scale_x_frame.right = max_c(scale_x_frame.right, new_width); + + scale_x_bitmap = new BBitmap(scale_x_frame, B_GRAY8); if (scale_x_bitmap->IsValid() == FALSE) throw std::bad_alloc(); @@ -424,7 +424,7 @@ ScaleManipulator::ManipulateSelectionMap(ManipulatorSettings* set) *(target_bits + x + y * target_bpr) = background; if (diff != 1) { - ScaleUtilities::ScaleHorizontallyGray(target_bpr, starting_height, + ScaleUtilities::ScaleHorizontallyGray(new_width, starting_height, BPoint(original_left, original_top), selection_map, scale_x_bitmap, diff); } else { for (int32 y = 0; y <= selection_map->Bounds().Height(); y++) { @@ -439,7 +439,10 @@ ScaleManipulator::ManipulateSelectionMap(ManipulatorSettings* set) } if (new_height != starting_height) { - scale_y_bitmap = new BBitmap(bitmap_frame, B_GRAY8); + BRect scale_y_frame(scale_x_frame); + + scale_y_frame.bottom = max_c(scale_y_frame.bottom, new_height); + scale_y_bitmap = new BBitmap(scale_y_frame, B_GRAY8); if (scale_y_bitmap->IsValid() == FALSE) throw std::bad_alloc(); @@ -448,8 +451,10 @@ ScaleManipulator::ManipulateSelectionMap(ManipulatorSettings* set) source_bits = (uint8*)scale_x_bitmap->Bits(); int32 source_bpr = scale_x_bitmap->BytesPerRow(); - for (int32 y = 0; y < new_height; y++) - for (int32 x = 0; x < new_width; x++) + int32 max_height = min_c(new_height, scale_y_bitmap->Bounds().Height()); + int32 max_width = min_c(new_width, target_bpr); + for (int32 y = 0; y < max_height; y++) + for (int32 x = 0; x < max_width; x++) *(target_bits + x + y * target_bpr) = background; int32 top = (int32)bounds.top; @@ -466,8 +471,8 @@ ScaleManipulator::ManipulateSelectionMap(ManipulatorSettings* set) ScaleUtilities::ScaleVerticallyGray(new_width, new_height, BPoint(left, top), scale_x_bitmap, scale_y_bitmap, diff); } else { - for (int32 y = 0; y < selection_map->Bounds().Height(); y++) { - for (int32 x = 0; x <= selection_map->Bounds().Width(); x++) { + for (int32 y = 0; y < scale_x_bitmap->Bounds().Height(); y++) { + for (int32 x = 0; x <= scale_x_bitmap->Bounds().Width(); x++) { // Just copy it straight *(target_bits + x + y * target_bpr) = *(source_bits + x + y * source_bpr); } @@ -502,15 +507,15 @@ ScaleManipulator::ManipulateSelectionMap(ManipulatorSettings* set) target_bpr = final_bitmap->BytesPerRow(); final_bounds.top = settings->top; - final_bounds.bottom = settings->bottom; + final_bounds.bottom = min_c(settings->bottom, final_bitmap->Bounds().bottom); final_bounds.left = settings->left; - final_bounds.right = settings->right; + final_bounds.right = min_c(settings->right, final_bitmap->Bounds().right); if (source_bits != NULL) { for (int32 y = final_bounds.top; y <= final_bounds.bottom; y++) { int32 src_y = y - final_bounds.top; - if (src_y >= source_bounds.bottom) + if (src_y > source_bounds.bottom) break; if (y < 0) @@ -518,7 +523,7 @@ ScaleManipulator::ManipulateSelectionMap(ManipulatorSettings* set) for (int32 x = final_bounds.left; x <= final_bounds.right; x++) { int32 src_x = x - final_bounds.left; - if (src_x >= target_bpr || src_x >= source_bpr) + if (src_x > source_bpr) break; if (x < 0) continue; @@ -529,6 +534,8 @@ ScaleManipulator::ManipulateSelectionMap(ManipulatorSettings* set) } } + delete selection_map; + return final_bitmap; } @@ -548,11 +555,13 @@ ScaleManipulator::PreviewBitmap(bool, BRegion* region) white.bytes[2] = 0xFF; white.bytes[3] = 0x00; + preview_bitmap->Lock(); // Here do a DDA-scaling from copy_of_the_preview_bitmap to preview_bitmap. uint32 width = preview_bitmap->Bounds().IntegerWidth(); uint32 height = preview_bitmap->Bounds().IntegerHeight(); uint32 source_width = copy_of_the_preview_bitmap->Bounds().IntegerWidth(); uint32 source_height = copy_of_the_preview_bitmap->Bounds().IntegerHeight(); + preview_bitmap->Unlock(); if (width == 0 || height == 0) return 0; @@ -568,6 +577,15 @@ ScaleManipulator::PreviewBitmap(bool, BRegion* region) float width_coeff = old_width / new_width; float height_coeff = old_height / new_height; + BRect selection_bounds; + if (selection != NULL) { + selection_bounds = selection->GetBoundingRect(); + selection_bounds = selection_bounds & copy_of_the_preview_bitmap->Bounds(); + } + + if (orig_selection_map != NULL) + selection->ReplaceSelection(orig_selection_map); + if (selection == NULL || selection->IsEmpty() == true) { int32 preview_width = width; int32 preview_height = height; @@ -618,14 +636,13 @@ ScaleManipulator::PreviewBitmap(bool, BRegion* region) if (reject_mouse_input == true) return 1; - BRect selection_bounds = selection->GetBoundingRect(); - selection_bounds = selection_bounds & copy_of_the_preview_bitmap->Bounds(); + BRect orig_selection_bounds = selection->GetBoundingRect(); + int32 sel_top = (int32)selection_bounds.top; int32 sel_bottom = (int32)selection_bounds.bottom; int32 sel_left = (int32)selection_bounds.left; int32 sel_right = (int32)selection_bounds.right; - selection->ReplaceSelection(orig_selection_map); if (transform_selection_only == false) { for (int32 y = sel_top; y <= sel_bottom; ++y) { for (int32 x = sel_left; x <= sel_right; ++x) { @@ -637,61 +654,49 @@ ScaleManipulator::PreviewBitmap(bool, BRegion* region) } } } - selection_bounds = selection->GetBoundingRect(); - - selection->ScaleTo(selection_bounds.LeftTop(), new_x, new_y); - selection->Recalculate(); + BBitmap* selmap = PreviewSelectionMap(width_coeff, height_coeff); //settings); + selection->ReplaceSelection(selmap); selection_bounds = selection->GetBoundingRect(); + delete selmap; - if (settings->left != original_left || settings->top != original_top) { - - selection->Translate(settings->left - original_left, settings->top - original_top); - selection->Recalculate(); - selection_bounds = selection->GetBoundingRect(); - } - + copy_of_the_preview_bitmap->Lock(); selection_bounds = selection_bounds & copy_of_the_preview_bitmap->Bounds(); + copy_of_the_preview_bitmap->Unlock(); if (transform_selection_only == false) { if (selection_bounds.IsValid() == false || selection_bounds.Width() <= 1 || selection_bounds.Height() <= 1) { selection->ReplaceSelection(orig_selection_map); - selection->Translate(previous_left, previous_top); - selection->Recalculate(); selection_bounds = selection->GetBoundingRect(); - selection->ScaleTo(selection_bounds.LeftTop(), previous_right - previous_left, - previous_bottom - previous_top); - selection->Recalculate(); reject_mouse_input = true; return 1; } - sel_top = (int32)selection_bounds.top; - sel_bottom = (int32)selection_bounds.bottom; - sel_left = (int32)selection_bounds.left; - sel_right = (int32)selection_bounds.right; - if (settings->left < 0) - sel_left = settings->left; - if (settings->top < 0) - sel_top = settings->top; - - for (int32 y = sel_top; y <= sel_bottom; y++) { - int32 source_y = (int32)floor((y - sel_top) * height_coeff) + original_top; - int32 y_times_bpr = y * bpr; - int32 source_y_times_bpr = source_y * bpr; - for (int32 x = sel_left; x <= sel_right; x++) { - if (selection->ContainsPoint(x, y)) { - int32 source_x - = (int32)floor((x - sel_left) * width_coeff) + original_left; - if (source_x > width || source_y > height) { - *(target_bits + x + y_times_bpr) = white.word; - } else { - *(target_bits + x + y_times_bpr) - = src_over_fixed(*(target_bits + x + y_times_bpr), - *(source_bits + source_x + source_y_times_bpr)); + sel_top = (int32)settings->top; + sel_bottom = min_c((int32)selection_bounds.bottom, preview_bitmap->Bounds().bottom); + sel_left = (int32)settings->left; + sel_right = min_c((int32)selection_bounds.right, preview_bitmap->Bounds().right); + + if (sel_right > 0 && sel_bottom > 0 + && sel_left < preview_bitmap->Bounds().right + && sel_top < preview_bitmap->Bounds().bottom) { + for (int32 y = sel_top; y <= sel_bottom; y++) { + int32 source_y = (int32)floor((y - sel_top) * height_coeff) + original_top; + int32 y_times_bpr = y * bpr; + int32 source_y_times_bpr = source_y * bpr; + for (int32 x = sel_left; x <= sel_right; x++) { + if (selection->ContainsPoint(x, y)) { + int32 source_x + = (int32)floor((x - sel_left) * width_coeff) + original_left; + if (source_x > width || source_y > height || source_x < 0 || source_y < 0) { + *(target_bits + x + y_times_bpr) = white.word; + } else { + *(target_bits + x + y_times_bpr) + = *(source_bits + source_x + source_y_times_bpr); + } } } } @@ -705,6 +710,68 @@ ScaleManipulator::PreviewBitmap(bool, BRegion* region) } +BBitmap* +ScaleManipulator::PreviewSelectionMap(float width_coeff, float height_coeff) +{ + BBitmap* current_selection_map = selection->ReturnSelectionMap(); + + BRect selection_frame(settings->left, settings->top, settings->right, settings->bottom); + int32 width = selection_frame.IntegerWidth(); + int32 height = selection_frame.IntegerHeight(); + + BRect selection_map_frame = BRect(preview_bitmap->Bounds()); + selection_map_frame.right = max_c(selection_map_frame.right, width); + selection_map_frame.bottom = max_c(selection_map_frame.bottom, height); + + BBitmap* selection_map = new BBitmap(selection_map_frame, B_GRAY8); + + uint8* source_bits = (uint8*)current_selection_map->Bits(); + uint8* target_bits = (uint8*)selection_map->Bits(); + int32 bpr = selection_map->BytesPerRow(); + int32 source_bpr = current_selection_map->BytesPerRow(); + + for (int32 y = 0; y <= selection_map->Bounds().IntegerHeight(); y++) + for (int32 x = 0; x <= selection_map->Bounds().IntegerWidth(); x++) + *(target_bits + x + y * bpr) = 0; + + int32 sel_top = (int32)settings->top; + int32 sel_bottom = min_c((int32)selection_frame.bottom, preview_bitmap->Bounds().bottom); + int32 sel_left = (int32)settings->left; + int32 sel_right = min_c((int32)selection_frame.right, preview_bitmap->Bounds().right); + + for (int32 y = sel_top; y <= sel_bottom; y++) { + int32 source_y = (int32)floor((y - sel_top) * height_coeff) + original_top; + int32 y_times_bpr = y * bpr; + int32 source_y_times_bpr = source_y * source_bpr; + + if (y < 0) + continue; + + if (y > preview_bitmap->Bounds().bottom) + break; + + for (int32 x = sel_left; x <= sel_right; x++) { + if (x < 0) + continue; + + if (x > preview_bitmap->Bounds().right) + break; + + int32 source_x + = (int32)floor((x - sel_left) * width_coeff) + original_left; + if (source_x > 0 && source_y > 0 + && source_x < current_selection_map->Bounds().right + && source_y < current_selection_map->Bounds().bottom) { + *(target_bits + x + y_times_bpr) + = *(source_bits + source_x + source_y_times_bpr); + } + } + } + + return selection_map; +} + + void ScaleManipulator::MouseDown(BPoint point, uint32 buttons, BView* image_view, bool first_click) { diff --git a/artpaint/viewmanipulators/ScaleManipulator.h b/artpaint/viewmanipulators/ScaleManipulator.h index 82a23b21..cf1fd616 100644 --- a/artpaint/viewmanipulators/ScaleManipulator.h +++ b/artpaint/viewmanipulators/ScaleManipulator.h @@ -110,7 +110,7 @@ class ScaleManipulator : public WindowGUIManipulator { BBitmap* ManipulateBitmap(ManipulatorSettings*, BBitmap *original, BStatusBar*); - int32 PreviewBitmap(bool, BRegion* =NULL); + int32 PreviewBitmap(bool, BRegion* = NULL); void MouseDown(BPoint, uint32, BView*, bool); @@ -135,6 +135,7 @@ class ScaleManipulator : public WindowGUIManipulator { void SetInterpolationMethod(interpolation_type newMethod) { method = newMethod; } void UpdateSettings(); BBitmap* ManipulateSelectionMap(ManipulatorSettings*); + BBitmap* PreviewSelectionMap(float width_coeff, float height_coeff); }; diff --git a/artpaint/viewmanipulators/TranslationManipulator.cpp b/artpaint/viewmanipulators/TranslationManipulator.cpp index 34070424..79004545 100644 --- a/artpaint/viewmanipulators/TranslationManipulator.cpp +++ b/artpaint/viewmanipulators/TranslationManipulator.cpp @@ -154,7 +154,7 @@ TranslationManipulator::ManipulateBitmap( // with the same values int32 x_translation_local = ((int32)new_settings->x_translation); int32 y_translation_local = ((int32)new_settings->y_translation); - if (selection->IsEmpty()) { + if (selection == NULL || selection->IsEmpty()) { // First clear the target bitmap. Here the clearing of the whole bitmap is not usually // necessary. Actually this loop combined with the next should only set each pixel in the // bitmap exactly once. @@ -183,6 +183,7 @@ TranslationManipulator::ManipulateBitmap( *(target_bits + x + y * target_bpr) = *(source_bits + x + y * source_bpr); } + selection->ReplaceSelection(orig_selection_map); // Then clear the selection BRect selection_bounds = selection->GetBoundingRect(); int32 left = (int32)selection_bounds.left; @@ -196,8 +197,10 @@ TranslationManipulator::ManipulateBitmap( } } + BBitmap* selmap = ManipulateSelectionMap(settings); + selection->ReplaceSelection(selmap); + selection_bounds = selection->GetBoundingRect(); - selection_bounds.OffsetBy(settings->x_translation, settings->y_translation); selection_bounds = selection_bounds & original->Bounds() & new_bitmap->Bounds(); left = (int32)selection_bounds.left; right = (int32)selection_bounds.right; @@ -207,7 +210,7 @@ TranslationManipulator::ManipulateBitmap( for (int32 x = left; x <= right; x++) { int32 new_x = (int32)(x - new_settings->x_translation); int32 new_y = (int32)(y - new_settings->y_translation); - if (selection->ContainsPoint(new_x, new_y)) { + if (selection->ContainsPoint(x, y)) { *(target_bits + x + y * target_bpr) = src_over_fixed(*(target_bits + x + y * target_bpr), *(source_bits + new_x + new_y * source_bpr)); @@ -239,7 +242,7 @@ TranslationManipulator::ManipulateSelectionMap(ManipulatorSettings* set) orig_selection_map->Unlock(); } - BBitmap* selection_map = selection->ReturnSelectionMap(); + BBitmap* selection_map = new BBitmap(selection->ReturnSelectionMap()); BBitmap* new_bitmap; new_bitmap = new BBitmap(bitmap_frame, B_GRAY8); @@ -344,6 +347,10 @@ TranslationManipulator::PreviewBitmap(bool full_quality, BRegion* updated_region * last_calculated_resolution; int32 y_translation_local = ((int32)settings->y_translation) / last_calculated_resolution * last_calculated_resolution; + + if (orig_selection_map != NULL) + selection->ReplaceSelection(orig_selection_map); + if (selection == NULL || selection->IsEmpty() == true) { // First clear the target bitmap. BRegion to_be_cleared; @@ -393,13 +400,14 @@ TranslationManipulator::PreviewBitmap(bool full_quality, BRegion* updated_region updated_region->Set(uncleared_rect); updated_region->Include(&to_be_cleared); } else { - selection->Translate(x_translation_local - previous_x_translation, - y_translation_local - previous_y_translation); + BRect orig_selection_bounds = selection->GetBoundingRect(); + + BBitmap* selmap = ManipulateSelectionMap(settings); + selection->ReplaceSelection(selmap); BRegion to_be_cleared; to_be_cleared.Set(uncleared_rect); uncleared_rect = selection->GetBoundingRect(); - uncleared_rect.OffsetBy(x_translation_local, y_translation_local); uncleared_rect.InsetBy(-10, -10); uncleared_rect = uncleared_rect & preview_bitmap->Bounds(); @@ -425,7 +433,7 @@ TranslationManipulator::PreviewBitmap(bool full_quality, BRegion* updated_region } // Then do the selection - BRect selection_bounds = selection->GetBoundingRect(); + BRect selection_bounds(orig_selection_bounds); selection_bounds.left = ceil(selection_bounds.left / last_calculated_resolution) * last_calculated_resolution; selection_bounds.top = ceil(selection_bounds.top / last_calculated_resolution) @@ -434,15 +442,11 @@ TranslationManipulator::PreviewBitmap(bool full_quality, BRegion* updated_region int32 right = (int32)selection_bounds.right; int32 top = (int32)selection_bounds.top; int32 bottom = (int32)selection_bounds.bottom; - for (int32 y = top; y <= bottom; y += last_calculated_resolution) { - for (int32 x = left; x <= right; x += last_calculated_resolution) { - if (selection->ContainsPoint(x, y)) - *(target_bits + x + y * target_bpr) = background.word; - } - } + for (int32 y = top; y <= bottom; y += last_calculated_resolution) + for (int32 x = left; x <= right; x += last_calculated_resolution) + *(target_bits + x + y * target_bpr) = background.word; selection_bounds = selection->GetBoundingRect(); - selection_bounds.OffsetBy(settings->x_translation, settings->y_translation); selection_bounds = selection_bounds & preview_bitmap->Bounds(); selection_bounds.left = ceil(selection_bounds.left / last_calculated_resolution) * last_calculated_resolution; @@ -452,14 +456,19 @@ TranslationManipulator::PreviewBitmap(bool full_quality, BRegion* updated_region right = (int32)selection_bounds.right; top = (int32)selection_bounds.top; bottom = (int32)selection_bounds.bottom; - for (int32 y = top; y <= bottom; y += last_calculated_resolution) { - for (int32 x = left; x <= right; x += last_calculated_resolution) { - int32 new_x = (int32)(x - settings->x_translation); - int32 new_y = (int32)(y - settings->y_translation); - if (selection->ContainsPoint(new_x, new_y)) - *(target_bits + x + y * target_bpr) - = src_over_fixed(*(target_bits + x + y * target_bpr), - *(source_bits + new_x + new_y * source_bpr)); + + if (selection_bounds != preview_bitmap->Bounds() || + (orig_selection_bounds == preview_bitmap->Bounds() + && (settings->x_translation >= 0 && settings->y_translation >= 0))) { + for (int32 y = top; y <= bottom; y += last_calculated_resolution) { + for (int32 x = left; x <= right; x += last_calculated_resolution) { + int32 new_x = (int32)(x - settings->x_translation); + int32 new_y = (int32)(y - settings->y_translation); + if (selection->ContainsPoint(x, y) && new_x >= 0 && new_y >= 0) + *(target_bits + x + y * target_bpr) + = src_over_fixed(*(target_bits + x + y * target_bpr), + *(source_bits + new_x + new_y * source_bpr)); + } } } } @@ -484,7 +493,6 @@ TranslationManipulator::ReturnSettings() void TranslationManipulator::Reset() { - selection->Translate(int32(-settings->x_translation), int32(-settings->y_translation)); settings->x_translation = 0; settings->y_translation = 0; previous_x_translation = 0; @@ -500,6 +508,9 @@ TranslationManipulator::Reset() uncleared_rect = preview_bitmap->Bounds(); } + + if (orig_selection_map != NULL && selection != NULL) + selection->ReplaceSelection(orig_selection_map); } diff --git a/artwork/test images/Walter_the_OS.png b/artwork/test images/Walter_the_OS.png index b63e2533..4c9eeaac 100644 Binary files a/artwork/test images/Walter_the_OS.png and b/artwork/test images/Walter_the_OS.png differ