(* ImageEn Build 7.0.0.06.2637 @ 7-4-17 14:58:42.679 *) (* Copyright (c) 1998-2017 by Carlotta Calandra. All rights reserved. Copyright (c) 2011-2017 by Xequte Software. This software comes without express or implied warranty. In no case shall the author be liable for any damage or unwanted behavior of any computer hardware and/or software. Author grants you the right to include the component in your application, whether COMMERCIAL, SHAREWARE, or FREEWARE. ImageEn, IEvolution and ImageEn ActiveX may not be included in any commercial, shareware or freeware libraries or components. www.ImageEn.com *) (* File version 1007 Doc revision 1001 *) unit histogrambox; {$R-} {$Q-} {$I ie.inc} interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, ImageEnProc, hyiedefs, iexBitmaps; type {!! THistogramKind Declaration } THistogramKind = set of (hkRed, hkGreen, hkBlue, hkGray, hkHue); {!!} {!! THistogramLabels Declaration } THistogramLabels = set of (hlVertical, hlHorizontal); {!!} {!! THistogramStyle Declaration } THistogramStyle = (hsBars, hsLines, hsFilledLines); {!!} {!! THistogramMouseInteract Declaration THistogramMouseInteract = (mhNone, mhSelectValue, mhSelectRange); Description What action does the mouse perform: Value Description mhNone Mouse has no effect mhSelectValue Clicking/moving the mouse selects a single value on the histogram mhSelectRange Clicking/moving the mouse selects a range of values on the histogram
!!} THistogramMouseInteract = (mhNone, mhSelectValue, mhSelectRange); {!! THistogramBox Description THistogramBox can be attached to a component from which it gets information to compute and display the color channels histogram. Demo Demos\ImageAnalysis\Histogram\Histogram.dpr Example // Setup with HistogramBox1 do begin Background := clBtnFace; // Change background color Font.Color := clDarkGray; // Set font and chart color to dark gray MouseInteract := mhSelectValue; // Allow selection of a single value HistogramKind := [ hkRed, hkGreen, hkBlue ]; // Histogram to show RGB levels HistogramStyle := hsFilledLines; // Show a filled line graph instead of bars end; // Display histogram of colors in current image HistogramBox1.UpdateFromBitmap( ImageEnView1.IEBitmap ); Methods and Properties Events !!} {$ifdef IEHASPLATFORMATTRIBUTE} [ComponentPlatformsAttribute(pidWin32 or pidWin64)] {$endif} THistogramBox = class(TCustomControl) private { Private declarations } fBackground: TColor; fAIEP: TImageEnProc; // attached TImageEnProc fHistKind: THistogramKind; fLabels: THistogramLabels; fCompBar: boolean; fHistogramStyle: THistogramStyle; fHistogramAbsXPos: integer; fGrayColor: TColor; fMouseMinX : Integer; fMouseMaxX : Integer; fMouseMinDown : Boolean; fMouseMaxDown : Boolean; fMouseInteract: THistogramMouseInteract; fSelectionColor : TColor; fOnSelectionChanged: TNotifyEvent; fOnSelectionChanging: TNotifyEvent; fScale: THistogramScale; procedure SetBackground(bk: TColor); procedure SetLabels(v: THistogramLabels); procedure SetCompBar(v: boolean); procedure SetHistogramStyle(v: THistogramStyle); procedure SetHistogramKind(v: THistogramKind); procedure SetAIEP(v: TImageEnProc); function GetHistogramKind: THistogramKind; function GetLabels: THistogramLabels; procedure SetMouseInteract(v: THistogramMouseInteract); procedure SetSelectionColor(const Value: TColor); function GetMaxSelected: Integer; function GetMinSelected: Integer; procedure SetMaxSelected(const Value: Integer); procedure SetMinSelected(const Value: Integer); procedure SetScale(Value: THistogramScale); protected { Protected declarations } procedure WMSize(var Message: TWMSize); message WM_SIZE; procedure WMEraseBkgnd(var Message: TMessage); message WM_ERASEBKGND; procedure MouseMove(Shift: TShiftState; X, Y: Integer); override; procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; procedure Notification(AComponent: TComponent; Operation: TOperation); override; public { Public declarations } {!! THistogramBox.Bitmap Declaration property Bitmap: TBitmap; Description The bitmap of the current histogram Example uses iexHelperFunctions; // Print the current histogram Printer.BeginDoc; HistogramBox1.Bitmap.PrintImage(Printer.Canvas, 0, 0, 0, 0, ievpCenter, iehpCenter, iesFitToPage); Printer.EndDoc; !!} Bitmap: TBitmap; procedure Paint; override; constructor Create(Owner: TComponent); override; destructor Destroy; override; procedure Update(); override; procedure UpdateFromBitmap(Bitmap: TIEBitmap); procedure UpdateFromHistogram(Histogram: TIEHistogram); procedure Clear(); {!! THistogramBox.HistogramAbsXPos Declaration property HistogramAbsXPos: integer; Description Returns the left X coordinate where the histogram will be painted inside the component client area. Read-only !!} property HistogramAbsXPos: integer read fHistogramAbsXPos; property SelectionColor : TColor read fSelectionColor write SetSelectionColor; property MinSelected : Integer read GetMinSelected write SetMinSelected; property MaxSelected : Integer read GetMaxSelected write SetMaxSelected; property Scale: THistogramScale read fScale write SetScale; published { Published declarations } property AttachedImageEnProc: TImageEnProc read fAIEP write SetAIEP; property Background: TColor read fBackground write SetBackground default clWhite; property HistogramKind: THistogramKind read GetHistogramKind write SetHistogramKind default [hkGray]; property Labels: THistogramLabels read GetLabels write SetLabels default [hlVertical, hlHorizontal]; property CompBar: boolean read fCompBar write SetCompBar default true; property HistogramStyle: THistogramStyle read fHistogramStyle write SetHistogramStyle default hsBars; {!! THistogramBox.GrayColor Declaration property GrayColor: Tcolor; Description Specifies the color of the line/bar for a gray histogram (i.e. when is [hkGray]). !!} property GrayColor: TColor read fGrayColor write fGrayColor default clBlack; {!! THistogramBox.OnSelectionChanged Declaration property OnSelectionChanged: TNotifyEvent; Description If has been enabled then this event will occur after the user has modified the selection. Note: Unlike this event only fires once per change (on mouse up) !!} property OnSelectionChanged: TNotifyEvent read fOnSelectionChanged write fOnSelectionChanged; {!! THistogramBox.OnSelectionChanging Declaration property OnSelectionChanging: TNotifyEvent; Description If has been enabled then this event will occur as the user modifies the selection. Note: Unlike this event will fire multiple times during a selection change (as user drags mouse) !!} property OnSelectionChanging: TNotifyEvent read fOnSelectionChanging write fOnSelectionChanging; property MouseInteract: THistogramMouseInteract read fMouseInteract write SetMouseInteract default mhNone; property Align; property DragCursor; property DragMode; property Enabled; property ParentShowHint; property PopupMenu; property ShowHint; property Visible; property OnClick; property OnDblClick; property OnDragDrop; property OnDragOver; property OnEndDrag; property OnMouseDown; property OnMouseMove; property OnMouseUp; property OnStartDrag; property Font; property Width default 256; property Height default 105; property OnContextPopup; end; implementation uses iegdiplus, hyieutils, imageenview; {$R-} ///////////////////////////////////////////////////////////////////////////////////// constructor THistogramBox.Create(Owner: TComponent); begin inherited Create(Owner); IEGDIPLoadLibrary(); ControlStyle := ControlStyle + [csOpaque, csAcceptsControls]; fBackground := clWhite; fHistKind := [hkGray]; fLabels := [hlVertical, hlHorizontal]; fCompBar := true; fHistogramStyle := hsBars; fGrayColor := clBlack; Height := 105; Width := 256; bitmap := TBitmap.create; bitmap.PixelFormat := pf24bit; bitmap.Width := 1; bitmap.Height := 1; fAIEP := nil; fMouseInteract := mhNone; fMouseMinX := 0; fMouseMaxX := 0; fMouseMinDown := False; fMouseMaxDown := False; fSelectionColor := clRed; fScale := iehsLinear; Update; end; ///////////////////////////////////////////////////////////////////////////////////// destructor THistogramBox.Destroy; begin FreeAndNil(bitmap); IEGDIPUnLoadLibrary(); inherited; end; procedure THistogramBox.Paint; begin canvas.Draw(0, 0, bitmap); if ( fMouseInteract = mhSelectValue ) and ( fMouseMinX >= fHistogramAbsXPos ) then begin Canvas.Pen.Color := fSelectionColor; Canvas.MoveTo( fMouseMinX, 0 ); Canvas.LineTo( fMouseMinX, Height ); end; if ( fMouseInteract = mhSelectRange ) and ( fMouseMinX >= fHistogramAbsXPos ) then begin if fMouseMinX > fMouseMaxX then begin IESwap( fMouseMinX, fMouseMaxX ); IESwap( fMouseMinDown, fMouseMaxDown ); end; Canvas.Brush.Color := fSelectionColor; Canvas.FrameRect( Rect( fMouseMinX, 0 , fMouseMaxX + 1, Height )); end; end; procedure THistogramBox.WMEraseBkgnd(var Message: TMessage); begin Message.Result := 0; end; procedure THistogramBox.WMSize(var Message: TWMSize); begin inherited; bitmap.Width := message.Width; bitmap.Height := message.Height; Update; end; {!! THistogramBox.Background Declaration property Background: TColor; Description Specifies the background color. Note: To change the color of the font and grid use Font.Color !!} procedure THistogramBox.SetBackground(bk: TColor); begin fBackground := bk; update; end; procedure THistogramBox.MouseMove(Shift: TShiftState; X, Y: Integer); const Cursor_Margin = 3; begin inherited; if fMouseInteract in [ mhSelectValue, mhSelectRange ] then begin if fMouseMinDown then fMouseMinX := ilimit( X, fHistogramAbsXPos, Width - 1 ); if fMouseMaxDown then fMouseMaxX := ilimit( X, fHistogramAbsXPos, Width - 1 ); if fMouseMinDown or fMouseMaxDown then begin Invalidate; if assigned( fOnSelectionChanging ) then fOnSelectionChanging( Self); end; if ( X >= fHistogramAbsXPos - Cursor_Margin div 2 ) and (( Abs( X - fMouseMinX ) <= Cursor_Margin ) OR ( Abs( X - fMouseMaxX ) <= Cursor_Margin )) then Cursor := crHSplit else Cursor := crDefault; end; end; procedure THistogramBox.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin inherited; if ( Button = mbLeft ) and ( fMouseInteract = mhSelectValue ) and ( X >= fHistogramAbsXPos ) then begin fMouseMinDown := True; fMouseMaxDown := False; fMouseMinX := X; Invalidate; end else if ( Button = mbLeft ) and ( fMouseInteract = mhSelectRange ) and ( X >= fHistogramAbsXPos ) then begin fMouseMinDown := False; fMouseMaxDown := False; // Over Min or Max item? if Abs( X - fMouseMinX ) < Abs( X - fMouseMaxX ) then begin fMouseMinX := X; if fMouseMaxX < fHistogramAbsXPos then fMouseMaxX := fHistogramAbsXPos; fMouseMinDown := True; end else begin if fMouseMinX < fHistogramAbsXPos then fMouseMinX := fHistogramAbsXPos; fMouseMaxX := X; fMouseMaxDown := True; end; Invalidate; end; end; procedure THistogramBox.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin inherited; if fMouseMinDown or fMouseMaxDown then begin fMouseMinDown := False; fMouseMaxDown := False; Invalidate; // Ensure it is called even if user clicks once in a new position if assigned( fOnSelectionChanging ) then fOnSelectionChanging( Self); if assigned( fOnSelectionChanged ) then fOnSelectionChanged( Self); end; end; procedure THistogramBox.SetLabels(v: THistogramLabels); begin if v <> fLabels then begin fLabels := v; Update; end; end; {!! THistogramBox.MouseInteract Declaration property MouseInteract: ; Description Determines what effect use of the mouse has on the component Example // Allow the user to select a value on the histogram HistogramBox1.MouseInteract := mhSelectValue; See Also - - - !!} procedure THistogramBox.SetMouseInteract(v: THistogramMouseInteract); begin if v <> fMouseInteract then begin fMouseInteract := v; Invalidate; end; end; {!! THistogramBox.SelectionColor Declaration property SelectionColor: TColor; Description Specifies the color of the selection line/box if you have enabled mouse interaction. See Also - !!} procedure THistogramBox.SetSelectionColor(const Value: TColor); begin fSelectionColor := Value; Invalidate; end; {!! THistogramBox.CompBar Declaration property CompBar: boolean; Description If True, a gradient bar is shown below the histogram graph. !!} procedure THistogramBox.SetCompBar(v: boolean); begin if v <> fCompBar then begin fCompBar := v; Update; end; end; {!! THistogramBox.HistogramStyle Declaration property HistogramStyle: ; Description Specifies the styling of the histogram: Solid bars, single lines or filled lines. Default: hsBars !!} procedure THistogramBox.SetHistogramStyle(v: THistogramStyle); begin if v <> fHistogramStyle then begin fHistogramStyle := v; Update; end; end; procedure THistogramBox.SetHistogramKind(v: THistogramKind); begin if v <> fHistKind then begin fHistKind := v; Update; end; end; function ConvHistKindToHistContent(histKind: THistogramKind): TIEHistogramContent; begin result := []; if hkRed in histKind then result := result + [iehcRed]; if hkGreen in histKind then result := result + [iehcGreen]; if hkBlue in histKind then result := result + [iehcBlue]; if hkGray in histKind then result := result + [iehcGray]; if hkHue in histKind then result := result + [iehcHue]; end; {!! THistogramBox.UpdateFromBitmap Declaration procedure UpdateFromBitmap(Bitmap: TIEBitmap); Description Updates the histogram from the specified bitmap. Example HistogramBox1.UpdateFromBitmap( ImageEnView1.IEBitmap ); !!} procedure THistogramBox.UpdateFromBitmap(Bitmap: TIEBitmap); var proc: TImageEnProc; Hist: TIEHistogram; begin proc := TImageEnProc.CreateFromBitmap(Bitmap); try Hist := proc.GetHistogram(ConvHistKindToHistContent(fHistKind)); UpdateFromHistogram(Hist); finally proc.Free(); end; end; {!! THistogramBox.Clear Declaration procedure Clear(); Description Reset the histogram to null values. Example HistogramBox1.Clear(); !!} procedure THistogramBox.Clear(); var i: integer; Hist: TIEHistogram; begin SetLength(Hist, 256); for i := 0 to 255 do begin Hist[i].r := 0; Hist[i].g := 0; Hist[i].b := 0; Hist[i].Gray := 0; Hist[i].Hue := 0; end; UpdateFromHistogram( Hist ); end; // rebuild histogram from current selection (needs AttachedImageEnProc) procedure THistogramBox.Update(); var i: integer; Hist: TIEHistogram; function GetRandom : integer; begin if I <= 128 then Result := I else Result := 256 - I; Result := Result + random(128); end; begin if (assigned(fAIEP) and assigned(fAIEP.AttachedIEBitmap)) or (csDesigning in ComponentState) then begin if csDesigning in ComponentState then begin SetLength(Hist, 256); for i := 0 to 255 do begin Hist[i].r := GetRandom; Hist[i].g := GetRandom; Hist[i].b := GetRandom; Hist[i].Gray := GetRandom; Hist[i].Hue := GetRandom; end; UpdateFromHistogram(Hist); end else if Assigned( fAIEP.AttachedImageEn ) and ( fAIEP.AttachedImageEn is TImageEnView ) and TImageEnView( fAIEP.AttachedImageEn ).IsEmpty2 then Clear() else begin Hist := fAIEP.GetHistogram(ConvHistKindToHistContent(fHistKind)); UpdateFromHistogram(Hist); end; end; end; {!! THistogramBox.UpdateFromHistogram Declaration procedure UpdateFromHistogram(Histogram: ); Description Updates content from the specified histogram. !!} procedure THistogramBox.UpdateFromHistogram(Histogram: TIEHistogram); const Horz_Text_Margin = 4; var MaxV: dword; q, w, e, dv: integer; dx, dy, x1: integer; xx: integer; sz: TSize; compdy: integer; px: pRGBROW; CVS: TIECanvas; histlen: integer; rgb: TRGB; Offset: Integer; function ScaleValue(Value: integer): integer; begin case fScale of iehsLinear, iehsLinearClipped: result := round(Value / MaxV * dy); iehsLogarithmic: result := round( ln(1 + Value) / ln(1 + MaxV) * dy ); else result := 0; end; end; function IEHistogramItem(R, G, B, Gray, Hue: DWORD): THistogramItem; begin result.R := R; result.G := G; result.B := B; result.Gray := Gray; result.Hue := Hue; end; function CountOutBins(): integer; var i: integer; begin result := 0; for i := 0 to histlen - 1 do begin if (hkRed in fHistKind) and (Histogram[i].r > MaxV) then inc(result) else if (hkGreen in fHistKind) and (Histogram[i].g > MaxV) then inc(result) else if (hkBlue in fHistKind) and (Histogram[i].b > MaxV) then inc(result) else if (hkGray in fHistKind) and (Histogram[i].Gray > MaxV) then inc(result) else if (hkHue in fHistKind) and (Histogram[i].Hue > MaxV) then inc(result); end; end; procedure CalcMax(); var i: integer; j: dword; hmax, htot, hcnt: THistogramItem; vmax, vtot, vcnt: dword; begin MaxV := 0; hmax := IEHistogramItem(0, 0, 0, 0, 0); htot := hmax; hcnt := hmax; for i := 0 to histlen - 1 do begin if hkRed in fHistKind then begin if Histogram[i].R > hmax.R then hmax.R := Histogram[i].R; if Histogram[i].R > 0 then inc(hcnt.R); inc(htot.R, Histogram[i].R); end; if hkGreen in fHistKind then begin if Histogram[i].G > hmax.G then hmax.G := Histogram[i].G; if Histogram[i].G > 0 then inc(hcnt.G); inc(htot.G, Histogram[i].G); end; if hkBlue in fHistKind then begin if Histogram[i].B > hmax.B then hmax.B := Histogram[i].B; if Histogram[i].B > 0 then inc(hcnt.B); inc(htot.B, Histogram[i].B); end; if hkGray in fHistKind then begin if Histogram[i].Gray > hmax.Gray then hmax.Gray := Histogram[i].Gray; if Histogram[i].Gray > 0 then inc(hcnt.Gray); inc(htot.Gray, Histogram[i].Gray); end; if hkHue in fHistKind then begin if Histogram[i].Hue > hmax.Hue then hmax.Hue := Histogram[i].Hue; if Histogram[i].Hue > 0 then inc(hcnt.Hue); inc(htot.Hue, Histogram[i].Hue); end; end; vmax := imax(hmax.R, imax(hmax.G, imax(hmax.B, imax(hmax.Gray, hmax.Hue)))); vcnt := imax(hcnt.R, imax(hcnt.G, imax(hcnt.B, imax(hcnt.Gray, hcnt.Hue)))); vtot := imax(htot.R, imax(htot.G, imax(htot.B, imax(htot.Gray, htot.Hue)))); if (fScale = iehsLinearClipped) and (vtot <> 0) then begin j := 3; repeat MaxV := imin(vmax, j * vtot div vcnt); inc(j); until CountOutBins() < 4; if (vmax - MaxV) / vtot < 0.05 then // ignore clip if difference is less than 5% MaxV := vmax; end else MaxV := vmax; end; begin Bitmap.Canvas.Brush.Color := fBackground; if Bitmap.Width = 1 then begin bitmap.Width := width; bitmap.Height := height; end; Bitmap.Canvas.FillRect(rect(0, 0, Bitmap.Width, Bitmap.Height)); CVS := TIECanvas.Create(Bitmap.Canvas, true, true); try CVS.Brush.Color := fBackground; CVS.Pen.Color := fBackground; CVS.Pen.Style := psSolid; histlen := length(Histogram); CalcMax(); if histlen > 0 then begin if ((GetParentForm(self) <> nil) or (ParentWindow <> 0)) and HandleAllocated then begin dx := ClientWidth; dy := ClientHeight; end else begin // client size still not available dx := Width; dy := Height; end; x1 := 0; compdy := trunc(abs(Font.Height) * 1.2); if fCompBar then dec(dy, compdy + 2); // LABELS if (hlVertical in fLabels) then begin // paint vertical axis with labels CVS.Font.Assign( Font ); sz := CVS.TextExtent( WideString(IEIntToFormattedStr( MaxV, 3 )) ); if MaxV div 2 < MaxV then CVS.TextOut(0, dy div 2 - sz.cy div 2, string(IEIntToFormattedStr( MaxV div 2, 3 )) ); CVS.TextOut(0, 0, string(IEIntToFormattedStr( MaxV, 3 )) ); CVS.Pen.Color := Font.Color; dec(dx, sz.cx + Horz_Text_Margin); inc(x1, sz.cx + Horz_Text_Margin); end; if (hlHorizontal in fLabels) then begin // paint horizontal axis with labels CVS.Font.Assign( Font ); sz := CVS.TextExtent(IntToStr(MaxV)); dv := histlen div 4; for q := 0 to 3 do CVS.TextOut(x1 + round(((q * dv) / histlen) * dx), dy - abs(Font.Height) - 1, IntToStr(q * dv)); q := CVS.TextWidth(IntToStr(histlen - 1)); CVS.TextOut(x1 + dx - q, dy - abs(Font.Height) - 1, IntToStr(histlen - 1)); dec(dy, sz.cy + 2); // axis CVS.MoveTo(x1 - 1, 0); CVS.LineTo(x1 - 1, dy); CVS.LineTo(x1 + dx, dy); end; // fHistogramAbsXPos := x1; // COMPBAR if fCompBar then begin for w := 0 to compdy - 1 do begin // row px := bitmap.ScanLine[bitmap.height - w - 1]; for q := 0 to dx - 1 do begin px^[x1 + q].r := 0; px^[x1 + q].g := 0; px^[x1 + q].b := 0; e := round(q / dx * 256); if (hkRed in fHistKind) or (hkGray in fHistKind) then px^[x1 + q].r := e; if (hkGreen in fHistKind) or (hkGray in fHistKind) then px^[x1 + q].g := e; if (hkBlue in fHistKind) or (hkGray in fHistKind) then px^[x1 + q].b := e; if fHistKind = [hkHue] then begin HSV2RGB(px^[x1 + q], trunc(e / histlen * 360), 99, 50); end; end; end; end; Offset := 0; if fHistogramStyle = hsFilledLines then Offset := -1; // paint histogram on Bitmap // hsBars and hsFilledLines if ( MaxV > 0 ) and (( fHistogramStyle = hsBars ) or ( fHistogramStyle = hsFilledLines )) then for xx := 0 to dx - 1 do begin q := trunc(xx / dx * histlen); if hkRed in fHistKind then begin if fHistogramStyle = hsFilledLines then CVS.Pen.Color := IEAverageColor( Background, clRed ) else CVS.Pen.Color := clRed; CVS.MoveTo(xx + x1, dy - 1); e := ScaleValue(Histogram[q].r); if (Histogram[q].r > 0) and (e = 0) then e := 1; CVS.LineTo(xx + x1, dy - 1 - e - Offset); end; if hkGreen in fHistKind then begin if fHistogramStyle = hsFilledLines then CVS.Pen.Color := IEAverageColor( Background, clGreen ) else CVS.Pen.Color := clGreen; CVS.MoveTo(xx + x1, dy - 1); e := ScaleValue(Histogram[q].g); if (Histogram[q].g > 0) and (e = 0) then e := 1; CVS.LineTo(xx + x1, dy - 1 - e - Offset); end; if hkBlue in fHistKind then begin if fHistogramStyle = hsFilledLines then CVS.Pen.Color := IEAverageColor( Background, clBlue ) else CVS.Pen.Color := clBlue; CVS.MoveTo(xx + x1, dy - 1); e := ScaleValue(Histogram[q].b); if (Histogram[q].b > 0) and (e = 0) then e := 1; CVS.LineTo(xx + x1, dy - 1 - e - Offset); end; if hkGray in fHistKind then begin if fHistogramStyle = hsFilledLines then CVS.Pen.Color := IEAverageColor( Background, fGrayColor ) else CVS.Pen.Color := fGrayColor; CVS.MoveTo(xx + x1, dy - 1); e := ScaleValue(Histogram[q].Gray); if (Histogram[q].Gray > 0) and (e = 0) then e := 1; CVS.LineTo(xx + x1, dy - 1 - e - Offset); end; if hkHue in fHistKind then begin HSV2RGB(rgb, trunc(q / histlen * 360), 99, 50); if fHistogramStyle = hsFilledLines then CVS.Pen.Color := IEAverageColor( Background, TRGB2TCOLOR(rgb) ) else CVS.Pen.Color := TRGB2TCOLOR(rgb); CVS.MoveTo(xx + x1, dy - 1); e := ScaleValue(Histogram[q].Hue); if (Histogram[q].Hue > 0) and (e = 0) then e := 1; CVS.LineTo(xx + x1, dy - 1 - e - Offset); end; end; // hsLines and hsFilledLines if ( MaxV > 0 ) and (( fHistogramStyle = hsLines ) or ( fHistogramStyle = hsFilledLines )) then begin if hkRed in fHistKind then begin CVS.Pen.Color := clRed; CVS.MoveTo(x1, dy - 1); for xx := 0 to dx - 1 do begin q := trunc(xx / dx * histlen); CVS.LineTo(xx + x1, dy - 1 - ScaleValue(Histogram[q].r) + 1); end; end; if hkGreen in fHistKind then begin CVS.Pen.Color := clGreen; CVS.MoveTo(x1, dy - 1); for xx := 0 to dx - 1 do begin q := trunc(xx / dx * histlen); CVS.LineTo(xx + x1, dy - 1 - ScaleValue(Histogram[q].g) + 1); end; end; if hkBlue in fHistKind then begin CVS.Pen.Color := clBlue; CVS.MoveTo(x1, dy - 1); for xx := 0 to dx - 1 do begin q := trunc(xx / dx * histlen); CVS.LineTo(xx + x1, dy - 1 - ScaleValue(Histogram[q].b) + 1); end; end; if hkGray in fHistKind then begin CVS.Pen.Color := fGrayColor; CVS.MoveTo(x1, dy - 1); for xx := 0 to dx - 1 do begin q := trunc(xx / dx * histlen); CVS.LineTo(xx + x1, dy - 1 - ScaleValue(Histogram[q].Gray) + 1); end; end; if hkHue in fHistKind then begin CVS.MoveTo(x1, dy - 1); for xx := 0 to dx - 1 do begin q := trunc(xx / dx * histlen); HSV2RGB(rgb, trunc(q / histlen * 360), 99, 50); CVS.Pen.Color := TRGB2TCOLOR(rgb); CVS.LineTo(xx + x1, dy - 1 - ScaleValue(Histogram[q].Hue) + 1); end; end; end; end; finally CVS.Free; end; invalidate; end; procedure THistogramBox.Notification(AComponent: TComponent; Operation: TOperation); begin inherited Notification(AComponent, Operation); if (AComponent = fAIEP) and (Operation = opRemove) then fAIEP := nil; end; {!! THistogramBox.AttachedImageEnProc Declaration property AttachedImageEnProc: ; Description Use this property to attach a THistogramBox to a TImageEnProc object. Example HistogramBox1.AttachedImageEnProc := ImageEnView1.Proc; HistogramBox1.Update; // now HistogramBox1 will display the histogram of an image attached to ImageEnProc1 !!} procedure THistogramBox.SetAIEP(v: TImageEnProc); begin fAIEP := v; if assigned(fAIEP) then fAIEP.FreeNotification(self) else Clear; end; {!! THistogramBox.HistogramKind Declaration property HistogramKind: ; Description Selects which channels are shown: Value Description hkRed Red channel hkGreen Green channel hkBlue Blue channel hkGray Gray-scale level hkHue Hue (of HSV values)
!!} function THistogramBox.GetHistogramKind: THistogramKind; begin result := fHistKind; end; {!! THistogramBox.Labels Declaration property Labels:
; Description Specifies which labels (vertical and horizontal) are shown: Value Description hlVertical Values are shown along the X axis hlHorizontal Range is shown along the Y axis
Default: [hlVertical, hlHorizontal]; !!} function THistogramBox.GetLabels: THistogramLabels; begin result := fLabels; end; {!! THistogramBox.MinSelected Declaration property MinSelected: Integer; Description If
= mhSelectRange then MinSelected and specify the range of returned values. If = mhSelectValue then MinSelected and return the same value. Note: This valid range of MinSelected will depend on . If is [hkHue] then the range will be 0 to 359. Otherwise it will be 0 to 255. -1 can also be specified to clear the selection. Example // Select mid-point in color histogram HistogramBox1.MinSelected := 128; See Also - - - !!} function THistogramBox.GetMinSelected: Integer; begin if fMouseMinX < 0 then Result := -1 else begin if fHistKind = [hkHue] then Result := MulDiv( 359, fMouseMinX - fHistogramAbsXPos, Width - fHistogramAbsXPos - 1 ) else Result := MulDiv( 255, fMouseMinX - fHistogramAbsXPos, Width - fHistogramAbsXPos - 1 ); end; end; procedure THistogramBox.SetMinSelected(const Value: Integer); begin if fMouseMinX = Value then exit; if Value < 0 then begin // Deselect fMouseMinX := -1; fMouseMaxX := -1; end else begin if fHistKind = [hkHue] then fMouseMinX := fHistogramAbsXPos + MulDiv( Width - fHistogramAbsXPos - 1, Value, 359 ) else fMouseMinX := fHistogramAbsXPos + MulDiv( Width - fHistogramAbsXPos - 1, Value, 255 ); if fMouseMinX > Width - 1 then fMouseMinX := Width - 1; end; Invalidate; end; {!! THistogramBox.MaxSelected Declaration property MaxSelected: Integer; Description If = mhSelectRange then and MaxSelected specify the range of returned values. If = mhSelectValue then and MaxSelected return the same value. Note: This valid range of MaxSelected will depend on . If is [hkHue] then the range will be 0 to 359. Otherwise it will be 0 to 255. -1 can also be specified to clear the selection. Example // Select from 100 to 200 HistogramBox1.MouseInteract := mhSelectRange; HistogramBox1.MinSelected := 100; HistogramBox1.MaxSelected := 200; See Also - - - !!} function THistogramBox.GetMaxSelected: Integer; begin If fMouseInteract = mhSelectValue then Result := GetMinSelected else if fMouseMaxX < 0 then Result := -1 else begin if fHistKind = [hkHue] then Result := MulDiv( 359, fMouseMaxX - fHistogramAbsXPos, Width - fHistogramAbsXPos - 1 ) else Result := MulDiv( 255, fMouseMaxX - fHistogramAbsXPos, Width - fHistogramAbsXPos - 1 ); end; end; procedure THistogramBox.SetMaxSelected(const Value: Integer); begin if fMouseMaxX = Value then exit; if Value < 0 then begin // Deselect fMouseMinX := -1; fMouseMaxX := -1; end else begin if fHistKind = [hkHue] then fMouseMaxX := fHistogramAbsXPos + MulDiv( Width - fHistogramAbsXPos - 1, Value, 359 ) else fMouseMaxX := fHistogramAbsXPos + MulDiv( Width - fHistogramAbsXPos - 1, Value, 255 ); if fMouseMaxX > Width - 1 then fMouseMaxX := Width - 1; end; Invalidate; end; {!! THistogramBox.Scale Declaration property Scale: ; Description Specifies the histogram plot scale. Default value is iehsLinear. Use iehsLinearClipped or iehsLogarithmic on images with a heavy background color, which may create flat histograms. Example // Improve range of histogram display HistogramBox1.Scale := iehsLinearClipped; !!} procedure THistogramBox.SetScale(Value: THistogramScale); begin if fScale <> Value then begin fScale := Value; Update(); end; end; end.