I'm writing a service for a project that's going to handle our image processing. One such process is supposed to strip all metadata from the byte[] provided and return the same image as a byte[].
The method I'm currently working on involves always converting the image to a Bitmap, then converting it back to the original format and returning the data from a MemoryStream.
I haven't been able to test it yet but something tells me I'm going to experience some quality loss.
How can I remove all metadata from any image with a common format?
(bmp, gif, png, jpg, icon, tiff)
Not sure how I can narrow that down any further. Would be nice if I got some feedback regarding the downvotes.
For the lossless formats (except JPEG), your idea of loading it as a bitmap and re-saving is fine. Not sure if .NET natively supports TIFFs (I doubt it does).
For JPEGs, as you suggested there may be quality loss if you're re-compressing the file after decompressing it. For that, you might try the ExifLibrary and see if that has anything. If not, there are command line tools (like ImageMagick) that can strip metadata. (If you use ImageMagick, you're all set, since it supports all of your required formats. The command you want is convert -strip.)
For TIFFs, .NET has built-in TiffBitmapDecoder and ...Encoder classes you might be able to use; see here.
In short, using an external tool like ImageMagick is definitely the easiest solution. If you can't use an external tool, you're almost certainly going to need to special-case the formats that .NET doesn't support natively (and the lossy JPEG).
EDIT: I just read that ImageMagick doesn't do lossless stripping with JPEGs, sorry. I guess using the library I linked above, or some other JPEG library, is the best I can think of.
Related
I am using C# and want to save images using JPEG format. However .NET reduces quality of the images and saves them with compression that is not enough.
I want to save files with their original quality and size. I am using the following code but compression and quality are not like the original ones.
Bitmap bm = (Bitmap)Image.FromFile(FilePath);
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
ImageCodecInfo ici = null;
foreach (ImageCodecInfo codec in codecs)
{
if (codec.MimeType == "image/jpeg")
ici = codec;
}
EncoderParameters ep = new EncoderParameters();
ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)100);
bm.Save("C:\\quality" + x.ToString() + ".jpg", ici, ep);
I am archiving studio photos and quality and compression is very important. Thanks.
The .Net encoder built-in to the library (at least the default Windows library provided by Microsoft) is pretty bad:
http://b9dev.blogspot.com/2013/06/nets-built-in-jpeg-encoder-convenient.html
Partial Update
I'm now using an approach outlined here, that uses ImageMagick for the resize then jpegoptim for the final compression, with far better results. I realize that's a partial answer but I'll expand on this once time allows.
Older Answer
ImageMagick is the best choice I've found so far. It performs relatively solid jpeg compression.
http://magick.codeplex.com/
It has a couple downsides:
It's better but not perfect. In particular, its Chroma subsampling is set to high detail at 90% or above, then jumps down to a lower detail level - one that can introduce a lot of artifacts. If you want to ignore subsampling, this is actually pretty convenient. But if you wanted high-detail subsampling at say, 50%, you have a larger challenge ahead. It also still won't quite hit quality/compression levels of Photoshop or Google PageSpeed.
It has a special deployment burden on the server that's very easy to miss. It requires a Visual Studio 2008 SDK lib installed. This lib is available on any dev machine with Visual Studio on it, but then you hit the server for the first time and it implodes with an obscure error. It's one of those lurking gotchas most people won't have scripted/automated, and you'll trip over it during some future server migration.
Oldest Answer
I dug around and came across a project to implement a C# JPEG encoder by translating a C project over:
http://www.codeproject.com/Articles/83225/A-Simple-JPEG-Encoder-in-C
which I've simplified slightly:
https://github.com/b9chris/ArpanJpegEncoder
It produces much higher quality JPEGs than the .Net built-in, but still is not as good as Gimp's or Photoshop's. Filesizes also tend to be larger.
BitMiracle's implementation is practically identical to the .Net built-in - same quality problems.
It's likely that just wrapping an existing open source implementation, like Google's jpeg_optimizer in PageSpeed Tools - seemingly libjpeg underneath, would be the most efficient option.
Update
ArpanJpegEncoder appears to have issues once it's deployed - maybe I need to increase the trust level of the code, or perhaps something else is going on. Locally it writes images fine, but once deployed I get a blank black image from it every time. I'll update if I determine the cause. Just a warning to others considering it.
It looks like you're setting the quality to 100%. That means that there will be no compression.
If you change the compression level (80, 50, etc.) and you're unsatisifed with the quality, you may want to try a different image library. LEADTools has a good (non-free) engine.
UPDATE: As a commenter mentioned, 100% quality still does not mean lossless compression when using JPEG. Loading the image, doing something to it, and then saving it again will ultimately result in image degradation. If you need to alter and save an image without losing any of the data you need to use a lossless format such as TIFF, PNG or BMP. I'd go with compressed TIFF (since it's still lossless even though it's compressed) or PNG.
Compression and quality are always a trade off.
JPEGs are always going to be lossy.
You may want to consider using PNG and minifying the files using PNGCrush or PNGauntlet
Regarding the setup of the compression level in .NET, please check this link (everything included): http://msdn.microsoft.com/en-us/library/bb882583.aspx
Rearding your question:
Usually you will save the uploaded image from users as PNG, then you use this PNG as base to generate your JPGs with different sizes (and you put a watermark ONLY on the JPGs, never on the original PNG!)
Advantage of this is: if you change your images-dimensions later on for your platform, you have the original PNG saved and based on this you can re-compute any new image sizes.
It must save the file like its orjinal quality and size
That doesn't make a lot of sense. When you are using lossy compression you are going to lose some information by definition. The point of compressing an image is to reduce the file size. If you need high quality and jpeg isn't doing it for you you may have to go with some type of lossless compression, but your file sizes will not be reduced by much. You could always try using the 'standard' library for compressing to jpeg (libjpeg) and see if that gives you any different results (I doubt it, but I don't know what .NET is using under the hood.)
Compressing the jpeg format by its very nature reduces quality. Perhaps you should look into file compression, such as #ziplib. You may be able to get a reasonable compression over a group of files.
I've developed a Silverlight application that needs to compress JPEG images on the client. I've been using a library called FJCore to achieve this goal.
One of the biggest issues I'm encountering, however, is the fact that this toolkit requires you to convert the JPEG to a WriteableBitmap first which strips off all the metadata associated with the JPEG such as EXIF, XMP, JFIF, etc. I've modified the source of the FJCore library to persist the EXIF, compress the image, and then reattach the EXIF data. This process works but loses other types of metadata information.
Instead of having to implement a function that saves and writes each different type of metadata that exists for the JPEG format, I am looking for a simplified approach that will allow me to extract all metadata, regardless of type or format, use the FJCore toolkit to compress/resize that image, and then reattach all the previously saved metadata. Some direction or sample code that could help me achieve my goal would be greatly appreciated. Remember, this is a Silverlight application, so those .NET libraries are what I have to work with.
Thank you.
You can do this using FJCore aka ImageTools. All you need to do is add this on line 212:
// Exif. Do something?
headers.Add(header);
https://github.com/briandonahue/FluxJpeg.Core/blob/master/FJCore/Decoder/JpegDecoder.cs
And make sure you copy those headers when resizing:
jpegOut = new DecodedJpeg(
new ImageResizer(jpegIn.Image)
.Resize(320, ResamplingFilters.NearestNeighbor),
jpegIn.MetaHeaders); // Retain EXIF details
Recompile and you should be good to go.
I searched on how to check if a TIFF file is corrupt or not. Most suggests wrapping the Image.FromFile function in a try block. If it throws an OutOfMemoryException, its corrupt. Has anyone used this? Is it effective? Any alternatives?
Please check out the freeware called LibTiff .NET. It has the function to check if every page in a TIF file is corrupted or not. Even partially corrupt also no problem
http://bitmiracle.com/libtiff/
Thanks
Many tiff files won't open in the standard GDI+ .NET. That is, if you're running on Windows XP. Window 7 is much better. So any file which is not supported by GDI+ (i.e. fax, 16 bit gray scale, 48bpp RGB, tiled tiff, piramidical tiled tiff etc.) are then seen as 'corrupt'. And not just that, anything resulting in a bitmap over a few 100 MByte on a 32-bit system will also cause an out-of-memory exception.
If your goal is to support as much as possible of the TIFF standard, please start from LibTiff (derivates). I've used LibTiff.NET from BitMiracle (LGPL), which worked well for me. Please see my other posts
Many of the TIFF utilities are also based on LibTIFF, some of them are ported to C#.NET. This would be my suggestion if you want to validate the TIFF.
As for the TIFF specification suggested in other replies: of course this gives you bit-level control. But to my experience you won't need to go that low to have good TIFF support. The format is so versatile that it will cost you an enormous amount of time to start support from scratch.
It will only be corrupt in the sense that the frameworks methods cant open it.
There are some TIFF types that the framework cannot open -( In my case I cant remember the exact one, think it was one of the FAX type ones...)
That may be enough for you, if you are just looking a using the framework to manipulate images. After all I you cant open it, you cant use it...
ImageMagic - may give you more scope here
Without looking at the tiff, it may be difficult to see if its corrupt from a visual perspective, but if you have issues with processing an image, just create a function that does a basic test for this type of processing and handle the error?
I am using C# and want to save images using JPEG format. However .NET reduces quality of the images and saves them with compression that is not enough.
I want to save files with their original quality and size. I am using the following code but compression and quality are not like the original ones.
Bitmap bm = (Bitmap)Image.FromFile(FilePath);
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
ImageCodecInfo ici = null;
foreach (ImageCodecInfo codec in codecs)
{
if (codec.MimeType == "image/jpeg")
ici = codec;
}
EncoderParameters ep = new EncoderParameters();
ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)100);
bm.Save("C:\\quality" + x.ToString() + ".jpg", ici, ep);
I am archiving studio photos and quality and compression is very important. Thanks.
The .Net encoder built-in to the library (at least the default Windows library provided by Microsoft) is pretty bad:
http://b9dev.blogspot.com/2013/06/nets-built-in-jpeg-encoder-convenient.html
Partial Update
I'm now using an approach outlined here, that uses ImageMagick for the resize then jpegoptim for the final compression, with far better results. I realize that's a partial answer but I'll expand on this once time allows.
Older Answer
ImageMagick is the best choice I've found so far. It performs relatively solid jpeg compression.
http://magick.codeplex.com/
It has a couple downsides:
It's better but not perfect. In particular, its Chroma subsampling is set to high detail at 90% or above, then jumps down to a lower detail level - one that can introduce a lot of artifacts. If you want to ignore subsampling, this is actually pretty convenient. But if you wanted high-detail subsampling at say, 50%, you have a larger challenge ahead. It also still won't quite hit quality/compression levels of Photoshop or Google PageSpeed.
It has a special deployment burden on the server that's very easy to miss. It requires a Visual Studio 2008 SDK lib installed. This lib is available on any dev machine with Visual Studio on it, but then you hit the server for the first time and it implodes with an obscure error. It's one of those lurking gotchas most people won't have scripted/automated, and you'll trip over it during some future server migration.
Oldest Answer
I dug around and came across a project to implement a C# JPEG encoder by translating a C project over:
http://www.codeproject.com/Articles/83225/A-Simple-JPEG-Encoder-in-C
which I've simplified slightly:
https://github.com/b9chris/ArpanJpegEncoder
It produces much higher quality JPEGs than the .Net built-in, but still is not as good as Gimp's or Photoshop's. Filesizes also tend to be larger.
BitMiracle's implementation is practically identical to the .Net built-in - same quality problems.
It's likely that just wrapping an existing open source implementation, like Google's jpeg_optimizer in PageSpeed Tools - seemingly libjpeg underneath, would be the most efficient option.
Update
ArpanJpegEncoder appears to have issues once it's deployed - maybe I need to increase the trust level of the code, or perhaps something else is going on. Locally it writes images fine, but once deployed I get a blank black image from it every time. I'll update if I determine the cause. Just a warning to others considering it.
It looks like you're setting the quality to 100%. That means that there will be no compression.
If you change the compression level (80, 50, etc.) and you're unsatisifed with the quality, you may want to try a different image library. LEADTools has a good (non-free) engine.
UPDATE: As a commenter mentioned, 100% quality still does not mean lossless compression when using JPEG. Loading the image, doing something to it, and then saving it again will ultimately result in image degradation. If you need to alter and save an image without losing any of the data you need to use a lossless format such as TIFF, PNG or BMP. I'd go with compressed TIFF (since it's still lossless even though it's compressed) or PNG.
Compression and quality are always a trade off.
JPEGs are always going to be lossy.
You may want to consider using PNG and minifying the files using PNGCrush or PNGauntlet
Regarding the setup of the compression level in .NET, please check this link (everything included): http://msdn.microsoft.com/en-us/library/bb882583.aspx
Rearding your question:
Usually you will save the uploaded image from users as PNG, then you use this PNG as base to generate your JPGs with different sizes (and you put a watermark ONLY on the JPGs, never on the original PNG!)
Advantage of this is: if you change your images-dimensions later on for your platform, you have the original PNG saved and based on this you can re-compute any new image sizes.
It must save the file like its orjinal quality and size
That doesn't make a lot of sense. When you are using lossy compression you are going to lose some information by definition. The point of compressing an image is to reduce the file size. If you need high quality and jpeg isn't doing it for you you may have to go with some type of lossless compression, but your file sizes will not be reduced by much. You could always try using the 'standard' library for compressing to jpeg (libjpeg) and see if that gives you any different results (I doubt it, but I don't know what .NET is using under the hood.)
Compressing the jpeg format by its very nature reduces quality. Perhaps you should look into file compression, such as #ziplib. You may be able to get a reasonable compression over a group of files.
I have a raw pixel data in a byte[] from a DICOM image.
Now I would like to convert this byte[] to an Image object.
I tried:
Image img = Image.FromStream(new MemoryStream(byteArray));
but this is not working for me. What else should I be using ?
One thing to be aware of is that a dicom "image" is not necessarily just image data. The dicom file format contains much more than raw image data. This may be where you're getting hung up. Consider checking out the dicom file standard which you should be able to find linked on the wikipedia article for dicom. This should help you figure out how to parse out the information you're actually interested in.
You have to do the following
Identify the PIXEL DATA tag from the file. You may use FileStream to read byte by byte.
Read the pixel data
Convert it to RGB
Create a BitMap object from the RGB
Use Graphics class to draw the BitMap on a panel.
The pixel data usually (if not always) ends up at the end of the DICOM data. If you can figure out width, height, stride and color depth, it should be doable to skip to the (7FE0,0010) data element value and just grab the succeeding bytes. This is the trick that most normal image viewers use when they show DICOM images.
There is a C# library called EvilDicom (http://rexcardan.com/evildicom/) that can be used to pull the image out of a DICOM file. It has a tutorial on how to do it on the website.
You should use GDCM.
Grassroots DiCoM is a C++ library for DICOM medical files. It is automatically wrapped to python/C#/Java (using swig). It supports RAW, JPEG 8/12/16bits (lossy/lossless), JPEG 2000, JPEG-LS, RLE and deflated (zlib).
It is portable and is known to run on most system (Win32, linux, MacOSX).
http://gdcm.sourceforge.net/wiki/index.php/GDCM_Release_2.4
See for example:
http://gdcm.sourceforge.net/html/DecompressImage_8cs-example.html
Are you working with a pure standard DICOM File? I've been maintainning a DICOM parser for over a two years and I came across some realy strange DICOM files that didn't completely fulfill the standard (companies implementing their "own" twisted standard DICOM files) . flush you byte array into a file and test whether your image viewer(irfanview, picassa or whatever) can show it. If your code is working with a normal JPEG stream then from my experience , 99.9999% chance that this simply because the file voilate the standard in some strange way ( and believe me , medical companies does that a lot)
Also note that DICOM standard support several variants of the JPEG standard . could be that the Bitmap class doesn't support the data you get from the DICOM file. Can you please write down the transfer syntax?
You are welcome to send me the file (if it's not big) yossi1981#gmail.com , I can check it out , There was a time I've been hex-editing DICOM file for a half a year.
DICOM is a ridiculous specification and I sincerely hope it gets overhauled in the near future. That said Offis has a software suite "DCMTK" which is fairly good at converting dicoms with the various popular encodings. Just trying to skip ahead in the file x-bytes will probably be fine for a single file but if you have a volume or several volumes a more robust strategy is in order. I used DCMTK's conversion code and just grabbed the image bits before they went into a pnm. The file you'll be looking for in DCMTK is dcm2pnm or possibly dcmj2pnm depending on the encoding scheme.
I had a problem with the scale window that I fixed with one of the runtime flags. DCMTK is open source and comes with fairly simple build instructions.