The Layout:
I'm using third party controls to scan documents. I have an event that occurs when I scan an image (mostly used to add annotations the image). The event provides me with only one property named .PAhDC. This property is a handle to the DC that stores the image before it is written to a file. Thus I can make changes to the image before it gets written to a file.
The Expected Results:
I would like to simply add a 1/4 inch (lets say 100 pixels) of white space line on the very top of the image. If my original image is 200x200 (WxH) then my new final image would need to be 200x300.
Question And Other Thoughts:
How can I alter an existing image with only knowing it's DC handle? I was thinking of doing something like the following...
Create a new DC.
Create a new Bitmap 100 pixels taller than the original image.
Use that new bitmap in the new DC.
Copy the original image to the new bitmap (100 pixels from the top as a start point).
Then use something like SelectObject to replace the old bitmap in the original hDC with the new one and then destroy the old bitmap object.
Note: I would like to do this with MANAGED CODE as much as possible. Using SelectObject() was the only way I could think of but it's of course unmanaged code... :/
You can't without cooperation with the owner of the bitmap and DC.
The DeviceContext is purely a viewport onto an underlying DIB/bitmap and has no concept of size or dimensions (beyond the clipping region) While you can create a new bitmap and select it into the DC, it's highly likely that the application will just ignore what you've done and use the DIB that it has created.
The end result of this will be GDI object leaks and no change to the underlying image.
To do what you you ask, you will need full cooperation with the other code and them adding a method that allows you to replace the underlying data.
Sure, you can do this in managed code. All P/Invoke declarations are readily available from any decent search engine.
When creating a new DC, make sure it's a DC compatible with the original one
When creating a new bitmap, make sure it's compatible with the DC
Related
Im trying to create a little game with C# and GDI+. For learning purposes I'm trying to avoid as much frameworks etc. as possible. So I have some specific questions to GDI+
Is it possible to fill a region object in GDI with an image?
-If not, is there a manual way for it?
Can you read and set single pixels in a graphics object (not a bitmap)?
Have you got any tips for me to increase overall performance in GDI?
Thanks for any help
Is it possible to fill a region object in GDI with an image?
A region can't be filled, it doesn't store pixels. What you are almost certainly looking for here is the Graphics.Clip property. Assign the region to it and draw the image, it will be clipped by the region.
Can you read and set single pixels in a graphics object (not a bitmap)?
No, the Graphics object doesn't store any pixels itself, it only keeps track of where you draw to. The "device context" in Windows speak. Which can be a bitmap, the screen, a printer, a metafile. Not all of these device contexts let you read a pixel back after drawing (not a printer and not a metafile for example). But no problem of course when you draw to a bitmap.
Have you got any tips for me to increase overall performance in GDI?
There is one crucial one, .NET makes it very easy to overlook. The pixel format of the bitmap you draw to is super-duper important. The most expensive thing you'll ever do with a bitmap is copying it, from CPU memory to the video-adapter's memory. That copy is only fast if the format of the pixels exactly match the format the video-adapter uses. On all modern machines that's PixelFormat.Format32bppPArgb. The difference is huge, it is ten times faster than all the other ones.
Many answers that will detail these points:
Once you have a Region it will limit where pixels are drawn. Use Graphics.DrawImage then
No way to read and only a perverted way to set a Pixel by Graphics.FillRectangle(br, x,y,1,1); The reason behind this is probably that Graphics can not only operate in a Pixel mode but also with various other Units from points to inches and mm..
Use Lockbits. Just one example using one Bitmap. Other common jobs demand locking two (one input one output) or or even three (two inputs and one calculated output) bitmaps..
Know what you invalidate, often only a small part really needs it..
Learn about ImageList, it can't do much but is useful for what it does, that is cache images of one size and color depth
Learn when to use a Panel and when a Picturebox
I have a problem as follow:
I basically have a code that generates a series of bitmap images. At the end of each iteration I use:
I was expecting that after all the iterations being completed, I end up with a new list which is consisting of different images. However I just realised that in my list-1 only the same image is going to be copied again and again.
Can anyone tell me if I am making any mistake in my code?
You likely need to make a new image for each loop iteration in the "code that generates a series of bitmap images" (in the code you're not displaying).
If you reuse the same image (the bmp variable), without creating a new image, (ie: bmp = new Bitmap(width, height) or similar), you'll end up overwriting and reusing the same image in memory for each loop iteration, which explains your current behavior.
Simply put, I'm trying to draw an image (2560x2048) that is supposed to be zoomed / draged and such but the performance is very bad, because it flickers everytime I move it. I use a custom control to be able to drag the image to a new position and zoom in and out, which means it have to be flexible and fast.
So, what is the easiest and best way to just draw a single image with the graphics card? Without having to initialize a thousand directX objects just for one simple purpose.
Overall, the application is a tool - so not a game. But this particular large image is supposed to be drawn effectively.
Double buffering is your friend http://msdn.microsoft.com/en-us/library/3t7htc9c.aspx
Well I am Borland C++ friendly so i would use simple Canvas (simple Windows GDI interface).
No need for GL,GLSL or DX
you need 2 bitmaps.
one as source image (that is your 2560x2048) next is back-buffer of the screen (client size of your view area). Both has to be DIB. I prefer pf32bit pixel format (32 bit int as a color so I can use int *p ...)
need to write render function (or use GDIs strech draw or CopyRect)
do not use Set or Put or Pixels they are slow (always checking size and color format and many other stuff for each pixel). Instead use bitmaps scan lines (in VCL bmp->ScanLine[y]).
This usually speeds up things about ~1000 times if done properly
put it all together
clear back-buffer with background color. Use your render function to copy viewed area to back-buffer (no need to render whole image). When all rendering is done copy back-buffer to the screen.
when all works you can further speed up things
use array of scan lines pointers instead of calling them in rendering. Addresses of scan lines are changed only after resizing of bitmap so on resize delete all array of pointers and create and fill new one (int *pyx[ys];)
This kind of bitmap rendering is fast enough for simple software 3D rendering so for your purpose must be sufficient with high enough framerate (estimate well over 70fps on average desktop machine)
some code for Borland C++ VCL (just so you know what to look for in your programing languge)
// init
int xs=0,ys=0,*pyx=NULL;
Graphics::TBitmap *bmp=new Graphics::TBitmap;
bmp->HandleType=bmDIB;
bmp->PixelFormat=pf32bit;
// exit
if (bmp) delete bmp; bmp=NULL;
if (pyx) delete pyx; pyx=NULL;
// resize(_xs,_ys)
if (pyx) delete pyx; pyx=NULL;
bmp->Width=_xs;
bmp->Height=_xs;
xs=bmp->Width;
ys=bmp->Height;
pyx=new int*[ys];
if (pyx==NULL) return; // not enough memory
for (int y=0;y<ys;y++) pyx[y]=(int*)bmp->ScanLine[y];
// now pyx[y][x]=0; means setpixel(x,y)=color(0) without any slowing down checks
// now c=pyx[y][x]; means colro(c)=getpixel(x,y) without any slowing down checks
// but beware of accessing x,y, outside <0;xs),<0;ys) !!!
I am looking to draw a string on a DC (Graphics - I am using C#) - but I want the drawn text to be "deleted" from the image so that what's left is essentially a cut-out of the text.
If I was to DrawString with a transparent brush obviously nothing would have happened.
Is there a way of drawing something like that, or do I need to use 2 DCs and BitBlt with some combination of NOTs or XOR or whatever (I did similar things years ago, but was wondering if there's an easiery way)?
If you want to cut sth out of the image, you can do it like this:
Drawing2D.GraphicsContainer c = graphics.BeginContainer();
GraphicsPath p = new GraphicsPath();
p.AddString(...);
graphics.SetClip(p, CombineMode.Xor);
graphics.DrawImage(this.Image, this.Location);
graphics.EndContainer(c);
It's like the solution farther above, but first without SetClip the Graphics-Object doesn't get updated, and second, you need to use Xor.
Note, that making a GraphicsContainer is optional, but makes encapsulation easier, especially if you work with transforms.
You might want to try:
// g is your Graphics object
using (var path = new GraphicsPath())
{
path.AddString(.... );
g.Clip.Exclude(path);
}
// Do your other painting here
Sounds like this may require you to make a new image and draw the old one on top. I'm not to sure of your situation though.
You could set Graphics.CompositingMode to CompositingMode.SourceCopy - but I'm not sure if that will work with transparent content.
The way around this is to:
Draw your text to a separate image using red brush over black background.
Iterate over each pixel of text image and target image...
...manually set target image pixel color's Alpha value according to text's image Red component.
If speed is not a concern and you deal with small bitmaps, you can use GetPixel and SetPixel methods. But I would recommend using LockBits to access BitmapData directly and process pixels in a byte array. This is fast and not-so-hard-to-implement solution, although you'll have to deal with "unsafe" code (or use the Marshal class).
LockBits reference on MSDN
Marshal reference on MSDN
From a quick search it unfortunately doesn't look like System.Drawing supports XOR drawing and you need to use unmanaged calls to GDI+. This answer to a similar question links to a page that might explain how to do that - the interesting file is here.
Hope this helps.
I have a bitmap that I have created by tiling the same graphic multiple times. When the bitmap is created it colours the tiles based on specific criteria.
When the bitmap is loaded, I then want to give the user the options to change the tile colours based on further pre-defined criteria. Would I therefore need to discard the current bitmap, generate again with the new colours and attach to the panel. Or can I iterate through the bitmap for each tile and change the colours that way?
Thanks.
It depends on how often the user is likely to change the tile colours. If they're not going to be doing it too often then it's probably easier to generate a new bitmap (mostly because your code seems like it's optimized for this scenario).
A better more performant possibiliy however is to use the Bitmap.LockBits/UnlockBits methods to get at the pixel data in the bitmap then manipulate the pixel data direcly. See the MSDN documentation on the Bitmap.LockBits method (http://msdn.microsoft.com/en-us/library/5ey6h79d.aspx) for a sample on how to do this.
As far as I know, the only way you can go through the bitmap and change colors is to do it pixel by pixel, so I think your best shot is to generate the bitmap from scratch when the user selects new colors.