I am trying to clear a bitmap in SkiaSharp in Xamarin, the bitmap is drawn by a SkCanvas,
new SKCanvas(SkBitmap bitmap)
but at times i need to clear the bitmap data.
SkCanvas.Clear()
tries to fill the bitmap with SKColor(0,0,0,0) pixels, but premul with the existing pixels it doesn't affect it.
SKBitmap.Reset()
doesnt work because it resets the object completely including the size.
Any idea how can i achieve this in an efficient way, not by going through all the pixels?
If you are trying to clear the pixel data, you WILL have to clear each pixel. There is no way around this.
To clear the bitmap/canvas, you should use SKCanvas.Clear(), but remember, you can pass in a color. So if you want the pixel data to be all zeroes, you can just SKCanvas.Clear(0).
I think this is what you are asking, if not I may need more info.
EDIT
Another thing that just occurred is that there is a SKBitmap.Erase(SKColor). This may be better as there is no need for a canvas.
Related
Hi i'm in the process of trying to create a large 1000x1000 array of rectangles in WPF, where each point in the array i'm able to find the index position using cursor and click on the position to modify the colour of the rectangle.
I need the array to be generated quickly <0.1s
Currently i'm reading in my into and array and from this generating a bitmap image, which i scale and colour accordingly, but after many attempts the fastest i can generate the image is around 1s
Any suggestions on how this could be done faster? either generating the image faster or potentially a better method of generating the array
Thanks
I do not think you will be able to draw 10^6 rectangles in 100ms. But that is a great deal of rectangle for a regular monitor. So you should probably consider what it is you are actually trying to do.
If you want a grid, just draw lines, that should reduce the number of draw calls to 1000+1000, much more manageable.
If you want a pixel aligned grid you could consider just iterating over every other row/pixel column in a bitmap and set the color. Typically using a writeablebitmap for fast access to the pixel-buffer. That should probably not take more than single digit ms. Manipulating pixels on this level will require some familiarity with how images are represented and how to convert x/y coordinates, i.e. var startOfPixelIndex = y * stride + x * bytesPerPixel if using a byte pointer.
If you want to color rectangles you probably want to work with a writeableBitmap and set individual, or small rectangles of pixels to your desired color. Ideally you should avoid recreating or clearing the entire bitmap, and instead just update the same bitmap over and over.
As far as I know there is no convenient way to draw to a WriteableBitmap, so in some cases it might make sense to use a GDI graphics object to draw to a regular bitmap, and copy the pixels over to a WriteableBitmap.
This is a follow on to my previous question Speeding Up Image Handling
Apologies if I should have amended that question in some way rather than starting a new one.
I have tried all sorts of different things to speed up the drawing of an image on screen.
I thought that compressing the image until it is smaller would have an effect. However while this might save memory for the object I do not think it has any effect on how long it takes to draw. I tried converting the image to jpeg and using 100% compression. However while this creates a blocky image it does not affect the drawing time. I now think this is because the number of pixels that get rendered is not changed by this
I tried reducing the color palette to 256 colors. This makes the size smaller since it uses less bytes per pixel but does not seem to affect drawing on screen. I had thought that reducing the bytes per pixel GDI+ has to handle might save some time but it is not enough for me to see so far.
So am I wasting my time looking at compression and palette?
I assume that time taken will be affected by the number of pixels to be drawn (width x height) and I have resized the image to match the pixel size as displayed on screen. I think this is the one thing that does have an effect....
I have looked at how to stop autoscaling of the image - does my resize stop that or can the image still be autoscaled when it is rendered?
I am wondering if I can replace the DrawImage call with something using p/Invoke or other API call (which I admit I don't really understand).
You could use the Bitblt P/Invoke, which copies image data directly. It does require some initialisation to convert the image data to something the display device understands, but this copy operation is lightning fast. If you would like to know what exactly is happening in DrawImage btw, use a tool like ILSpy or Reflector.NET to inspect the method.
See BitBlt code not working for an example. For some information about Bitblt see http://www.codeproject.com/KB/GDI-plus/flicker_free.aspx.
I am working on a project where I need to play with two bitmaps. I am putting them in a grid one over the other with reduced opacity (to give a watermark effect).
I am rendering the grid to a bitmap using RenderTargetBitmap and saving the bitmap to a file.
Now my requirement is to load the rendered bitmap again and recover the original pictures separately. Is there any way to recover the original images again. I am not able to think any algorithm to implement this.
My aim is to give a watermarking effect and then recover the images individually.
No. The information is lost during "flattening" of the image.
You need to save both images and information about their properties (position, opacity) into single file. And restore it on load.
If your goal is to simulate watermarking and allow later 'dewatermarking', then assuming that you have your watermarking bitmap present at decoding time, you probably can do that. Sure you cannot use your initial approach - just simple merging of two layers is not reversible.
You need to use some reversible transformation, like rotating source image pixel RGB values vector, using watermark image pixel RGB values as parameters. While dewatermarking you just use negative values from watermark image.
Well, RGB vector is not ideal - you can go out of RGB space while rotating it. Probably you can find color space (or some other transformation in RGB space), better suited to your goal.
(English is not my first or even second language, thereby I apologize if you can't understand my idea - just ask over.)
Why don't you try to make it two layers of bitmap?
i wonder if you can use TIFF format, where you can store multiple images. that way on display you can choose to show with/without watermark.
I found an article on image processing from here: http://www.switchonthecode.com/tutorials/csharp-tutorial-image-editing-saving-cropping-and-resizing Everything works fine.
I want to keep the high quality when resizing the image. I think if I can increase the DPI value I can achieve this. Does anyone know if this is possible? And if so, how can I implement it in C#?
For starters, it's worth pointing out that there are two general categories of images; vector [e.g. SVG, WMF, Adobe Illustrator and Corel Draw Graphics] and bitmap (also called raster) images [e.g. Bitmap, JPEG and PNG Images].
Vector images are formed from a series of mathematical equations and/or calculations. Bitmap images, on the other hand, are made up of individual dots (pixels) each corresponding to a particular feature on the object the image is taken of.
If it should happen that you want to resize an image, the first thing to consider is if it is a bitmap or vector image. By virtue of the fact that vector images are obtained from calculations, they can be perfectly resized without losing any detail. The case is different for bitmap images. Since each pixel is independent of the other, when you desire to resize it, you are simply increasing or decreasing the source to target pixel ratio.
So in order to double the size of a vector image, simply multiply the target dimensions by two and everything comes out all right. If you should apply the same effect on a bitmap, you are actually increasing each source pixel to cover four pixels (two rows of two horizontal pixels).
Of course, by applying interpolation and filtering, the computer can "smooth" out the edges of the target pixels so they seem to blend into each other and give the appearance of a reasonably resized image but this output is never the same as resizing a vector image; vector images resize perfectly.
You also mentioned DPI in your question. DPI is essentially the number of pixels that correspond to an inch when the image is printed not when it is viewed on a screen. Therefore by increasing the DPI of the image, you do not increase the size of the image on the screen. You only increase the quality of print [which needless to say depends on the maximum resolution of the printer].
If you really desire to resize the image and the image is a bitmap, as a rule of thumb, do not increase the size beyond 200% of the original image's size else you'll lose the quality.
You can see this answer for code to resize bitmap images.
To see a sample vector image, go to this link.
Note Try zooming in and out of the image to see how well it resizes.
A typical bitmap are the StackOverflow sprites. They do not keep their quality resized.
Further Reading
Vector Graphics: http://en.wikipedia.org/wiki/Vector_image
Bitmap Graphics: http://en.wikipedia.org/wiki/Bitmap_image
Simply If the original image is smaller then the re-sized image then there is hardly anything you can do. Rest is a research problem.
This would only be possible if it's a vector graphic. Look into SVG. Otherwise, I think you might need Silverlight or Flex for that part.
What you're asking isn't really possible. You can't enlarge an image while maintaining the same quality.
If you think about an image as a mapped array of pixels (literally, a "bit-map"), this makes sense. The image is saved with a fixed amount of data, and that's all you have to work with when you resize it. Any examples to the contrary (like TV shows, as suggested by one of the comments) are purely fictional.
The best that you can do is set the InterpolationMode property of the Graphics object you're using to do the resizing to "HighQualityBicubic", which is the highest quality smoothing algorithm supported by GDI+ and in fact by every major graphics package on the market. It's the best that even Adobe Photoshop has to offer. Essentially, interpolation means that the computer is calculating the approximate value of the new pixels you're adding to make the image larger from the relative values of neighboring pixels. It's a "best guess" method, but it's the best compromise we've come up with yet.
At the very least, the resulting images won't have "jaggies" or rough, pixelated lines.
Sample code:
Graphics g;
g.InterpolationMode = Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
// ... insert the rest of your code here
Beyond that, it's worth noting that GDI+ (which the .NET Framework uses internally for graphics routines) works best with image sizes that are multiples of 16. So if it all possible, you should try and make the width and height of your resized images a multiple of 16. This will preserve as much of the original image quality as possible.
The ideal solution is to switch to vector graphics that can be resized at will. Instead of pixel information, they contain mathematical information used to draw or "render" the image. Read more on Wikipedia.
let's try metadata in GDI+, may be it can suit your request
I've been fussing with this for the better part of the night, so maybe one of you can give me a hand.
I have found GDI+ DrawImage in C# to be far too slow for what I'm trying to render, and from the looks of forums, it's the same for other people as well.
I decided I would try using AlphaBlend or BitBlt from the Win32 API to get better performance. Anyway, I've gotten my images to display just fine except for one small detail—no matter what image format I use, I can't get the white background to disappear from my (transparent) graphics.
I've tried BMP and PNG formats so far, and verified that they get loaded as 32bppargb images in C#.
Here's the call I'm making:
// Draw the tile to the screen.
Win32GraphicsInterop.AlphaBlend(graphicsCanvas, destination.X, destination.Y, this.TileSize, this.TileSize,
this.imageGraphicsPointer, tile.UpperLeftCorner.X, tile.UpperLeftCorner.Y,
this.TileSize, this.TileSize,
new Win32GraphicsInterop.BLENDFUNCTION(Win32GraphicsInterop.AC_SRC_OVER, 0,
Convert.ToByte(opacity * 255),
Win32GraphicsInterop.AC_SRC_ALPHA));
For the record, AC_SRC_OVER is 0x00 and AC_SRC_ALPHA is 0x01 which is consistent with what MSDN says they ought to be.
Do any of you guys have a good solution to this problem or know a better (but still fast) way I can do this?
Graphics.DrawImage() speed is critically dependent on the pixel format. Format32bppPArgb is 10 times faster than any other one on any recent machine I've tried.
Also make sure you the image doesn't get resized, be sure to use a DrawImage() overload that sets the destination size equal to the bitmap size. Very important if the video adapter's DPI setting doesn't match the resolution of the bitmap.
Have you tried an opacity of just 255 rather than a calculated one?
This blog post describes what you're trying to do:-
http://blogs.msdn.com/andreww/archive/2007/10/10/preserving-the-alpha-channel-when-converting-images.aspx
Critical thing is that he carries out a conversion of the image to make the alpha channel compatible..
Ok. From a pure Win32 perspective:
In order for AlphaBlend to actually alpha blend... it needs the source device context to contain a selected HBITMAP representing an image with 32bpp bitmap with a pre-multiplied alpha channel.
To get a device bitmap with 32bpp you can either call one of the many functions that will create a screen compatible device bitmap and hope like hell the user has selected 32bpp as the desktop bitdepth. OR, ensure that the source bitmap is a DIBSection. Well, the library or framework that is creating it from the loaded image for you.
So, C# is loading your images with 32bpp argb, BUT, how are you converting that C# representation of the bitmap into a HBITMAP? You need to ensure that a DIB Section is being created, not a DDB (or device dependent bitmap), and that the DIB Section is 32bpp.