Problem with saving PNM image on Windows in my app - c#

I am creating a photo editing app for my c# project. I need to support different image formats, but to begin with, I chose a very simple format - PNM. At the moment, I can open PNM images and change the color scheme, but strange things happen when saving. When saving the image on macOS, everything works fine, but after trying a similar action on Windows, I got a strange effect, the colors were read with a shift of 1 byte with each new opening after saving.
Here is an example of an image:
example image
That’s what is happening after loading and re-opening it on Windows:
damaged image
It is logical to assume that the problem is in the methods of saving the image. I first write the entire file header to the stream, and then write the color bytes one by one.
I can't figure out what exactly the problem is, because when debugging, the array of bytes being written contained nothing extra. Opening the image in the notepad before and after saving, I did not find any visible changes.
Here is my implementation of saving in a file:
public void SaveTo(Stream stream)
{
_filter.WriteHeader(stream, _image);
foreach (var (x, y) in _enumerationStrategy.Enumerate(Width, Height))
{
var triplet = _image[x, y];
_filter.Write(stream, triplet, _converterProvider.Converter);
}
}
public void WriteHeader(Stream stream, IBitmapImage image)
{
var builder = new StringBuilder();
builder.AppendLine("P6");
builder.AppendLine($"{image.Width} {image.Height}");
builder.AppendLine("255");
var header = builder.ToString();
var headerBytes = Encoding.UTF8.GetBytes(header);
stream.Write(headerBytes, 0, headerBytes.Length);
}
I tried to create a header of image without a string builder, and I tried to write the header to the stream in different ways. Trying different encodings to convert bytes didn't work out too. The effect is the same...

I guess your issue is caused by inconsistent line endings between operating systems. When you use AppendLine it adds a \n character after your string which is translated to binary differently, depending on the OS you running.
I suggest you to write a line ending directly like so:
builder.Append((char)10);

Related

How to extract image from TCP Stream

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.

EvilDicom Image Corrupted

I'm trying to use the library to anonymize a dicom image.
In some cases it works fine, but in other cases the final image is corrupted. I mean, the pixels of the image are wrong and also the FileMetaInformationGroupLength tag of final image has changed.
This also happen when I don't anonymize the image, I just read and write the image in a new file.
This is my code:
//---------------------------------------------------------------------
string dir = #"C:\Users\Desktop\CT.dcm";
var dcmBytes = System.IO.File.ReadAllBytes(#dir);
try
{
var dcm = EvilDICOM.Core.DICOMObject.Read(dcmBytes);
var refName = new EvilDICOM.Core.Element.PersonName
{
FirstName = "",
Tag = EvilDICOM.Core.Helpers.TagHelper.PATIENT_NAME
};
dcm.ReplaceOrAdd(refName);
dcm.Write(#"C:\Users\Desktop\CT2.dcm");
}
catch(Exception ex)
{
throw new Exception("EXCEPTION: " + ex.Message);
}
//---------------------------------------------------------------------
Following is the original image with which I have the problem:
https://www.dropbox.com/s/s5ase23jl9908jm/3DSlice1.dcm?dl=0
Following is the screenshot with the original image and the final image (the corrupted image).
https://www.dropbox.com/s/12liy3gbw7dkb4d/Image_corrupted.PNG?dl=0
I don't know what is happening with the pixel data. But I have seen that the FileMetaInformationGroupLength tag changes.
Original image is compressed with Transfer syntax 1.2.840.10008.1.2.4.70. The output image is encoded with 1.2.840.10008.1.2 which means uncompressed. You need to check if this change in transfer syntax is applied correctly while calling dcm.Write.
Or may be that the transfer syntax is already changed while read operation.
In any case, make sure the change in transfer syntax is intended, it is done correctly and consistent with DICOM tags.
I never used Evil DICOM toolkit so I may not help you with code.

Append DataVizualisation Chart Control to text file

I'm developing a system that takes data input from textboxes, and on a button click, saves these values to the respective listbox ready to be written to a text file once the process is complete.
The next stage has been using this data to create graphs, which has gone successfully but I'm now looking for a way to add these onto the end of my text file so it's all included in one place.
I originally tried it like this (included in the total 'saveToFile' function):
consoleFile.WriteLine(chartBP.Text); //chart title
chartBP.SaveImage((fileName), System.Drawing.Imaging.ImageFormat.Jpeg);
consoleFile.WriteLine("\n\n");
This appeared to work ok but threw a run-time error stating that the file could not be accessed because it was being used by another process.
I don't think I'm far off where I need to be, but I don't have enough experience with charts to know what to try next.
Does anyone have any idea how to make this work, or another method that wouldn't produce the error?
Any help is greatly appreciated!
If your problem is just to get rid of the exception, then you could do this:
consoleFile.WriteLine(chartBP.Text);
consoleFile.Close();
FileStream imgFile = File.Open(filename, FileMode.Append);
chartBP.SaveImage(imgFile, ChartImageFormat.Jpeg);
imgFile.Close();
consoleFile = new StreamWriter(filename, true);
consoleFile.WriteLine("\n\n");
consoleFile.Close();
But remember, you're not going to see any images in your text file, just a messy stream of characters corresponding to the binary image, displayed as text.

generic error in gdi+ decoding a valid jpeg

I have a valid jpeg frame that is taken from a camera:
http://www.developerinabox.com/test.jpg
I'm loading this with the below (example) code:
using System.Net;
using System.Drawing;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
WebRequest req = WebRequest.Create("http://www.developerinabox.com/test.jpg");
req.Timeout = 5000;
WebResponse resp = null;
resp = req.GetResponse();
if (resp != null)
{
var s = resp.GetResponseStream();
if (s != null)
{
Image img = Image.FromStream(s); //<-- Error thrown here
}
}
}
}
}
In windows XP/Vista/7 this works fine.
In windows 8 it's failing with "generic error in gdi+" I've tried loading it via WPF with the same result.
I can display the image on my windows 8 PC in google chrome but not in IE. It will display in both on windows XP/Vista/7.
I can open it on my Windows 8 box in Fireworks but trying to open it in paint gives me:
"This is not a valid bitmap file, or its format is not currently supported."
Any ideas?
Actually, it is an invalid JPEG image but, as you can see, many applications can decode this image seamlessly. This JPEG image has a bogus SOS marker (sorry for the technical information), this Scan header (SOS) says that this image has 1 color component but the Frame header (SOF, which appears before the SOS in the JPEG file structure) claims that it's a 3 components image.
So the Scan header has less information than required but the missing information can be replaced with default values and the JPEG image should be decoded with no issues, which is exactly what is happening. The missing information are the Huffman table indices and default sets of these indices can be assumed based on the JPEG coding type (sequential, progressive or lossless).
Well, it seems that Win8 is stricter when it comes to JPEG decoding. If you are curious you can take a look to this code I uploaded for another JPEG related issue (it's coded in VB.NET) and you can debug it to know where the problem is (you should check JPEG specifications as well).
EDIT: It was a valid JPEG image after all
This JPEG is a baseline multi-scan sequential image (similar to a planar image), not to be confused with a progressive image (which is similar to an interlaced image). So this JPEG has a smaller Scan header because the image is decoded one component at a time. Thus, this file has 3 non-contiguous Scan headers (SOS for 1st component, compressed data, SOS for 2nd component, compressed data,...), and each scan header has information for a single component.
Finally, if the problem was an incomplete or bogus scan header there would be a workaround (you could fix a bogus SOS header) but this is not the case. So you could make a request to the MS guys asking for support for multi-scan sequential JPEG images on Win8 ;-) or use some third-party JPEG decoding library.

WinRT image handling

A friend and I spent the better part of last night nearly tearing our hair out trying to work with some images in a metro app. We got images into the app with the share charm, and then I wanted to do some other work with them, cropping the images and saving them back into the appdata folder. This proved extremely frustrating.
My question, at the end of all this, is going to be "What's the proper way of doing this, without feeling like I'm hammering together a bunch of mismatched jigsaw puzzle pieces?"
When sharing multiple images with the app, they come in as a list of Windows.Storage.StorageFiles. Here's some code used to handle that.
var storageItems = await _shareOperation.Data.GetStorageItemsAsync();
foreach (StorageFile item in storageItems)
{
var stream = await item.OpenReadAsync();
var properties = await item.Properties.GetImagePropertiesAsync();
var image = new WriteableBitmap((Int32)properties.Width, (Int32)properties.Height);
image.SetSource(stream);
images.Add(image);
}
Some searching online has indicated that currently, a Windows.UI.Xaml.Media.Imaging.WriteableBitmap is the only thing capable of letting you access the pixel data in the image. This question includes a helpful answer full of extension methods for saving images to a file, so we used those.
Our problems were the worst when I tried opening the files again later. I did something similar to before:
var files = await ApplicationData.Current.LocalFolder.GetFilesAsync();
foreach (var file in files)
{
var fileStream = await file.OpenReadAsync();
var properties = await file.Properties.GetImagePropertiesAsync();
var bitmap = new WriteableBitmap((Int32)properties.Width, (Int32)properties.Height);
bitmap.SetSource(fileStream);
System.IO.Stream stream = bitmap.PixelBuffer.AsStream();
Here comes a problem. How long is this stream, if I want the bytes out of it?
// CRASH! Length isn't supported on an IRandomAccessStream.
var pixels = new byte[fileStream.Length];
Ok try again.
var pixels = new byte[stream.Length];
This works, except... if the image is compressed, the stream is shorter than you would expect, so you will eventually get an out of bounds exception. For now pretend it's an uncompressed bitmap.
await _stream.ReadAsync(pixels, 0, pixels.Length);
Well guess what. Even though I said bitmap.SetSource(fileStream); in order to read in the data, my byte array is still full of zeroes. I have no idea why. If I pass this same bitmap into a my UI through the sample data group, the image shows up just fine. So it has clearly got the pixel data in that bitmap somewhere, but I can't read it out of bitmap.PixelBuffer? Why not?
Finally, here's what ended up actually working.
var decoder = await BitmapDecoder.CreateAsync(BitmapDecoder.PngDecoderId, fileStream);
var data = await decoder.GetPixelDataAsync();
var bytes = data.DetachPixelData();
/* process my data, finally */
} // end of that foreach I started a while ago
So now I have by image data, but I still have a big problem. In order to do anything with it, I have to make assumptions about its format. I have no idea whether it's rgba, rgb, abgr, bgra, whatever they can be. If I guess wrong my processing just fails. I've had dozens of test runs spit out zero byte and corrupted images, upside down images (???), wrong colors, etc. I would have expected to find some of this info in the properties that I got from calling await file.Properties.GetImagePropertiesAsync();, but no luck. That only contains the image width and height, plus some other useless things. Minimal documentation here.
So, why is this process so painful? Is this just reflecting the immaturity of the libraries right now, and can I expect it to get better? Or is there already some standard way of doing this? I wish it were as easy as in System.Drawing. That gave you all the data you ever needed, and happily loaded any image type correctly, without making you deal with streams yourself.
From what I have seen - when you are planning on loading the WriteableBitmap with a stream - you don't need to check the image dimensions - just do new WriteableBitmap(1,1), then call SetSource().
Not sure why you were thinking var pixels = new byte[fileStream.Length]; would work, since the fileStream has the compressed image bytes and not a pixel array.
You might need to seek to the beginning of the stream to get the pixels array:
var pixelStream = pixelBuffer.AsStream();
var bytes = new byte[this.pixelStream.Length];
this.pixelStream.Seek(0, SeekOrigin.Begin);
this.pixelStream.Read(bytes, 0, Bytes.Length);
I had started working on a WinRT port of WriteableBitmapEx - maybe it could help you: http://bit.ly/WriteableBitmapExWinRT. I have not tested it well and it is based on an older version of WBX, but it is fairly complete in terms of feature support. Might be a tad slower than it is possible too.

Categories