Change TIFF palette from 8 bit into 32 bit - c#

I have some set of TIFF files (8-bit palette). I need to change the bit depth into 32 bit.
I tried the code below, but getting an error, that the parameter is not correct... Could you help me to fix it? Or maybe some1 is able to suggest some different solution for my problem.
public static class TiffConverter
{
public static void Convert8To32Bit(string fileName)
{
BitmapSource bitmapSource;
using (Stream imageStreamSource = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
TiffBitmapDecoder decoder = new TiffBitmapDecoder(imageStreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
bitmapSource = decoder.Frames[0];
}
using (FileStream stream = new FileStream(fileName, FileMode.OpenOrCreate))
{
ImageCodecInfo tiffCodec = ImageCodecInfo.GetImageEncoders().FirstOrDefault(codec => codec.FormatID.Equals(ImageFormat.Tiff.Guid));
if (tiffCodec != null)
{
Image image = BitmapFromSource(bitmapSource);
EncoderParameters parameters = new EncoderParameters();
parameters.Param[0] = new EncoderParameter(Encoder.ColorDepth, 32);
image.Save(stream, tiffCodec, parameters);
}
}
}
private static Bitmap BitmapFromSource(BitmapSource bitmapSource)
{
Bitmap bitmap;
using (MemoryStream outStream = new MemoryStream())
{
BitmapEncoder enc = new BmpBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(bitmapSource));
enc.Save(outStream);
bitmap = new Bitmap(outStream);
}
return bitmap;
}
}
Thanks in advance!
[edit]
I noticed that the error appears in this line:
image.Save(stream, tiffCodec, parameters);
ArgumentException occured: Parameter is not valid.

If the error you're getting is on the line:
parameters.Param[0] = new EncoderParameter(Encoder.ColorDepth, 32);
then the problem is that the compiler cannot know if you're referring System.Text.Encoder or System.Drawing.Imaging.Encoder...
Your code should look like this to to avoid any ambiguity:
parameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.ColorDepth, 32);
Edit:
This is an alternative (and tested :)) way of doing the same thing:
Image inputImg = Image.FromFile("input.tif");
var outputImg = new Bitmap(inputImg.Width, inputImg.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
using (var gr = Graphics.FromImage(outputImg))
gr.DrawImage(inputImg, new Rectangle(0, 0, inputImg.Width, inputImg.Height));
outputImg.Save("output.tif", ImageFormat.Tiff);

Related

Memory Leak in C# when compress image

I try to compress ImageSource with MagickImage in memory. But it consumes too much memory. With VS performance tool, every call of this method with consume a lot of memory. It should take 0Mb once it exists, right?
internal static System.Windows.Media.ImageSource compressImage(System.Windows.Media.ImageSource ims)
{
using (MemoryStream stream = new MemoryStream())
{
using (MemoryStream outS = new MemoryStream())
{
BitmapSource bs = ims as BitmapSource;
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
BitmapFrame bf = BitmapFrame.Create(bs);
//encoder.Frames.Add(BitmapFrame.Create(image1.Source));
encoder.Frames.Add(bf);
encoder.Save(stream);
stream.Flush();
try
{
// Read first frame of gif image
using (MagickImage image = new MagickImage(stream))
{
image.Quality = 75;
image.Resize(new Percentage(0.65));
image.Density = new Density(200, DensityUnit.PixelsPerInch);
image.Write(outS);
}
stream.Close();
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
outS.Position = 0;
bitmap.StreamSource = outS;
//
bitmap.EndInit();
//bitmap.Freeze();
outS.Flush();
outS.Close();
ims = null;
return bitmap;
}
catch (Exception e)
{
return null;
}
}
}
}
}
Since Image is stored in memory pixel by pixel. It will consume much memory depends on its size.
Specifying its size will reduce much memory.
bitmap.DecodePizelWidth = 800;

Convert bitmap to ImageSource give NullReference exception

I've got WCF service to send image as a stream to client app.
My client app gets the stream :
Stream imageStream = client.GetImage();
When I use this code:
imageStream.CopyTo(stream);
int size = (int)stream.Length;
stream.Seek(0, SeekOrigin.Begin);
BitmapFrame bf = BitmapFrame.Create(stream,
BitmapCreateOptions.None,
BitmapCacheOption.OnLoad);
cam_img.Source = bf;
It work's fine but I need apply some filters to image before assign to source.
So I need bitmap. First, I convert Stream imageStream to byte array and then I use some code I find on forums:
byte[] tab_img;
using (var memoryStream = new MemoryStream())
{
imageStream.CopyTo(memoryStream);
tab_img= memoryStream.ToArray();
}
Bitmap bm;
using (MemoryStream mStream = new MemoryStream())
{
mStream.Write (tab_img, 0, tab_img.Length);
mStream.Seek(0, SeekOrigin.Begin);
bm = new Bitmap(mStream);
Grayscale filter = new Grayscale(0.2125, 0.7154, 0.0721);
Bitmap bm_post = filter.Apply(bm);
ImageSourceConverter c = new ImageSourceConverter();
object source = new ImageSourceConverter().ConvertFrom(bm_post);
ImageSource is1 = (ImageSource)source;
cam_img.Source = is1;
}
but I still get NullReferenceException in line
object source = new ImageSourceConverter().ConvertFrom(bm_post);

MemoryTributary GetBuffer

My application is MVC5 C#, I use memorystream to generate images using the following:
using (var memStream = new MemoryStream())
{
const int quality = 90;
var encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, (long)quality);
objImage.Save(memStream, GetImageCodeInfo("image/png"), encoderParameters);
data = this.File(memStream.GetBuffer(), "image/png");
memStream.Dispose();
}
However I get OutOfMemoryException with some files. I was reading about MemoryTributary but could not find a solution to GetBuffer! Would appreciate your suggestions.
How about leaving all the buffer stuff out?
var memStream = new MemoryStream();
const int quality = 90;
var encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, (long)quality);
objImage.Save(memStream, GetImageCodeInfo("image/png"), encoderParameters);
memStream.Seek(0, SeekOrigin.Begin);
return File(memStream, "image/png");
The FileStreamResult will dispose the MemoryStream, no need to worry about that.

Convert raw images to bitmap in c#

My code currently looks like this:
if (fe == "CR2")
{
Image img = null;
byte[] ba = File.ReadAllBytes(open.FileName);
using (Image raw = Image.FromStream(new MemoryStream(ba)))
{
img = raw;
}
Bitmap bm = new Bitmap(img);
pictureBox1.Image = bm;
statusl.Text = fe;
}
When I open a RAW image the program stops and Visual Studio says:
Parameter is not valid: Image raw = Image.FromStream(new MemoryStream(ba))
Please help! How can I get a RAW file to show in a PictureBox ?
Create the bitmap like this:
Bitmap bmp = (Bitmap) Image.FromFile(open.FileName);
or without using bitmap:
this.pictureBox1.Image = Image.FromFile(open.FileName);
Example WPF:
BitmapDecoder bmpDec = BitmapDecoder.Create(new Uri(origFile),
BitmapCreateOptions.DelayCreation, BitmapCacheOption.None);
BitmapEncoder bmpEnc = new BmpBitmapEncoder();
bmpEnc.Frames.Add(bmpDec.Frames[0]);
Stream ms = new MemoryStream();
bmpEnc.Save(ms);
Image srcImage = Bitmap.FromStream(ms);
You're actually disposing an Image by specifying using (Image raw = Image.FromStream(new MemoryStream(ba))) later assigning the Disposed instance of image to picturebox which leads to this exception. To make to work you've to either don't dispose or clone the image.
Bitmap raw = Image.FromStream(new MemoryStream(ba) as Bitmap;
pictureBox1.Image = raw;
Or simply Clone
using (Image raw = Image.FromStream(new MemoryStream(ba)))
{
img = raw.Clone() as Bitmap;
}
Both of the above should work
you try this code :
private static void SaveImageToRawFile(string strDeviceName, Byte[] Image, int nImageSize)
{
string strFileName = strDeviceName;
strFileName += ".raw";
FileStream vFileStream = new FileStream(strFileName, FileMode.Create);
BinaryWriter vBinaryWriter = new BinaryWriter(vFileStream);
for (int vIndex = 0; vIndex < nImageSize; vIndex++)
{
vBinaryWriter.Write((byte)Image[vIndex]);
}
vBinaryWriter.Close();
vFileStream.Close();
}
private static void LoadRawFile(string strDeviceName, out Byte[] Buffer)
{
FileStream vFileStream = new FileStream(strDeviceName, FileMode.Open);
BinaryReader vBinaryReader = new BinaryReader(vFileStream);
Buffer = new Byte[vFileStream.Length];
Buffer = vBinaryReader.ReadBytes(Convert.ToInt32(vFileStream.Length));
vBinaryReader.Close();
vFileStream.Close();
}

How to save image using JpegBitmapEncoder

According to the image encoding example here I should be able to use JpegBitmapEncoder to encode an image for saving as a jpeg file but get this compile error:
error CS1503: Argument 1: cannot convert from 'System.Windows.Controls.Image' to 'System.Uri'
I don't see a way (property or method in Image) to get System.Uri from Image.
What am I missing?
The Image xaml code is
<Image Name="ColorImage"/>
The SaveImage C# is
...
SaveImage(ColorImage, path);
...
private void SaveImage(Image image, string path)
{
var jpegEncoder = new JpegBitmapEncoder();
jpegEncoder.Frames.Add(BitmapFrame.Create(image));
using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write))
{
jpegEncoder.Save(fs);
}
}
The code below (taken mostly from the kinect-sdk) streams 640 x 480 RBG to a WriteableBitmap at 30 Fps (the kinect ColorImageFormat is RgbResolution640x480Fps30).
using (var colorImageFrame = allFramesReadyEventArgs.OpenColorImageFrame())
{
if (colorImageFrame == null) return;
var haveNewFormat = currentColorImageFormat != colorImageFrame.Format;
if (haveNewFormat)
{
currentColorImageFormat = colorImageFrame.Format;
colorImageData = new byte[colorImageFrame.PixelDataLength];
colorImageWritableBitmap = new WriteableBitmap(
colorImageFrame.Width,
colorImageFrame.Height, 96, 96, PixelFormats.Bgr32, null);
ColorImage.Source = colorImageWritableBitmap;
}
// Make a copy of the color frame for displaying.
colorImageFrame.CopyPixelDataTo(colorImageData);
colorImageWritableBitmap.WritePixels(
new Int32Rect(0, 0, colorImageFrame.Width, colorImageFrame.Height),
colorImageData,
colorImageFrame.Width*Bgr32BytesPerPixel,
0);
}
private void SaveImage(string path)
{
var jpegEncoder = new JpegBitmapEncoder();
jpegEncoder.Frames.Add(BitmapFrame.Create(colorImageWritableBitmap));
using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write))
{
jpegEncoder.Save(fs);
}
}
The problem occurs, because you pass an Image to BitmapFrame.Create. Imageis more common in Windows Forms. A simple approach would be to create a MemoryStream first and the pass this:
private void SaveImage(Image image, string path)
{
MemoryStream ms = new MemoryStream();
image.Save(ms,System.Drawing.Imaging.ImageFormat.Jpeg);
var jpegEncoder = new JpegBitmapEncoder();
jpegEncoder.Frames.Add(BitmapFrame.Create(ms));
using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write))
{
jpegEncoder.Save(fs);
}
}
Addition (see conversation in comments):
you could try to use the CopyPixels method on the writeableBitmap object and copy the pixels to a byte array which you load to a MemoryStream and the write it to a Jpeg File withe the JpegBitmapEncoder. But it's just a guess.
This could work, too:
private void SaveImage (WriteableBitmap img, string path)
{
FileStream stream = new FileStream(path, FileMode.Create);
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(img));
encoder.Save(stream);
stream.Close();
}
You will just have to extract the WriteableBitmap from your Image control
Try: BitmapFrame.Create(image.Source)

Categories

Resources