C# .NET Dynamic Image Library? - c#

Hi there I am looking to create a image dynamically from an array[500][500] (500x500pixel)
Each array item has the pixel color data,
Does anyone know which .NET library/interface would be best for this? Could point me in right direction? I need to create/save the file.
Also, The image is a composite of the data from many images, I am wondering if it is possible to use various formats, or if I need to first convert the small images into one format,
Also which image format is best to use (the most compatible?) JPG/PNG24? (for web)
Thanks for your input!

if you can use unsafe code in your website (in other words, your code runs under full trust), just use the Bitmap class, and use the LockBits method, then you can use pointers just like in C++ to access the pixels (tip: create a Pixel struct to hold RGB values). You will see GetPixel and SetPixel methods, DO NOT EVER use them. The performance is terrible, more than 100 times slower than using pointers. Just go with BitmapData.Scan0.ToPointer() and then iterate with for.

You could use the System.Drawing.Bitmap class.
If you are able to use unsafe code, construct the bitmap using pointers and BitmapData rather than SetPixel
var bitmap = new Bitmap(500, 500);
// Update the pixels with values in you array...
bitmap.Save("myfilename.jpg", ImageFormat.Jpeg);

The format depends on what you need (for example png can support transaprency, jpg does not).
You could start wich System.Drawing.Bitmap .

Related

DrawImage is slow, lockbits to the rescue?

I've read many C# tutorials on using lockbits to manipulate images, but I just don't know how to apply this info into PowerShell.
This is the problem:
$image1's height is 2950 pixels. $image2's height is 50 px taller, 3000 pixels. I need to fit $image2 into $image1 and I can skip $image2's first 49 px lines. So in pseudocode:
For(y=0... For(x=0.... { image1(x,y) = image2(x,y+50) } ....))
The PowerShell script below works, but does not work very fast:
$rect = new-object Drawing.Rectangle 0, 0, $image1.width, $image1.height
$image1drawing.drawimage($image2,
$rect,
0, 50, $image2.width, ($image2.height - 50),
$graphicalUnit)
The pages I've found, such as this (Not able to successfully use lockbits) or this (https://web.archive.org/web/20121203144033/http://www.bobpowell.net/lockingbits.htm) are in "plain English" but how to convert this concept into PowerShell?
You are using the correct approach. Using DrawImage will be faster that copying the pixels one by one.
Some suggestions to make it faster:
Try using Image.Clone to copy a rectangle from the original image, this will result in the smallest number of objects you need to create.
Make sure you use the same PixelFormat as the original image (faster copying). There is a PixelFormat attribute in Image.
Most important: accessing Width and Height takes a long time so save them to a local variable for reuse. If you know them before hand that's a good way to speed-up things.
Don't expect miracles at a width to height ratio of 4:3 each image is 3932 * 2950 * 3(assuming 24 bit RGB) = 33Mb per image. That's a lot of data, you may easily be be trying to copy a few gigs depending on how many images you have.
You are better off writing a simple cmdlet and using it in your PowerShell script.
BTW in case you are still interested:
Using lockbits in C# (as per your examples) relies on unsafe context and using pointers. I don't believe PowerShell has access to unsafe context.
You can manipulate unmanaged data without using an unsafe context by using the Marshall class; specifically the Read and Write methods (and you might be able to speed things up with the Copy method at expense of memory).
PowerShell was not meant as a replacement for .Net generic languages, that's what CmdLets are for.

How to get one pixel of Image in Windows Store App (C#)

I am writing a game for Windows 8 in C#. I have an Image and I need to check the color of some given pixel. I know coordinates (x, y) of the pixel in Image, but I can not find any class that can do that. For example
System.Drawing.Bitmap has method GetPixel, which would be perfect for me, but I can not use this class in Windows Store apps.
Does anyone know how can I do it? Thanks for any help!
I haven't used it, but you could try the WriteableBitmapEx class. The project page states that the class has a GetPixel method.
If you want to implement this yourself (it is not trivial, and takes quite a few function calls), one way is to use BitmapDecoder to read the bitmap and BitMapDecoder.GetPixelData to get a PixelDataProvider. From there you can get a byte buffer using DetachPixelData. The byte buffer is a one dimensional array in RGBA format. You'll have to map your x and y coordinates to this array.

Generate huge image in C#

I need to create a huge image (aprox 24000 x 22000) with PixelFormat.Format24bppRgb encoding. I know it will barely impossible to open it...
What I'm trying to do is this:
Bitmap final = new Bitmap(width, height, PixelFormat.Format24bppRgb);
As expected, an exception is thrown as I can't handle a 11GB file in memory easy that way.
But I had an idea: could I write the file as I'm generating it? So, instead of working on RAM, I would be working on the HD.
Just to better explain: I have about 13K tiles and I plan to stitch it together in this stupidly humongous file. As I can iterate them in a give order, I thing I could write it down directly to the memory using unsafe code.
Any suggestions?
ImageMagick's Large Image Support (tera-pixel) can help you put the image together once you have the tiles that compose it. You can either use use the command line and issue commands to it using this wrapper or use this ImageMagick.NET as an API.
You could write it in a non-compressed format like BMP. BMP saves raw color bytes in rows. So you would load first row of tiles, read their separate pixel rows and write it as composite single row in output image. This way, you can have open only few tiles and imediately write down the output image.
But I don't know how to write it as compressed image, like JPG or PNG. But I'm sure some specialised software exists for that.
Depending on what you intend to do with this image upon completion, I would suggest dividing it into 4 and working with it that way. I have worked with 10,000 x 10,000 pixels without the OOM exception being thrown.

Color Image Quantization in .NET

I want to reduce the number of unique colors of a bitmap in c#.
The reason I want to do this is that an image which is initially created with three color but due to many factors (including compression) has now more than three colors (i.e neighbour pixels has affected each other)
Any idea of how to do that?
The solution maybe something to convert the whole bitmap from RGB to Indexed color system or some function that can be applied to a single pixel.
Any GDI+ or Emgu (opencv) solutions are good for me.
Check out nQuant at http://nquant.codeplex.com. This yields much higher quality than the code in the MSDN article that Magnus references. It also takes the Alpha layer into consideration while the msdn article only evaluates RGB. Source code is available and there is an accompanying blog post that discusses the code and algorithm in detail.
There is an article on msdn called Optimizing Color Quantization for ASP.NET Images that might help you, it has good example code.
I've just stumbled upon this question and though it is quite an old one maybe it still can be useful to mention that last year I made my Drawing Libraries public (NuGet), which happens to support quantization, too.
Note: As the question contains the GDI+ tag the examples below go for the Bitmap type but the library supports completely managed bitmap data manipulation as well, which supports all pixel formats on every platform (see BitmapDataFactory and BitmapDataExtensions classes).
If you have a Bitmap instance, quantization is as simple as follows:
using System.Drawing;
using System.Drawing.Imaging;
using KGySoft.Drawing;
using KGySoft.Drawing.Imaging;
// [...]
IQuantizer quantizer = PredefinedColorsQuantizer.FromCustomPalette(myColors, backColor);
// getting a quantized clone of a Bitmap with arbitrary PixelFormat:
Bitmap quantizedBitmap = originalBitmap.ConvertPixelFormat(PixelFormat.Format8bppIndexed,
quantizer);
// or, you can quantize a Bitmap in-place (which does not change PixelFormat):
originalBitmap.Quantize(quantizer);
Original bitmap:
Quantized bitmap using a custom 8 colors palette and silver background (which appears white with this palette):
In the example above I used the FromCustomPalette method but there are many other predefined quantizers available in the PredefinedColorsQuantizer and OptimizedPaletteQuantizer classes (see the members for image and code examples).
And since reducing colors may severely affect the quality of the result you might want to use dithering with the quantization:
IQuantizer quantizer = PredefinedColorsQuantizer.FromCustomPalette(myColors, backColor);
IDitherer = OrderedDitherer.Bayer8x8;
// ConvertPixelFormat can be used also with a ditherer
Bitmap quantizedBitmap = originalBitmap.ConvertPixelFormat(PixelFormat.Format8bppIndexed,
quantizer, ditherer);
// Or use the Dither extension method to change the Bitmap in-place
originalBitmap.Dither(quantizer, ditherer);
The difference is quite significant, even though the same colors are used:
You will find a lot of image examples in the description of the OrderedDitherer, ErrorDiffusionDitherer, RandomNoiseDitherer and InterleavedGradientNoiseDitherer classes.
To try the possible built-in quantizers and ditherers in an application you can use my Imaging Tools app. In the link you can find also its source, which provides a bit more advanced examples with cancellable async conversions with progress tracking, etc.

C#, Bitmap, r8g8b8 and b5g6r5 pixel data

I am extracting r8g8b8 palette from file, looks like its very easy to convert it to System.Drawing.Color struct and then fill Bitmap by using SetPixel method.
But then i've encountered b5g6r5 palette and now i don't know what to do. Is there any way to fill Bitmap class with that kind of data?
Happy new year!
Have you considered converting BGR565 to RGB888 (as described in the answers here) and then do what you did with your RGB888 values?

Categories