Maybe this is a very easy problem to solve but I haven't found the perfect solution yet.
I'm trying to convert a png to ico with C# and found the question converting .PNG to .ICO in C/C# which sort of gives a working solution as below:
using (FileStream stream = File.OpenWrite(#"C:\temp\test.ico"))
{
Bitmap bitmap = (Bitmap)Image.FromFile(#"c:\temp\test.png");
Icon.FromHandle(bitmap.GetHicon()).Save(stream);
}
For my own project I have changed this approach slightly to:
string pngFile = "path/to/pngfile";
using (Bitmap bitmap = new Bitmap(pngFile))
{
using (Icon icon = Icon.FromHandle(bitmap.GetHicon()))
{
using (MemoryStream stream = new MemoryStream())
{
icon.Save(stream);
// something interesting with icon here
}
}
}
The problem that I am experiencing is that the resulting ico is of poor quality, I'm guessing it got resized to 16x16 and lost some of it's color depth, perhaps now only has 16 colors? How can I convert to a higher quality ico file?
I believe you will need a more robust method than GetHIcon(). It is more of a "quick and dirty" option, and by no means loss-less.
Here's an example of a class that can preserve image quality on the way to converting as ICO:
https://gist.github.com/darkfall/1656050
Check http://www.codeproject.com/Tips/627823/Fast-and-high-quality-Bitmap-to-icon-converter
This is a clear and fast solution to convert a bitmap to png
In the referenced question the accepted solution uses imagemagick, which is a great image manipulation tool that gives you have the ability to control size, colour depth etc. when converting from png to ico. I would really suggest trying that solution.
Using the imagemagick utility would look something like
convert -resize x16 -gravity center -crop 16x16+0+0 input.png \
-flatten -colors 256 output/favicon.ico
(you could then control -resize and -colors to achieve what you are looking for.)
The same options should be available programmatically in C# through http://imagemagick.codeplex.com
Related
I have an image https://drive.google.com/file/d/16Xotc-2CJ6HkEJDysfKBkjClkU1OGiyQ/view?usp=sharing that is GrayScale but every library I have tried, ImageMagick, ImageSharp, System.Drawing seem to interpret it as black and white, but when you open it in ImageJ or Photoshop or Incarta or many other software you can clearly see it is grayscale.
can anyone help me find a way to display this image? here is something I've tried but i've tried almost a dozen different things
TiffEncoder encoder = new TiffEncoder();
encoder.PhotometricInterpretation = SixLabors.ImageSharp.Formats.Tiff.Constants.TiffPhotometricInterpretation.BlackIsZero;
SixLabors.ImageSharp.Image image = SixLabors.ImageSharp.Image.Load(mysteryTiff);
PixelTypeInfo pixType = image.PixelType;
// Stretches the image to fit the pictureBox.
Stream stream = new MemoryStream();
image.SaveAsTiff(stream, encoder);
stream.Position = 0;
MagickImage magickImage = new MagickImage(stream);
pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
pictureBox1.ClientSize = new System.Drawing.Size(1200, 1200);
pictureBox1.Image = magickImage.ToBitmap();
Can anyone display this image correctly. It will display correctly when uploaded to
What you have there, according to the image tag directory, is a 2024x2024 16-bpp greyscale LZW-compressed extended TIFF. It even opens in some software, which proves that it's not malformed. So far so good.
Now here's where it breaks down: 16-bpp greyscale is not supported by a lot of things. The 'why' is mildly convoluted, having to do largely with "but we all use 8 bits per channel, and so does the hardware, so why bother", but the end result isn't: if you want to use anything above 8 bits per channel, you'll either have to find something that will do the work for you or convert the data to 8-bpp at some point.
Even when the file format explicitly support 16-bpp greyscale (TIFF and PNG for instance), most libraries tend not to support either read or write in that format because it is so rarely used that they don't bother to implement it. I ended up writing my own PNG encoder for 16-bpp greyscale images (converted from 12-bpp and 16-bpp XRAY images), but the images aren't viewable in most programs that supposedly support the full PNG standard.
In this case your best option is probably going to be to write a conversion of your own for this type of file. Assuming that the same format (16-bpp, LZW-compressed) is produced by the source application every time, it shouldn't be too difficult to convert the pixel buffer to 8-bpp and save out as TIFF, PNG or whatever you like. You'll lose half of your greyscale (depth) resolution, but for display purposes they're not going to help much anyway. It only really matters when there's a good reason to retain the full range of values.
Using SFML, I can render about any picture format using the following code:
SFML.Graphics.Image img = new SFML.Graphics.Image("pic.bmp");
SFML.Graphics.Texture tex = new Texture(img);
SFML.Graphics.Sprite sprite = new Sprite(tex);
renderWindow.Draw(sprite);
But this is not working correctly with a few bitmaps (files with .bmp extension) which are formatted in 8 bits (256 colors). It looks like the SFML lib is attempting to read it in 16 or 32 bits.
Is there something to fix this situation?
Update: I have opened problematic bmp files with paint and just saved them in the same format (8bits), then SFML became able to display those properly. But this is only a test and I can't do it using paint, I need a code-only solution.
If resaving the files again in a different application fixes the issue, then this sounds to me like you have a special format that's not supported by stb_image and thus isn't supported by SFML.
I highly recommend to use the PNG format, as it supports proper transparency and uses a loss-less compression.
A little bit of background:
I'm writing a bar code image scanner desktop app using WPF, that can take input from either a file location (previously scanned image) or have it come directly from a scanner (using NTWAIN). In both cases I create or get a stream.
Now when I create a new Bitmap from the stream and save it as a JPEG file using an Encoder
using (var bmp = Image.FromStream(rawStream))
{
EncoderParameter ratio = new EncoderParameter(Encoder.Quality, 100L);
EncoderParameter depth = new EncoderParameter(Encoder.ColorDepth, 8L);
EncoderParameters codecParams = new EncoderParameters(2);
codecParams.Param[0] = ratio;
codecParams.Param[1] = depth;
ImageCodecInfo jpegCodecInfo = ImageCodecInfo.GetImageEncoders().FirstOrDefault(x => x.FormatID == ImageFormat.Jpeg.Guid);
bmp.Save(file.FileFullPath, jpegCodecInfo, codecParams); // Save to JPG
}
or the built in
bmp.Save(file.FileFullPath, ImageFormat.Jpeg);
I tend to end up with much larger file sizes. Of course, this isn't always the case, but definately true when I'm loading a small black and white tiff file into memory and encoding as jpg.
My knowledge on image handling is rudimentary, but I think it is because the jpg files are saved with a color depth of 24 bits and the tiff images are originally stored as 1 bit. (Black and white)
No matter what I do, I can't get the jpg files to match the original file's bit depth.
The only work around I found is simply renaming the file to "filename.jpg" and saving like so
using (Bitmap bmp = new Bitmap(rawStream))
{
Save(file.FileFullPath);
}
But this feels like a solution that won't work indefinitely (as a side question, can one simply rename any *.bmp or *tiff file to *.jpg and it will still work?)
Based on my initial research it seems like
bmp.Save()
doesn't honor the encoding parameter for bit depth in jpeg images. Understandably my clients won't be happy having files grow from 16kb to 200kb for "no reason".
Is there a known work around for this problem or am I missing something obvious when it comes to working with streams and images?
JPEG works best for photographs with a multitude of colors, shades and gradients. Typical bit-depths: 8 (for greyscale) or 24 (for full color).
If you want monochrome (1-bit), I'd recommend agains using JPEG, not least because JPEG will introduce encoding artifacts that may not matter for photographs, but which will look like "added pepper and salt" if your original source is 1-bit. And the more you compress them, the more it will be there.
You should try using PNG instead, it has no such artifacts, and is better suited for digital sources with sharp edges.
You could also try making the TIFF smaller by 50% or 75% using a smart resize algorithm (using e.g. 8-bit output) that will convert micro-dots in the original into small gradients in the output. I did so long ago with 1-bit fax/scanner images, with actually quite good results. But too long to still have those sources.
The title pretty much explains my question. I would like to be able to read and write JPEG data on a per-pixel basis using C#.
I'm thinking something along the lines of CreateJPEG(x, y) which would set up a blank JPEG image in memory, and would give me a JPEG object, and then something like SetPixel(x, y, Color) and GetPixel(x, y) the latter of which would return a Color or something similar. You could then call an Apply() or Save() method, for example, to save the image in a standard JPEG-readable format (preferrably with compression options, but that's not necessary).
And I'm assuming some C# library or namespace makes this all a very easy process, I'd just like to know the best way to go about it.
Have a look at the Bitmap class. For advanced drawing besides manipulating single pixel you will have to use the Graphics class.
var image = new Bitmap("foo.jpg");
var color = image.GetPixel(1, 2);
image.SetPixel(42, 42, Color.White);
image.Save("bar.jpg", ImageFormat.Jpeg);
As Lasse V. Karlsen mentions in his answer this will not really manipulate the JPEG file. The JPEG file will be decompressed, this image data will be altered, and on saving a new JPEG file is created from the altered image data.
This will lower the image quality because even recompressing an unaltered image does usually not yield a bit-identical JPEG file due to the nature of lossy JPEG compressions.
There are some operations that can be performed on JPEG files without decompressing and recompressing it - for example rotating by 90° - put manipulating single pixels does not fit in this category.
JPEG is not a processing format, it's a storage format.
As such, you don't actually use a JPEG image in memory, you just have an image. It's only when you store it that you pick the format, like PNG or JPEG.
As such, I believe you're looking for the Bitmap class in .NET.
I am attempting to open .tif files that have color in them (300 dpi, PixelFormat.Format24bppRgb) using the .Net Image and Bitmap classes. I always get an "invalid parameter" error when the tiffs have color (works fine for black and white tiffs). If anyone has source code on how to open a .tif with color in it I'd deeply appreciate it. Below is what I'm attempting to do; this also fails when calling Bitmap.FromStream:
using (FileStream fs = File.OpenRead(fileName))
{
using (Image img = Image.FromStream(fs)) {}
}
The reason why you can't open the image file is that the image maybe has compression format.
I also encounter this problem when I open a .gif image file.
I'm searching the solutions.
We can communicate each other.
showlie#163.com
thanks
I think the basic problem is that one cannot use the .Net Image/Bitmap classes to reliably open color TIFFs. Many of the various compression formats used to encode color TIFFs break the .Net Image/Bitmap class.
It seems to be a catch 22--you have to know the TIFF formatting information to know how to load it, but in .Net one needs to load the Image/Bitmap class to read TIFF formatting information.
I think the answer to my question is, "this can't be done just using the .Net framework," and that I'll need to either buy a 3rd party control or create something myself in C++.
I found the GDI(+) the limiting factor in dealing with TIFF. I had many "invalid parameter" issues on XP (in my case because of using 16bpp grayscale and tiled tiff). The same code worked flawlessly on Windows7/64bit.
For me, the free LibTIFF.NET was the solution. (StackOverflow using LibTIFF from c#) Only con compared to GDI+: you'll have to roll your own BMP (uncompressed byte array to bmp conversion). I can provide you with examples if you like.
To diagnose your TIFF file type, you could use TiffDump download link
Using like tiffdump myfile.tif will produce an output like:
Magic: 0x4949 <little-endian> Version: 0x2a
Directory 0: offset 1669857288 (0x63880008) next 0 (0)
ImageWidth (256) SHORT (3) 1<33227>
ImageLength (257) SHORT (3) 1<24986>
BitsPerSample (258) SHORT (3) 1<16>
Compression (259) SHORT (3) 1<1>
Photometric (262) SHORT (3) 1<1>
FillOrder (266) SHORT (3) 1<1>
SamplesPerPixel (277) SHORT (3) 1<1>
XResolution (282) RATIONAL (5) 1<6400>
YResolution (283) RATIONAL (5) 1<6400>
PlanarConfig (284) SHORT (3) 1<1>
ResolutionUnit (296) SHORT (3) 1<2>
TileWidth (322) SHORT (3) 1<256>
TileLength (323) SHORT (3) 1<256>
Most likely such info can get you more specifc answers on StackOverflow.