I am having trouble loading Tiff files in C#. I downloaded some sample tiff files and was able to load them fine, however when I attempt to load any tiff files generated from PCI Geomatica or ArcGIS, the ReadRGBAImage call fails (returns false). Other than IMAGEWIDTH and IMAGELENGTH, all of the other tags I've tried to retrieve have returned null (eg. XRESOLUTION). Does anyone have any ideas as to why this is happening? The relevant code is below:
using (Tiff tif = Tiff.Open(fileName, "r"))
{
// Find the width and height of the image
FieldValue[] value = tif.GetField(TiffTag.IMAGEWIDTH);
int width = value[0].ToInt();
value = tif.GetField(TiffTag.IMAGELENGTH);
int height = value[0].ToInt();
// Read the image into the memory buffer
int[] raster = new int[height * width];
if (!tif.ReadRGBAImage(width, height, raster))
{
System.Windows.Forms.MessageBox.Show("Could not read image");
return null;
}
}
Thanks!
Without a file to reproduce the issue, I can be 100% sure, but it looks like your file can not be converted to RGBA raster with help of LibTiff.Net.
It's not an error, it's just you are using some not very popular flavor of TIFF. Some say TIFF is a Thousand of Incompatible File Formats. And there is certainly some truth in that statement.
The library can read (and decode!) your file. You can get decoded raster using ReadEncodedStrip and / or ReadScanline methods. The task of converting your raster to RGBA is left to you.
And don't forget that not every image can be converted to RGBA without loosing some of the image data.
Related
I need your help.
I was creating an application in c# that converts the data from the IP camera to an image (JPEG).
I was able to convert the image using the below code:
hex = "FFD8FFDB008400130D0F1.........";/// supply this with the attached hex dump.
byte[] image = HexString2Bytes(hex);
File.WriteAllBytes("visio.png", image);
Process.Start("visio.png");
private static byte[] HexString2Bytes(string hexString)
{
int bytesCount = (hexString.Length) / 2;
byte[] bytes = new byte[bytesCount];
for (int x = 0; x < bytesCount; ++x)
{
bytes[x] = Convert.ToByte(hexString.Substring(x * 2, 2), 16);
}
return bytes;
}
Sometimes I get a better image as expected:https://ibb.co/pxrwn6p
but sometimes I get a distorted image after converting https://ibb.co/9twx5ZT.
I was wondering if there is a problem with the conversion or the way I save the image.
because as per the supplier what I need to do is to directly save the image from the stream.
but since I receive it as a byte and I still need to convert it maybe there is something wrong with my codes.
the image also starts with ÿØÿÛ FF D8 and ends with ÿ Ùÿÿÿÿ (FF D9 FF FF FF FF)
here's the hex dump from their sample app:
https://drive.google.com/file/d/1CMlQ0xaVjM0jfU5A4MB-_HwK54dUMTOr/view?usp=sharing
using their test application the image can be captured and converted the image perfectly.
captured image using their application:https://ibb.co/2KgyLTc
using the hex from the sniff and convert it using my code:
converted image using my code:https://ibb.co/G0WMjht
sample source code:
please bare with my codes because currently this is only my test app before integrating this feature to another app.
https://drive.google.com/file/d/1Ux7zsR39IVNyd1wrBxQPQKA6yM4YnwJN/view?usp=sharing
Thank You in advance.
Looking at the hex-dump it looks like some kind of XML file with embedded image data. Trying to convert this directly to an image will most likely not work, you would need to parse the XML-data to extract the actual image file. But it looks like you have a valid Jpeg header, so I would guess you have found the start of the image at least. But you probably also need to check the length property from the XML-data to find the length of the image-data block.
However, the datablock looks like it contains large sections of zeros, this should not be present in a jpeg file, so it might indicate some data corruption. Possibly from the way the network data is captured.
I would expect cameras to use some higher level protocol than raw TCP. Like Real Time Streaming Protocol, GigE vision, or mjpeg over http. I have not seen any camera that require you to process a raw TCP streams. But since you do not show how the data is fetched it is difficult to tell if there is any mistakes in that code.
I have the following code for changing the DPI of an image:
public void changeDPI(string imagePathSource,string imagePathDestination,float DPIx,float DPIy)
{
Bitmap bitmap = new Bitmap(imagePathSource);
Bitmap newBitmap = new Bitmap(bitmap);
newBitmap.SetResolution(DPIx,DPIy);
newBitmap.Save(imagePathDestination);
}
However, this ends up changing the memory size of the file. An example test image started at 267 KB, and the newBitmap version of the file ended up as 1.51 MB. How can I change the DPI without changing the file size?
Why are you making a new bitmap out of it? That converts the image to 32bpp ARGB, and loses the connection to the original loaded data.
The original loaded image's file format is available in the RawFormat property. So just set the original bitmap's resolution to your new one, and save it to the new path using bitmap.RawFormat:
public void changeDPI(String imagePathSource, String imagePathDestination, Single dpiX, Single dpiY)
{
using (Bitmap bitmap = new Bitmap(imagePathSource))
{
bitmap.SetResolution(dpiX, dpiY);
bitmap.Save(imagePathDestination, bitmap.RawFormat);
}
}
I believe that this way, it won't even recompress the actual image content, meaning you have no further quality degrading due to reapplying the jpeg compression.
Also, do make sure you always either call Dispose() on image objects, or use them in a using block. They are objects backed by unmanaged sources (GDI+ objects), so you have to be careful or they'll pollute your program's memory, and keep locks on the files you opened.
On the note of locked files, if you give the same path for both imagePathSource and imagePathDestination you'll get an error about exactly that. To get around this, read the bytes from the image in advance, and use a MemoryStream to load the image:
public void changeDPI(String imagePathSource, String imagePathDestination, Single dpiX, Single dpiY)
{
Byte[] fileData = File.ReadAllbytes(imagePathSource);
using (MemoryStream ms = new MemoryStream(fileData))
using (Bitmap loadedImage = new Bitmap(ms))
{
bitmap.SetResolution(dpiX, dpiY);
bitmap.Save(imagePathDestination, bitmap.RawFormat);
}
}
I think you must indicate the format of the output file, to save as a compressed image format like JPEG.
newBitmap.Save(imagePathDestination, System.Drawing.Imaging.ImageFormat.Jpeg);
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
Right now I am using ghostscript in Unity to convert pdfs to jpgs and view them in my project.
Currently it flows like so:
-Pdfs are converted into multiple jpegs (one for each page)
-The converted jpegs are written to disk
-They are then read in by bytes into a 2D texture
-And this 2D texture is assigned to a GameObjects RawImage component
This works perfectly in Unity, but... (now comes the hiccup) my project is intended to run on the Microsoft Hololens.
The Hololens runs on the Windows 10 API, but in a limited capacity.
Where the issue arises is when I try to convert pdfs and view them on the Hololens. Quite simply, the Hololens cannot create or delete files outside of its known folders (Pictures, Documents, etc).
My imagined solution to this problem is to instead of write the converted jpeg files to disk, write them to memory and view them from there.
In talking with GhostScript devs, I was told GhostScript.NET does what I am looking to do - convert pdfs and view them from memory (It does this with the Rasterizer/Viewer classes, I believe, but again I don't understand it quite well).
I've been lead to look at the latest GhostScript.NET docs to route out how this is done, but I simply don't understand them well enough to approach this.
My question is then, based on how I'm using ghostscript now, how do I use GhostScript.NET in my project to write the converted jpegs into memory and view them there?
Here's how I'm doing it now (code-wise):
//instantiate
byte[] fileData;
Texture2D tex = null;
//if a PDF file exists at the current head path
if (File.Exists(CurrentHeadPath))
{
//Transform pdf to jpg
PdfToImage.PDFConvert pp = new PDFConvert();
pp.OutputFormat = "jpeg"; //format
pp.JPEGQuality = 100; //100% quality
pp.ResolutionX = 300; //dpi
pp.ResolutionY = 500;
pp.OutputToMultipleFile = true;
CurrentPDFPath = "Data/myFiles/pdfconvimg.jpg";
//this call is what actually converts the pdf to jpeg files
pp.Convert(CurrentHeadPath, CurrentPDFPath);
//this just loads the first image
if (File.Exists("Data/myFiles/pdfconvimg" + 1 + ".jpg"))
{
//reads in the jpeg file by bytes
fileData = File.ReadAllBytes("Data/myFiles/pdfconvimg" + 1 + ".jpg");
tex = new Texture2D(2, 2);
tex.LoadImage(fileData); //..this will auto-resize the texture dimensions.
//Read Texture into RawImage component
PdfObject.GetComponent<RawImage>().texture = tex;
PdfObject.GetComponent<RawImage>().rectTransform.sizeDelta = new Vector2(288, 400);
PdfObject.GetComponent<RawImage>().enabled = true;
}
else
{
Debug.Log("reached eof");
}
}
The convert function is from a script called PDFConvert which I obtained from code project. Specifically How To Convert PDF to Image Using Ghostscript API.
From the GhostScript.Net documentation, take a look at the example code labeled: "Using GhostscriptRasterizer class". Specifically the following lines:
Image img = _rasterizer.GetPage(desired_x_dpi, desired_y_dpi, pageNumber);
img.Save(pageFilePath, ImageFormat.Png);
The Image class seems to be part of the System.Drawing package, and System.Drawing.Image has another Save method where the first parameter is a System.IO.Stream.
What i am trying to do is to convert an image into a byte array and then write that byte array into a file. here's the code
public static byte[] Convert(Image img)
{
using (MemoryStream ms = new MemoryStream())
{
img.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
// or whatever output format you like
return ms.ToArray();
}
}
public Form1()
{
InitializeComponent();
Bitmap pic = new Bitmap("tulips.jpg");
pictureBox1.Image = pic;
byte[] img_array;
img_array = Convert(pic);
File.WriteAllBytes("test.txt", img_array);
}
Now I have been successfully able to convert the image into byte array. I have checked the values in byte array by means of a breakpoint and all of them are valid.
However when I try to write the array into a file and then open the file all I see is garbage.
Am I missing something?
Your Bitmap is an Image. Why do you convert it into a byte array when you can simply call Save (documented here)
Bitmap pic = new Bitmap("tulips.jpg");
pictureBox1.Image = pic;
pic.Save("test.gif", System.Drawing.Imaging.ImageFormat.Gif);
To manipulate the image, you will usually access the pixel data - what you have now contains the file type header as well as the pixels! See Bitmap.LockBits to manipulate the pixels (documented here)
Are you sure that you are trying to open the file with an image viewer? The .txt extension would typically cause it to be opened with a text editor instead. Since the format of an image file is binary, it is to be expected that you would only see "garbage" when you render it as text. It would help if you use the correct extension, .gif, when saving the file.
File.WriteAllBytes("test.gif", img_array);
What did you expect to see? You're saving the byte array to a text file. When you open a text file that has image file bytes, there's no way you're going to get a good result.
Ensure that you're saving the file as the proper type, then see what happens.