I am trying to get the current pixel in an image by a "OnMouseMove event" Using Scanline.
something equivalent to this:
Label1.Caption := IntToStr(Image1.Picture.Bitmap.Canvas.Pixels[X,Y]);
Any ideas ?
ScanLine returns a pointer to a packed array of pixels that constitutes one line of a bitmap. Using this pointer you can access these pixels fast.
ScanLine can't help if you need only one pixel.
Still you can use ScanLine here; assuming bitmap pixel format pf32bit:
Label1.Caption:= IntToStr(PIntegerArray(Image1.Picture.Bitmap.ScanLine[Y])^[X]);
Scanlines are useful for quickly scanning the entire line, like in your other post. But if you want to get an arbitrary single pixel, the best way to do it is to use the code you've already got.
Related
I am using the canvas draw functions drawrect and filltext to draw onto a Tbitmap but I don't want the results antialiased. Anyone know how to do that ?
Working with OSX and Delphi XE3 (but have XE4 and XE5 if needed)
Is the problem:
the bitmap you create seems to have anti-aliasing present in the data?
or have you got a good bitmap and want to disable anti-aliasing in the viewer/display?
If it is the former, have you checked that the anti-aliasing is actually present in the bitmap, and not introduced by your viewer?
In the past I've found it useful to draw a black-on-white test pattern, and display the image at 1:1 scale. Irfanview is a nice tool for viewing at 'true' scale. Then use a loupe/peak/lens to get a close-up of the actual pixels.
Black-on-white test patterns are particularly good since you should be able to see (hopefully) that the R,G and B sub-pixels are all equally illuminated when there is no anti-aliassing present. If you draw a black-on white pattern and you get solitary bright sub-pixels then you've definitely got anti-aliassing (or some other form of corruption!).
My experience has been that image viewers often do interpolation for you, and it can be tricky to see what is going on unless you look at the actual bitmap data or have a close-up look at the unscaled image...
Hi in the drawBitmap method you need to set HighSpeed parameter to "True", in the sample below:
NewBitmap.Canvas.DrawBitmap(SmallBmp, RectF(0, 0, SmallBmp.Width, SmallBmp.Height), RectF(0, 0, NewBitmap.Width, NewBitmap.Height), 1,**True**);
rgds
Ivan
I use delphi 7 and delphix so I can have ddraw and be able to create a surface to play with pixels.
so in a button trigger i use this:
for i:=1 to 100 do
for j:=1 to 100 do
dxdraw1.Surface.Pixels[i,j]:=250;
where dxdraw1 is a ddraw surface.
The problem is that it works, but the result shows after I hoover another window above my program, like it is not updating the rectangle area with the pixels.
(I press the button, the cpu usage is getting up for a short and the rectangle remains black until I hoover another window.)
Also its slow. I read somewhere this:
"...
DXDraw.Surface.Canvas.Pixels[X,Y]:=clBlue;
DXDraw.Surface.Canvas.Release;
..."
and after this:
"...
Just remember that this function is extremely slow .
It's locking and unlocking the surface on every pixel set.. not very usable.
PixelDX and turboPixel don't, you manually lock the surface, do all of your
pixel operations and then unlock it.. 1000 times faster.
..."
How to use these functions? I cant find them (and I have no idea since I am beginner on this)?
How to lock first and then unlock?
U P D A T E :
Ok, I used undelphix, but in the rectangle I cant see the result, it still remains black:
procedure TForm1.BitBtn1Click(Sender: TObject);
var
i,j :integer;
begin
dxdraw1.Surface.Lock;
for i:=1 to 150 do
for j:=1 to 150 do
dxdraw1.Surface.Pixel[i,j]:=100;
dxdraw1.Surface.Unlock;
end;
U P D A T E 2 :
It works but this bizarre happens: to see the result I have to "hide" the app window under another window or program, and the minimize that window to see the result. If I move the app then the result is gone, and it stays blank. Any ideas?
I'm not up to date on Delphi-X, but I have used the raw DirectX libs a lot in my Life32 program.
Here's how it works behind the scenes:
You get a lock on the screen.
This returns a pointer to memory that you can write to, whatever to write in this memory block will appear on the screen.
The entire system will be frozen (!) until you call unlock.
The memory pointer in step 2 can be regarded as a pointer directly to videomemory.
It is up to you to know:
- bits per pixel;
- number of pixels in the x and y direction;
- padding bytes at the end of each scan-line;
- if the bits per pixel are less than 24, you will not be working with RGB values, but with a palette;
- if you write past the end of the screen unpredicatable stuff will happen(!)
DelphiX is obsolete
I recommend you use unDelphiX: http://www.micrel.cz/Dx/
It is much more advanced and has many more features.
You can simply use:
DXDraw1.Surface.Lock; //special version Lock without any parameters
try
for xy:= 0 to Min(DXDraw1.Height, DXDraw1.Width) - 1 do begin
//silly example, unDirectX has line drawing routines
DXDraw1.Surface.Pixel[xy, xy]:= TheColor;
end; {for xy}
finally
DXDraw1.Surface.Unlock;
end;
Because you've called lock prior to accessing the pixel array, it will not bracket the call in a lock - unlock pair.
Warning
Always spend the absolute minimum amount of time possible in between lock and unlock calls, because your entire system will be frozen while the display is locked.
Also make sure that Delphi does not break on exceptions when debugging the code inside the lock box, because you system will be frozen with no way to revive it.
Note
There is still some overhead in the call to pixel, because the color value gets translated into a format dictated by the BytesPerPixel for your display.
Also the [x,y] coordinates get translated into a memory address.
In Life32 I resolved to write 8 different drawing routines, for every possible pixel depth.
And doing my own drawing of 16x16 blocks, thereby avoiding address translation per individual pixel.
Don't draw until you have to
Because DirectX is so fast, it's easy to draw much faster than the eye can see, use a high resolution timer (included in unDirectX) to limit drawing to x frames per second.
Do not use Windows messages like WM_PAINT to do your main drawing, but do redraw when you're receiving an incoming WM_PAINT message.
i have two different TPngObject SRC and DST. the SRC has assigned with a PNG graphic.
My code:
dst := TpngImage.createblank(COLOR_RGB, 16, 900, 60);
src.Assign(Image2.Picture.Graphic);
but i need to copy some portion of the src to the dst. i try to copy and draw on canvas but doesn't work with transparent.
I think you should be able to do this with the AlphaBlend function. You use {SRC/DEST}.Canvas.Handle for the HDC parameters.
I expect you could also achieve this with BitBlt.
I'm still curious as to the value of the TransparencyMode property of your TPNGImage instances.
I dont use TPNGImage, but I'll take a stab at this... does it support the Pixels property or Scanline? If so, you can copy over only the pixels you want, manually setting the r,g,b, and a values. I do this a lot with pf32bit bitmaps. Drawing it, as you noticed, wont preserve the transparency. You have to set the alpha value manually.
If TPNGImage doesnt support pixels or scanline, you can convert the png's to bitmaps first and do it that way.
I'm drawing some cars. They're Bitmap's, loaded from PNG's in the library. I need to be able to color the cars-- red ones and green ones and blue ones, whatever. However, when you paint the car green, the tires should stay black, and the windows stay window-color.
I know of two ways to handle this, neither one of which makes me happy. First, I could have two bitmaps for each car; one underneath for the body color, and one on top for detail bits. The underneath bitmap gets its transform.colorTransform set to turn the white car-body into whatever color I need. Not great, because I end up with twice as many Bitmap's running around on screen at runtime.
Second, I could programmatically search-and-replace "white" with "car-body" color when I load the bitmap for each car. Not great either, because the amount of memory I take up multiplies by however many colors I need.
What I would LIKE would be a way to say "draw this Bitmap with JUST THE WHITE PARTS turned into this other color" at runtime. Is there anything like this available? I will be less than surprised if the answer is "no," but I figure it's worth asking.
You might have answered the question yourself.
I think your first approach would need only two transparent images: one with pixels of the parts that need to change colour, one with the rest of the image. You will use colorTransform or ColorMatrix filter by case. It might even work with having the pixels the need the colour change covered with Sprite with a flat colour set on overlay ?
The downside would be that you will need to create a 'colour map'/set of pixels to replace for each different item that will need colour replacement.
For the second approach:
You might isolate the areas using something like threshold().
For speed, you might want either to store the indices of the pixels you need to replace in an Vector.<int> object that could be used in conjuction with BitmapData's getVector() method. (You would loop once to fetch the pixel indices that need to be replaced)
Since you will use the same image(same dimensions) to fill the same content with a different colour, you'll always loop through the same pixels. Also keep in mind that you will gain a bit of speed by using lock() before your loop to setPixel() and unlock() after the loop.
Alternatively you could use Pixel Bender and try some green screen/background subtraction techniques. It should be fast and wouldn't delay the execution of the rest of your as3 code as Pixel Bender code runs in it's own thread.
Also check out Lee's Pixel Bender subtraction technique too.
Although it's a bit old now, you can use some knowledge from #Quasimondo's article too.
HTH
I'm a little confused where you see the difference between your second approach and the one you would like to have. You can go over your loaded bitmap pixel by pixel and read out the color. If it turns out to be white replace it with another color. I do not see occurence of multiplied memory consumption.
You might want to try my selective color transform: http://www.quasimondo.com/archives/000614.php - it's from 2006, so some parts of it could probably be replaced by a pixel bender filter now.
Why not just load the pieces separately, perform the color transform on the one you want to change, then do a BitmapData.copyPixels() with the result? The blit routine runs in machine code, so is wicked fast. Doing it pixel by pixel in ActionScript would be glacially slow in comparison.
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/BitmapData.html#copyPixels()
WHAT I AM TRYING TO DO
I am trying to draw multiple graphics to a Timage, These graphics that i Draw consist of ordered layers with Foodfills and lines.
I use multiple buffers to ensure ordering and double buffering.
WHAT I AM DOING
procedure DrawScene();
var
ObjLength,LineLength,Filllength,Obj,lin,angle,i:integer;
Npoints : array[0..1] of Tpoint;
Objmap:TBitmap;
wholemap:TBitmap;
begin
wholemap := TBitmap.Create;
wholemap.Width:=area;
wholemap.height:=area;
ObjLength:=length(Objects);
for Obj:=0 to (ObjLength-1) do
if objects[Obj].Visible then
begin
// create object bitmap
if Objects[obj].Tag='FBOX' then
begin
Objmap := TBitmap.Create;
Objmap.Width:=area;
Objmap.height:=area;
Objmap.Transparent:=true;
Objmap.Canvas.Rectangle((objects[obj].Boundleft-4)+objects[obj].Position.x,area-((objects[obj].boundtop+4)+objects[obj].Position.y),(objects[obj].boundright+4)+objects[obj].Position.x,area-((objects[obj].boundbottom-4)+objects[obj].Position.y));
end;
//draw object
LineLength:=length(objects[Obj].Lines)-1;
angle:=objects[Obj].Rotation;
for lin:=0 to (LineLength) do
begin
for i:=0 to 1 do
begin
Npoints[i] := PointAddition(RotatePoint(objects[obj].Lines[lin].Point[i],angle),objects[obj].Position,false);
end;
Objmap:=DrawLine(Npoints[0].x,Npoints[0].y,Npoints[1].x,Npoints[1].y,objects[obj].Lines[lin].Color,Objmap);
end;
Filllength:=length(objects[Obj].Fills)-1;
for i:=0 to Filllength do
begin
Npoints[0]:=PointAddition(RotatePoint(objects[Obj].Fills[i].Point,objects[Obj].Rotation),objects[Obj].Position,false);
Objmap:=fillpoint( Npoints[0].x, Npoints[0].y,objects[Obj].Fills[i].color,Objmap);
end;
//write object to step frame
wholemap.Canvas.Draw(0,0,Objmap);
Objmap.Free;
end;
// write step frame to Visible Canvas
mainwindow.bufferim.Canvas.Draw(0,0,wholemap);
mainwindow.RobotArea.Picture.Graphic:=mainwindow.bufferim.Picture.Graphic;
wholemap.Free;
end;
WHAT I EXPECT
I expect to see each image object layered on top of one another with each image layer being the complete image for that layer.
im my example it is a robot with a flag behind it.
the flag is drawn first and then the robot.
WHAT I GET(on a pc)
on a pc i get what i expect and all appears to be correct.
WHAT I GET(on a laptop)
On a nearly every laptop and some pc's i only see the robot.
i put in some statments to see if it is drawing the flag and it does. the game can even interact with the flag in the correct manner.
further investigation showed me that it was only showing the last image drawn my "drawscene", and when images were drawn directly to the wholecanvas everthing apeared(this cannot be done for overlapping fill layers reasons)
WHAT I THINK IS HAPPENING
so what i deduced is that the Timage.transparent property of the Timage is not working or is being computed differently on some machines..
i did a test to prove this and made a canvas red. then to that canvas i drew at 0,0 i Timage with property transparent=true with just one dot in the middle to the red canvas. the resuly was a white canvas with a dot in the middle.
I am assuming and findings indicate that machines with very basic graphics drivers seem to treat null or transparent as white where as more powerful machines seem to treat null or transparent as transparent.
this seems to be a bit of a failure due to the fact that the Timage.Transparent property was true.
EDIT:
UPDATE!!!
It would appear to be that on ATI graphics cards if a colour is "null" then it is interpreted in the format of PF24bit and therefore no alpha channel and no transparency.
on Nvidia cards it takes it as PF32bit and treats null as transparent.
the obvious way to get around that woulf be to set the bitmaptype to PF32bit, but that does still not work.
I then assumed that maybe that is not enough and I should make sure that the background is SET to transparent rather than being left as null.. but there are no tools ( that I can see) inside the Timage to set colour with alpha. all canvas drawing functions require a Tcolor that is RGB 24 bit and ony a TcolorRef with RGBA 32 bit would do....
is there a way of drawing with alpha 0?
WHAT I THINK I NEED TO KNOW
How to force the Transparent property to work on all machines
or a way to make laptops not paste in transparent as white
Or a way to achieve the same result.
Anyone have any solutions or ideas?
I have been using an Graphics library (AggPas) to help with drawing graphics and one of the things I've noticed is that I always need a line Bitmap.PixelFormat = pf32bit to get it to draw transparancies.
Having said that I use TransformImage from the AggPas library to copy the Image with a transparent background to another one and AggPas only accepts pf24bit or pf32bits as Pixel formats (otherwise it doesn't attach to the bitmap)
I've seen similar behaviour on different machines in the past (a few years back).
They were caused by different video cards and drivers.
Either the NVideo or the ATI ones were getting the wrong results, but I forgot which ones.
It could be reproduced on both laptops and regular PC's.
So: what video cards and drivers do you use?
--jeroen
I would explicitly set the bitmap format to pf32bit for each bitmap you create to ensure the problem isnt converting colors from 32 to 16 bit (if thats the native video resolution of the bitmaps getting created), which might interfere with how the transparency works. Also, I've had better luck specifically setting the transparency color in the past.
Another option - perhaps a better one in the long run, is to instead set the Alpha Channel on the images (ie, use PNG files), and use the GDI function AlphaBlend() to draw the graphics.