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.
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
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
I am analyzing an image, with main problem being determining the brightness of an object and contrast between it and background. However, due to object having cell-like structure, with lots of internal spaces with background in it, pixels with background color make too much of a way into selection I use to determine brightness, spoiling the result.
I want to filter all pixels with backfround color out of selection altogether and, since picture-analyzing tool I am using (imageJ) does not allow it, filtering coresponding pixels in table seems to be a rational course.
Using c#, how can I accomplish this task?
Alternatively, any existent solutions would be welcome
Got it done with System.Drawing.Bitmap.
I'm writing a paint application. User must be able to move with all objects after it's painted or edited. I have a brush and erase tool, so user can erase all or any part of object painted with brush. So I made an object DrawBrush that holds a System.Drawing.Region made from GraphicsPath.
But I don't know how to size it. I need to change size in every direction separately on mouse move (for example only to left)
can someone help me?
I'm able to do anything with this object (moving), but no sizing...
A region is like a fence - it simply marks out the boundary of an area. It does not "contain" any graphics, so resizing a region will have no direct/visible effect.
If you wish to be able to move or resize portions of a bitmap image within your editor, you will need to copy a piece of your main image (as specified by your region) into a temporary Bitmap. Then you can draw the tempoary bitmap back to your main image (in a different location and/or at a different size).
If you wish to be able to draw multiple objects in your painting program, and then edit them (move them around and resize them) independently later, then you will need to store each of them in a separate bitmap object and composite them together to display the final image on screen or save it to a flat bitmap format. If you don't keep all the shapes separately like this, you will lose too much information and you won't be able to edit them later.
Before you try to work out write the code to do this, you may need to think about the design of your editor - what does it need to do, and how will you achieve it? How is your "document" going to be described? (A single bitmap? many small bitmaps that are drawn at different locations? Vector paths?). If you write code before you understand how you will represent the document, you're likely to paint yourself into a corner (sorry about the pun) and get totally stuck.
So here are the details (I am using C# BTW):
I receive a 32bpp image (JPEG compressed) from a server. At some point, I would like to use the Palette property of a bitmap to color over-saturated pixels (brightness > 240) red. To do so, I need to get the image into an indexed format.
I have tried converting the image to a GIF, but I get quality loss. I have tried creating a new bitmap in an index format by these methods:
// causes a "Parameter not valid" error
Bitmap indexed = new Bitmap(orig.Width, orig.Height, PixelFormat.Indexed)
// no error, but the resulting image is black due to information loss I assume
Bitmap indexed = new Bitmap(orig.Width, orig.Height, PixelFormat.Format8bppIndexed)
I am at a loss now. The data in this image is changed constantly by the user, so I don't want to manually set pixels that have a brightness > 240 if I can avoid it. If I can set the palette once when the image is created, my work is done. If I am going about this the wrong way to begin with please let me know.
EDIT: Thanks guys, here is some more detail on what I am attempting to accomplish.
We are scanning a tissue slide at high resolution (pathology application). I write the interface to the actual scanner. We use a line-scan camera. To test the line rate of the camera, the user scans a very small portion and looks at the image.
The image is displayed next to a track bar. When the user moves the track bar (adjusting line rate), I change the overall intensity of the image in an attempt to model what it would look like at the new line rate. I do this using an ImageAttributes and ColorMatrix object currently.
When the user adjusts the track bar, I adjust the matrix. This does not give me per pixel information, but the performance is very nice. I could use LockBits and some unsafe code here, but I would rather not rewrite it if possible. When the new image is created, I would like for all pixels with a brightness value of > 240 to be colored red. I was thinking that defining a palette for the bitmap up front would be a clean way of doing this.
Going from 32bpp to 8bpp indexed will almost always result in quality loss, unless the original image has less than 256 colors total.
Can you create another image that is a overlay with the affected pixels red, then show both of those?
Since you are going for brightness > 240, you can convert the overlay to grayscale first, then to indexed to get the overbright pixels.
You don't specify what you are doing with it once you have tagged the offenders, so I don't know if that will work.
Sounds like something you could do easily with a pixel shader. Even very early shader models would support something as easy as this.
The question is however:
Can you include shader support in your application without too much hastle?
Do you know shader programming?
EDIT:
You probably don't have a 3D context where you can do stuff like this =/
I was mostly just airing my thoughts.
Manipulating the picture pixel by pixel should be doable in real-time with a single CPU shouldn't it?
If not, look into GPGPU programming and Open CL.
EDIT AGAIN:
If you gave some more details about what the app actually does we might help a bit more? For example, if you're making a web-app none of my tips would make sense.
Thanks for the help everyone. It seems that this can be solved using the ImageAttributes class and simply setting a color remap table.
ColorMap[] maps = new ColorMap[someNum]
// add mappings
imageAttrs.SetRemapTable(maps);
Thanks for the help again, at least I learned something.