Our users needed the ability to change images (rotate\insert scan between pages etc) so I wrote an app that allows them to load a Tiff image and edit as needed.
The problem I have is that when the image is saved it is saved as black and white and not in color. The loaded image displays in color no problem so it seems that it is the saving that is causing the issue.
This is the code I am using to save the Tiff image from an array of BitmapSource:
//create encoder
TiffBitmapEncoder tiffEncoder = new TiffBitmapEncoder();
tiffEncoder.Compression = TiffCompressOption.Ccitt4;
//loop through images and create frames
foreach (BitmapSource src in bitmapList)
{
BitmapFrame bmFrame = BitmapFrame.Create(src);
tiffEncoder.Frames.Add(bmFrame);
}
//create stream to write file
FileStream fStream = null;
try
{
fStream = new FileStream(path, FileMode.Create);
//Save Tiff image to disc
tiffEncoder.Save(fStream);
}
finally
{
if (fStream != null)
{
fStream.Close();
}
}
When I look at the properties of the original file it has a bit depth of 24 but the newly saved image has a bit depth of 1 (black and white?), is this the problem?
I am new to working with Tiffs so any guidance would be greatly appreciated.
Please let me know if you need any other info.
Tx
The images are probably converted to black/white, because of the TiffCompressOption.Ccitt4 compression in use. The CCITT compressions are intended for fax documents, and only supports black/white images.
Instead, use a more general purpose compression, like LZW or Deflate. This will let the image data pass unchanged as 24 or 32 bit color data.
Related
image color is becoming inverted when bitmap is converted to byte array and then to memory stream and saved. This code was part of the dynamic image creation at my site ommrudraksha.com
using (var bmp = new System.Drawing.Bitmap(width + 10, height + 10))
{
using (Graphics g = Graphics.FromImage(bmp))
{
g.Flush();
bmp.Save("ss.jpg");
}
}
Above code saves properly the image.
But when the bmp is converted to memorystream and saved, the background becomes black.
Below code generates black image.
var memStream = new MemoryStream();
bmp.Save(memStream, ImageFormat.Jpeg);
var bytes = memStream.ToArray();
var ms2 = new MemoryStream(bytes);
Bitmap.FromStream(ms).Save("ss1.jpg");
Let's examine your drawing code first:
bmp.Save("ss.jpg");
In your case, this operation is actually saving as the "PNG" file format, regardless of the file name. I found this out using a hex editor. Windows is smart enough to check the file header, though, so most likely you can still preview or otherwise open it even with a wrong extension name. You can also explicitly specify an output format with a second argument.
By default, a new PNG will also be transparent. Some image formats may default to black, even though they support alpha channel (e.g. BMP and GIF). This means that if you really want to save as a BMP, you'll have to do some additional processing.
That brings me to why your output image is black. Jpeg does not support transparency at all, so when the transparent PNG was converted, the Jpeg defaulted to black. See this post.
If you need transparency, you'll have to use an image format that supports it. You may also have to clear the entire rectangle first, depending on the format.
I have an image with the color format YCbCr (CMYK). When I load this with the .NET bitmap and save the result, the color format will change to RBG and the filze increase from ~1.600 KB to ~7.500 KB.
using (Image bitmap = Image.FromFile(#"C:\Test\Original.tif"))
{
bitmap.Save(#"C:\Test\result.tif");
}
The sample file is a multi frame Tiff file with the color format YCbCr (CMYK) and it is 24 bit color deep. Its a Tiff container that includes two JPEG files with no compression.
Here you can download the sample file: https://ufile.io/9x21n
I already tried a OpenCV wrapper Nuget Package (https://github.com/shimat/opencvsharp), but the result is the same.
Mat imageForProcessing = Cv2.ImRead(#"C:\Test\Original.tif");
Cv2.ImWrite(#"C:\Test\result.tif", imageForProcessing);
Is there a free third party library, a .NET or OpenCV way to read and write the image without lossing the color format and increasing the file size five times?
Update 1
I tried the TiffBitmapEncoder class with the following source code. The bit deep is now correct (decreases the result from ~7.500 KB to ~6.400 KB), but the output is againg in RGB.
FileStream stream = new FileStream(#"C:\Test\original.tif", FileMode.Open);
TiffBitmapEncoder encoder = new TiffBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(stream));
encoder.Save(stream);
I would appreciate any help!
Regards
Sascha
I'm working on water marking an image with another image and I can't seem to get it quite right. I'm using the Graphics library to overlay the watermark image over the photo. The photo Stream object is later uploaded as a jpg image to Amazon S3. When I go to look at the image, the photo is there but no water mark is present.
I've tried using both the DrawImage() function and DrawText() to add text as a test but no luck. Are there any issues with this part of the code? Thanks for the help.
public Stream WatermarkImage(Stream img, Stream mark, ImageType type)
{
// watermark the image
using (Image result = Image.FromStream(img))
{
Image markImage = Image.FromStream(mark);
using (Graphics g = Graphics.FromImage(result))
{
// draw mark and get result
g.DrawImage(markImage, new Point(20, 20));
Stream markedResult = new MemoryStream();
result.Save(markedResult, ImageFormat.Jpeg);
// return image
return markedResult;
}
}
}
EDIT: I actually found that this part of the code does work. Instead of saving to S3, I saved it to a file:
result.Save(#"C:\Users\Dan\Documents\Jobs\ZenPhotos\Test\test_watermark" + DateTime.Now.ToString("MM_dd_yyyy_HH_mm") + ".jpg");
The saved file shows the watermarked image. So the problem is in my upload to S3 and is unrelated.
Have a look at Automatically add watermark to an image
Instead of saving it to disk as the example demonstrates, you can return a stream instead if that's what you are after.
Hope it helps.
Cloudinary allows you to manipulate your images on-the-fly using all kind of cool transformations capabilities including overlays & watermarks. See: http://cloudinary.com/blog/adding_watermarks_credits_badges_and_text_overlays_to_images
and: http://cloudinary.com/blog/transform_your_image_overlays_with_on_the_fly_manipulation
I have a functioning application in c#/.net that currently accepts raw image data in a bayer format from a set of embedded cameras and converts them to jpeg images. To save transmission time, I have modified the embedded devices to encode the images as jpegs prior to transmission. I'm an experienced embedded programmer but a total c#/.net noob. I have managed to modify the application to save the arrays to file with a jpeg name using this snippet: ( the offset of 5 is to skip header data in the transmission frame)
FileStream stream = File.Create(fileName);
BinaryWriter writer = new BinaryWriter(stream);
writer.Write(multiBuff.msgData, 5, multiBuff.dataSize - 5);
writer.Close();
The files open up fine, but now I want to treat the data as a bitmap without having to save & load from file. I tried the following on the data array:
MemoryStream stream = new MemoryStream(data);
BinaryReader reader = new BinaryReader(stream);
byte[] headerData = reader.ReadBytes(5);
Bitmap bmpImage = new Bitmap(stream);
But this throws a parameter not valid exception. As a newbie, I'm a little overwhelmed with all the classes and methods for images and it seems like what I'm doing should be commonplace, but I can't find any examples in the usual places. Any ideas?
I think you are looking for Bitmap.FromStream() :
Bitmap bmpImage = (Bitmap)Bitmap.FromStream(stream);
Actually using new Bitmap(stream) should have worked as well - this means that the data in the stream does not constitute a valid image - are you sure the jpg is valid? Can you save it to disk and open it i.e. in Paint to test?
You use the Image class.
Image image;
using (MemoryStream stream = new MemoryStream(data))
{
image = Image.FromStream(stream);
}
FYI it didn't work because reader.ReadBytes(5) returns the 5 first bytes of stream not the bytes after position 5
Using .Net how do I replace the first page of a multiple page tiff file with a new image. Preferable without create a new file.
I think you could not do it without creating another file.
You could read all the images first, replace the image you want to replace, close the original source, and then replace the file with the new multi-page TIFF, but I believe it will use a lot of memory. I would read an image at a time, and write it to a new file and, as the last step, change the file names.
Something like:
// open a multi page tiff using a Stream
using(Stream stream = // your favorite stream depending if you have in memory or from file.)
{
Bitmap bmp = new Bitmap(imagePath);
int frameCount = bmp.GetFrameCount(FrameDimension.Page);
// for a reference for creating a new multi page tiff see:
// http://www.bobpowell.net/generating_multipage_tiffs.htm
// Here all the stuff of the Encoders, and all that stuff.
EncoderParameters ep = new EncoderParameters(1);
ep.Param[0] = new EncoderParameter(enc, (long)EncoderValue.MultiFrame);
Image newTiff = theNewFirstImage;
for(int i=0; i<frameCount; i++)
{
if(i==0)
{
// Just save the new image instead of the first one.
newTiff.Save(newFileName, imageCodecInfo, Encoder);
}
else
{
Bitmap newPage = bmp.SelectActiveFrame(FrameDimension.Page);
newTiff.SaveAdd(newPage, ep);
}
}
ep.Param[0] = new EncoderParameter(enc, (long)EncoderValue.Flush);
newTiff.SaveAdd(ep);
}
// close all files and Streams and the do original file delete, and newFile change name...
Hope it helps. For questions in .NET imaging, the Bob Powell page has a lot of good stuff.
This is fairly easy to do. There's source code on this CodeProject tutorial page that will help you do what you want.
Essentially, you'll need to make a call to Image.GetFrameCount() which will give you the number of images in your multi-page TIFF (just to confirm that you actually have a multi-page TIFF).
You might need to experiment with how you save your resulting TIFF - you may need to reassemble the TIFF manually, or you might be able to edit/replace the image directly before writing the TIFF back to disk.