Hej,
Chciałbym przedstawić pewien problem, z którym się obecnie borykam. Chodzi o "przycięcie obrazka" (Crop) do wymiaru wskazanego przez użytkownika.
Moje rozwiązanie jest maksymalnie proste. Program wyświetla obraz w TImage. Do zaznaczania ramki zaznaczenia używam TShape (choć jeśli ktoś zna dedykowany komponent - chętnie sprawdzę). Całość bazuje na obsłudze zdarzeń TImage. Obrazek wczytuje ze schowka (ale to nie jest ważne skąd).
MouseDown
MouseMove
MouseUp
Zasadniczo to działa, ale jest kilka problemów (trudno je opisać).
-
Użytkownik wciskając mysz zaznacza punkt początkowy ramki i przesuwając go "rysuje" ramkę - kursor (koniec strzałki) jednak jest przesunięty względem tego punktu o pewną ilość pikseli (u mnie 10px na szerokości i 5px na wysokości). Dlaczego?
-
Jeśli okno z obrazkiem jest mniejsze (większe) od samego obrazka to zaznaczając ramkę w TImage nie mamy rzeczywistych punktów z obrazka (kopiujemy inny fragment niż chcemy). Jeśli obrazek jest mniejszy niż obszar TImage to przeliczam to jak w poniższym kodzie. Nie wiem jednak co, jeśli obrazek jest większy od obszaru TImage (ten jest skalowany). Jak to obliczyć?
Ogólnie, czy ktoś z Was zajmował się takim przypadkiem? Mamy obraz w TImage i chcemy, żeby użytkownik zaznaczając myszą wybrał fragment obrazu (przyciął go) i przypisał do tego TImage. Chętnie dowiem się jak to zrobić dobrze, prosto i efektywnie.
Przykładowy kod - BARDZo niedoskonały i prymitywny.
type
Img_ImagePreview: TImage;
CropFrame: TShape;
private
{ Private declarations }
CropMouseIsDown: Boolean;
pStartPoint: TPoint;
pStopPoint: TPoint;
public
{ Public declarations }
end;
...
procedure TImagePreview_Frm.FormShow(Sender: TObject);
var
BMP : TBitmap;
begin
BMP := TBitmap.Create;
try
BMP.Assign(Clipboard);
Img_ImagePreview.Align := alClient;
Img_ImagePreview.Visible := True;
Img_ImagePreview.IncrementalDisplay := True;
Img_ImagePreview.Proportional := True;
Img_ImagePreview.Stretch := False;
Img_ImagePreview.Transparent := True;
Img_ImagePreview.AutoSize := True;
Img_ImagePreview.Center := True;
Img_ImagePreview.Picture := nil;
Img_ImagePreview.Picture.Assign(BMP);
Img_ImagePreview.Refresh;
finally
BMP.Free;
end;
end;
procedure Img_ImagePreviewMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if (Button = mbLeft) then
begin
pStartPoint.X := X;
pStartPoint.Y := Y;
CropFrame.Shape := stRectangle;
CropFrame.Brush.Color := clWhite;
CropFrame.Brush.Style := bsClear;
CropFrame.Pen.Mode := pmCopy;
CropFrame.Pen.Color := clRed;
CropFrame.Pen.Style := psDashDot;
CropFrame.Pen.Width := 1;
CropFrame.Width := 0;
CropFrame.Height := 0;
CropFrame.Left := pStartPoint.X + 10; // !?
CropFrame.Top := pStartPoint.Y + 5; // !?
CropFrame.BringToFront;
CropFrame.Visible := True;
CropMouseIsDown := True;
end;
end;
procedure Img_ImagePreviewMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
if (CropMouseIsDown = True) then
begin
pStopPoint.X := X;
pStopPoint.Y := Y;
CropFrame.Width := pStopPoint.X - CropFrame.Left;
CropFrame.Height := pStopPoint.Y - CropFrame.Top;
end;
end;
procedure Img_ImagePreviewMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
BMP : TBitmap;
BMP_Source : TBitmap;
Img_W : Integer;
Img_H : Integer;
Real_W : Integer;
Real_H : Integer;
Diff_W : Integer;
Diff_H : Integer;
begin
if (CropMouseIsDown = True) then
begin
CropMouseIsDown := False;
CropFrame.Visible := False;
BMP_Source := TBitmap.Create;
BMP := TBitmap.Create;
try
BMP_Source.Assign(Img_ImagePreview.Picture.Bitmap);
Real_W := BMP_Source.Width;
Real_H := BMP_Source.Height;
Img_W := Img_ImagePreview.Width;
Img_H := Img_ImagePreview.Height;
Diff_W := Round((Img_W - Real_W) div 2);
Diff_H := Round((Img_H - Real_H) div 2);
BMP.SetSize(Abs(pStopPoint.X - pStartPoint.X), Abs(pStopPoint.Y - pStartPoint.Y));
BMP.Canvas.CopyRect(Rect(0,0, BMP.Width, BMP.Height),
BMP_Source.Canvas,
Rect( pStartPoint.X-Diff_W, pStartPoint.Y-Diff_H, (pStopPoint.X-Diff_W)-10, (pStopPoint.Y-Diff_H)-5)
);
// Copy to Clipboard (Cropped Image)
Clipboard.Assign(BMP);
finally
BMP_Source.Free;
BMP.Free;
end;
Close;
end;
end;