I have implemented the canvas on which we draw with a brush in Smalltak Squeak but with only a single color and a single size.
I'd like to add the possibility of changing the color and the size of the brush.
Could anyone help me please ?
Thank you in advance.
The differents methods are:
"Methods"
extent: aPoint
| newForm |
super extent: aPoint.
newForm := Form extent: self extent depth: 16.
newForm fillColor: Color veryLightGray.
form ifNotNil: [form displayOn: newForm].
form := newForm.
initialize
super initialize.
self extent: 400#350.
drawOn: aCanvas
aCanvas image: form at: bounds origin.
handlesMouseDown: evt
^ true
mouseDown: evt
brush := Pen newOnForm: form.
brush roundNib: 3.
brush color: Color red.
lastMouse := evt cursorPoint - bounds origin.
brush drawFrom: lastMouse to: lastMouse.
self invalidRect:
((lastMouse - brush sourceForm extent corner:
lastMouse + brush sourceForm extent)
translateBy: bounds origin).
mouseMove: evt
| p |
p := evt cursorPoint - bounds origin.
p = lastMouse ifTrue: [^ self].
brush drawFrom: lastMouse to: p.
self invalidRect: ((
((lastMouse min: p) - brush sourceForm extent) corner:
((lastMouse max: p) + brush sourceForm extent))
translateBy: bounds origin).
lastMouse := p.
addCustomMenuItems: aCustomMenu hand: aHandMorph
super addCustomMenuItems: aCustomMenu hand: aHandMorph.
aCustomMenu add: 'clear' action: #clear.
clear
form fillColor: Color veryLightGray.
self changed.
Related
This code does nice zoom effect at cursor position but I think the first call of glTranslate(...); is rendered as well and produce "flickering" which I do not want. How to avoid drawing glTranslate(...); at first call? I need the first call because it does it's job (translate MODELVIEW matrix), I just want this "the fist call" translation but without rendering. The second call of glTranslate(...) has to be drawn only. This is the code:
DrawScene()
begin
worldCoordinate(currentMousePos.X, currentMousePos.Y);
glTranslate(worldMMXYZ[0], worldMMXYZ[1], 0); //the fist call
glClear(GL_COLOR_BUFFER_BIT);
//-----------------PROJECTION-----------
glMatrixMode (GL_PROJECTION);
glLoadIdentity;
glViewport(0, 0, Width, Height);
glOrtho( Width + zumirajZoomX, Width * aspectRatio - zumirajZoomX, Height * aspectRatio - zumirajZoomY, Height + zumirajZoomY, 1, -1);
//---------------------------------------
glDisable(GL_DEPTH_TEST);
glMatrixMode (GL_MODELVIEW);
glTranslate(worldMMXYZ[0], worldMMXYZ[1], 0); //the second call
glFlush;
end;
OnPaint()
begin
DrawScene();
//some drawing functions
SwapBuffers();
end;
OnMouseWheel()
begin
//cursor position
end;
I am using GoCV (Open CV 4 bindings for go) and I want to crop an image represented as a cuda.GpuMat given an image.Rectangle.
With a regular gocv.Mat this operation is simple enough:
func Crop(src *gocv.Mat, rect image.Rectangle) *gocv.Mat {
res := src.Region(rect)
return &res
}
However, I do not see a similar Region method on the cuda.GpuMat in GoCv (some bindings are not implemented yet), nor do I see a region method in the C++ source/docs: https://docs.opencv.org/master/d0/d60/classcv_1_1cuda_1_1GpuMat.html.
I have managed to effectively crop using cuda.Remap as follows:
func Crop(src *cuda.GpuMat, rect image.Rectangle) *cuda.GpuMat {
rectWidth := rect.Dx()
rectHeight := rect.Dy()
dst := cuda.NewGpuMat()
map1 := gocv.NewMatWithSize(rectHeight, rectWidth, gocv.MatTypeCV32F)
defer map1.Close()
map2 := gocv.NewMatWithSize(rectHeight, rectWidth, gocv.MatTypeCV32F)
defer map2.Close()
offsetX := rect.Min.X
offsetY := rect.Min.Y
for x := 0; x < map1.Cols(); x++ {
for y := 0; y < map2.Rows(); y++ {
map1.SetFloatAt(x, y, float32(y+offsetY))
map2.SetFloatAt(x, y, float32(x+offsetX))
}
}
gmap1, gmap2 := cuda.NewGpuMat(), cuda.NewGpuMat()
defer gmap1.Close()
defer gmap2.Close()
gmap1.Upload(map1)
gmap2.Upload(map2)
cuda.Remap(*src, &dst, &gmap1, &gmap2, cuda.InterpolationDefault, cuda.BorderConstant, color.RGBA{0, 0, 0, 0})
return &dst
}
But after running some benchmarks this implementation is 1-2 orders of magnitude slower than gocv.Mat#Region.
Given that there is no Region method on cuda.GpuMat in GoCV or OpenCV4, what would be the most optimal equivalent operation?
I'm not too concerned if the GoCV bindings do not exist. I'm more interested in the OpenCV4 equivalent to Region for a GpuMat.
UPDATE
I have found another method of cropping a cuda.GpuMat, but it is also about an order of magnitude slower than gocv.Mat#Region.
func Crop2(src *cuda.GpuMat, rect image.Rectangle) *cuda.GpuMat {
rectWidth := rect.Dx()
rectHeight := rect.Dy()
dst := cuda.NewGpuMat()
sz := image.Point{
X: rectWidth,
Y: rectHeight,
}
cuda.Rotate(*src, &dst, sz, 0, -float64(rect.Min.X), -float64(rect.Min.Y), cuda.InterpolationDefault)
return &dst
}
I am customizing OnDrawItem event to draw icons next to item names.
Here is my code so far for the event OnDrawItem:
void __fastcall Form1::ComboBox1DrawItem(TWinControl *Control, int Index,
TRect &Rect, TOwnerDrawState State)
{
TComboBox* CB = static_cast<TComboBox*>(Control);
CB->Canvas->FillRect(Rect);
boost::scoped_ptr<Graphics::TBitmap> bitmap(new Graphics::TBitmap());
bitmap->PixelFormat = pf32bit;
bitmap->AlphaFormat = afPremultiplied;
ImageList1->GetBitmap(Index, bitmap.get());
bitmap->AlphaFormat = afPremultiplied;
if (bitmap->Canvas->Handle)
{
// structure for alpha blending
BLENDFUNCTION bf;
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.SourceConstantAlpha = 0xFF; // 0x00 (transparent) through 0xFF (opaque)
bf.AlphaFormat = AC_SRC_ALPHA; // Use bitmap alpha
::AlphaBlend(CB->Canvas->Handle, // handle to destination DC
Rect.Left + 2, // x-coord of upper-left corner
Rect.Top, // y-coord of upper-left corner
bitmap->Width, // destination width
bitmap->Height, // destination height
bitmap->Canvas->Handle, // handle to source DC
0, // x-coord of upper-left corner
0, // y-coord of upper-left corner
bitmap->Width, // source width
bitmap->Height, // source height
bf // alpha-blending function
);
}
Rect = Bounds(Rect.Left + 20 + 2, Rect.Top, Rect.Right - Rect.Left, Rect.Bottom - Rect.Top);
DrawTextW(CB->Canvas->Handle, CB->Items->Strings[Index].c_str(), -1, &Rect, DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
}
The problem of course is getting a transparent TImageList1 to copy to transparent TBitmap preserving 32-bit alpha transparency/semi-transparency. Currently I get it out with white background in the resulting TBitmap.
Just to be clear, TImageList ColorDepth is set to cd32bit with DrawingStyle = dsTransparent before loading images to it and the images on it are transparent, no problems there.
What is the trick to solve this?
UPDATE AND MY FINAL SOLUTION
Based on a reply here here is my final working code for someone else who might need it in the future. This of course is just a template code which you might want to customize further to your own needs.
void __fastcall TForm1::ComboBox1DrawItem(TWinControl *Control, int Index, TRect &Rect, TOwnerDrawState State)
{
if (Index >= 0)
{
TComboBox* CB = static_cast<TComboBox*>(Control);
CB->Canvas->FillRect(Rect);
// Note - ImageList1 already has DrawingStyle set to dsTransparent
ImageList1->Draw(CB->Canvas, Rect.Left + 2, Rect.Top, 0);
Rect = Bounds(Rect.Left + ImageList1->Width + 2 + 2, Rect.Top, Rect.Right - Rect.Left - ImageList1->Width - 2, Rect.Bottom - Rect.Top);
DrawTextW(CB->Canvas->Handle, CB->Items->Strings[Index].c_str(), -1, &Rect, DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
}
}
You don't need to try and grab the original bitmap from the imagelist because the imagelist itself knows how to draw honoring transparency information. You can use its Draw method for that.
Otherwise, an answer here suggests that setting AlphaFormat to 'afIgnored' before calling GetBitmap should preserve transparency.
Source is either PNG or GIF where the pixels that should be "colorized" are white. Background can be either black or transparent, whichever is easiest.
Now I'd like to cut out a rectangular part of the source, and AND it with the palette color (gif) or RGB color (png) of the "brush", to "stamp" it out on a TImage/TCanvas with that color.
Probably one of those lazy questions where RTFM would do. But if you have a nice solution please share :)
I tried Daud's PNGImage lib, but I can't even get it loading the source image. Is there a trick to using it?
The solution needs to work on D7 and up, XP and up.
do i understand you want to change the white color with some other color?
if that is so i think you should check the image pixel by pixel and check what color is the pixel and change it if is white.
thats how you can loop through image
var
iX : Integer;
Line: PByteArray;
...
Line := Image1.ScanLine[0]; // We are scanning the first line
iX := 0;
// We can't use the 'for' loop because iX could not be modified from
// within the loop
repeat
Line[iX] := Line[iX] - $F; // Red value
Line[iX + 1] := Line[iX] - $F; // Green value
Line[iX + 2] := Line[iX] - $F; // Blue value
Inc(iX, 3); // Move to next pixel
until iX > (Image1.Width - 1) * 3;
Here's code that show how to reads the Red and Blue values and switched them.
var
btTemp: Byte; // Used to swap colors
iY, iX: Integer;
Line : PByteArray;
...
for iY := 0 to Image1.Height - 1 do begin
Line := Image1.ScanLine[iY]; // Read the current line
repeat
btSwap := Line[iX]; // Save red value
Line[iX] := Line[iX + 2]; // Switch red with blue
Line[iX + 2] := btSwap; // Switch blue with previously saved red
// Line[iX + 1] - Green value, not used in example
Inc(iX, 3);
until iX > (Image1.Width - 1) * 3;
end;
Image1.Invalidate; // Redraw bitmap after everything's done
but this is for bitmap image only.
if this is useful try to convert your image to bitmap and from then manipulate it.
The area chart (image) has a few data series, which are charted with different colors. We know the image size and co-ordinates of each lable on x-Axis, is it possible to discover the series of y-Axis by image recongition? Can anybody shed some light?
If you know the y-axis scale, it should be possible.
To screenscrape, you could first filter your image with a color filter for each of the series.
Second step would be to gather the coordinates of all remaining pixels in your temporary image and transform them these to the scale needed.
given
a pixel at coordinates x,y
the offset of the charts Origin in image pixels xoffset, yoffset
the Scale of you chart axis xscale, yscale
you could calculate the data for this pixel (pseudocode)
pixelData.x := (x - xoffset) * xscale
pixeldata.y := (y - yoffset) * yscale
And afterwards, do some interpolation if your series line is more then one pixel wide (for example get the average data for all pixels in a single column or so).
Update1: Pseudocode for naive color filter filtering out red charts
//set up desired color levels to filter out
redmin := 240;
redmax := 255
bluemin := 0;
bluemax := 0;
greenmin := 0
greenmax := 0;
//load source bitmap
myBitmap := LoadBitmap("Chartfile.bmp");
//loop over bitmap pixels
for iX := 0 to myBitmap.width-1 do
for iY := 0 myBitmap.height-1 do
begin
myColorVal := myBitmap.GetPixels(iX, iY);
//if the pixel color is inside your target color range, store it
if ((mycolorVal.r >=redmin) and (myColorVal.r <= redmax)) and
((mycolorVal.g >=greenmin) and (myColorVal.g <= greenmax)) and
((mycolorVal.b >=bluemin) and (myColorVal.b <= bluemax)) then
storeDataValue(iX, iY); //performs the value scaling operation mentioned above
end;