How to "include" a .PNG image in a binary file? - c#

I'm doing some resource management code where I take a bunch of different resources (image positions etc.) along with the actual images and make a single binary file out of them. Now, how do I actually include the .PNG file in a binary file and how do I read it back again? I would like to retain the .PNG compression.
I use BinaryWriter to write the data into a file, and BinaryReader to read it back. Here's an example of the format I'm using:
BinaryWriter writer = new BinaryWriter(new FileStream("file.tmp"));
writer.Write(name);
writer.Write(positionX);
writer.Write(positionY);
// Here should be the binary data of the PNG image
writer.Close();
BinaryReader reader = new BinaryReader(new FileStream("file.tmp"));
string name = reader.ReadString();
float posX = reader.ReadSingle();
float posY = reader.ReadSingle();
Bitmap bitmap = ... // Here I'd like to get the PNG data
reader.Close();
There is some other data too, both before and after the PNG data. Basically I will merge multiple of PNG files into this one binary file.

You will need to use so sort of Prefix (int) Followed by a Length Indicator (int) followed by your Payload (variable length) or if you know this will be the last thing in your file, then you can skip the prefix/size and just read until end of stream.
Then when you save your various parts, you write your prefix, then your length and then your data.
Ideally you could use some of the serialisers like protobuf to do a lot of the serialising for you, then you can just load your class back. I do this in one of my projects for Plugin Installers. The final File is a Zip, but the structures to generate the file "filenames, description, actual file locations, etc" are stored in a custom file like what you are describing.
if you are doing this all in memory then you could Serialise your PNG Image to a MemoryStream (get the size), then write the Size to the FileStream (file.tmp) followed by the MemorySteam Buffer
using (MemoryStream ms = new MemoryStream())
{
bitmap.Save(ms);
writer.Write(ms.Length);
ms.Position = 0;
ms.CopyTo(writer.BaseStream);
}

Basically Paul Farry's answer is what you need to do. Read up on binary formats like the PNG format (see file header, chunks), the ZIP format (file headers, data descriptor), which implement something -- on a more elaborate level than you need -- the mechanism of storing different chunks of data in one file.

Related

How can I write to the column I want with StreamWriter? [duplicate]

I am trying to use StreamReader and StreamWriter to Open a text file (fixed width) and to modify a few specific columns of data. I have dates with the following format that are going to be converted to packed COMP-3 fields.
020100718F
020100716F
020100717F
020100718F
020100719F
I want to be able to read in the dates form a file using StreamReader, then convert them to packed fields (5 characters), and then output them using StreamWriter. However, I haven't found a way to use StreamWriter to right to a specific position, and beginning to wonder if is possible.
I have the following code snip-it.
System.IO.StreamWriter writer;
this.fileName = #"C:\Test9.txt";
reader = new System.IO.StreamReader(System.IO.File.OpenRead(this.fileName));
currentLine = reader.ReadLine();
currentLine = currentLine.Substring(30, 10); //Substring Containing the Date
reader.Close();
...
// Convert currentLine to Packed Field
...
writer = new System.IO.StreamWriter(System.IO.File.Open(this.fileName, System.IO.FileMode.Open));
writer.Write(currentLine);
Currently what I have does the following:
After:
!##$%0718F
020100716F
020100717F
020100718F
020100719F
!##$% = Ascii Characters SO can't display
Any ideas? Thanks!
UPDATE
Information on Packed Fields COMP-3
Packed Fields are used by COBOL systems to reduce the number of bytes a field requires in files. Please see the following SO post for more information: Here
Here is Picture of the following date "20120123" packed in COMP-3. This is my end result and I have included because I wasn't sure if it would effect possible answers.
My question is how do you get StreamWriter to dynamically replace data inside a file and change the lengths of rows?
I have always found it better to to read the input file, filter/process the data and write the output to a temporary file. After finished, delete the original file (or make a backup) and copy the temporary file over. This way you haven't lost half your input file in case something goes wrong in the middle of processing.
You should probably be using a Stream directly (probably a FileStream). This would allow you to change position.
However, you're not going to be able to change record sizes this way, at least, not in-line. You can have one Stream reading from the original file, and another writing to a new, converted copy of the file.
However, I haven't found a way to use StreamWriter to right to a specific position, and
beginning to wonder if is possible.
You can use StreamWriter.BaseStream.Seek method
using (StreamWriter wr = new StreamWriter(File.Create(#"c:\Temp\aaa.txt")))
{
wr.Write("ABC");
wr.Flush();
wr.BaseStream.Seek(0, SeekOrigin.Begin);
wr.Write("Z");
}

Image to PDF conversion without using third party library in C#

I need to convert image files to PDF without using third party libraries in C#. The images can be in any format like (.jpg, .png, .jpeg, .tiff).
I am successfully able to do this with the help of itextsharp; here is the code.
string value = string.Empty;//value contains the data from a json file
List<string> sampleData;
public void convertdata()
{
//sampleData = Newtonsoft.Json.JsonConvert.DeserializeObject<List<string>>(value);
var jsonD = System.IO.File.ReadAllLines(#"json.txt");
sampleData = Newtonsoft.Json.JsonConvert.DeserializeObject<List<string>>(jsonD[0]);
Document document = new Document();
using (var stream = new FileStream("test111.pdf", FileMode.Create, FileAccess.Write, FileShare.None))
{
PdfWriter.GetInstance(document, stream);
document.Open();
foreach (var item in sampleData)
{
newdata = Convert.FromBase64String(item);
var image = iTextSharp.text.Image.GetInstance(newdata);
document.Add(image);
Console.WriteLine("Conversion done check folder");
}
document.Close();
}
But now I need to perform the same without using third party library.
I have searched the internet but I am unable to get something that can suggest a proper answer. All I am getting is to use it with either "itextsharp" or "PdfSharp" or with the "GhostScriptApi".
Would someone suggest a possible solution?
This is doable but not practical in the sense that it would very likely take way too much time for you to implement. The general procedure is:
Open the image file format
Either copy the encoded bytes verbatim to a stream in a PDF document you have created or decode the image data and re-encode it in a PDF stream (whether it's the former or latter depends on the image format)
Save the PDF
This looks easy (it's only three points after all :-)) but when you start to investigate you'll see that it's very complicated.
First of all you need to understand enough of the PDF specification to write a new PDF file from scratch, doing all of the right things. The PDF specification is way over 1000 pages by now; you don't need all of it but you need to support a good portion of it to write a proper PDF document.
Secondly you will need to understand every image file format you want to support. That by itself is not trivial (the TIFF file format for example is so broad that it's a nightmare to support a reasonable fraction of TIFF files out there). In some cases you'll be able to simply copy the bulk of an image file format into your PDF document (jpeg files fall in that category for example), that's a complication you want to support because uncompressing the JPEG file and then recompressing it in a PDF stream will cause quality loss.
So... possible? Yes. Plausible? No. Unless you have gotten lots and lots of time to complete this project.
The structure of the simpliest PDF document with one single page and one single image is the following:
- pdf header
- pdf document catalog
- pages info
- image
- image header
- image data
- page
- reference to image
- list of references to objects inside pdf document
Check this Python code that is doing the following steps to convert image to PDF:
Writes PDF header;
Checks image data to find which filter to use. You should better select just one format like FlateDecode codec (used by PDF to compress images without loss);
Writes "catalog" object which is basically is the array of references to page objects.
Writes image object header;
Writes image data (pixels by pixels, converted to the given codec format) as the "stream" object in pdf;
Writes "page" object which contains "image" object;
Writes "trailer" section with the set of references to objects inside PDF and their starting offsets. PDF format stores references of objects at the end of PDF document.
I would write my own ASP.NET Web Service or Web API service and call it within the app :)

Saving zip file entry into a list

I have a List and I want to save several pictures into it, then I will binary serialize that list into a file.
I am getting the pictures from a zip file like this:
zip.GetEntry(path).Open()
The zip file opens correctly and if i replace Open with ExtractToFile and try to extract the picture into a folder it works with no problems.
But when I try to save the body of the picture into the list instead, as a stream, it doesn't work:
List.Add(zip.GetEntry(path).Open());
The picture is over 2MB large, yet when I serialize the list it has barely 2 kilobytes.
What am i doing wrong here?
ZipArchiveEntry.Open() returns a stream.
You need to read the stream using Stream.Read(...) method somewhere in your code.
You can save a list of streams if you want as long as you read them when you want to export the data.
The stream itself isn't the data, it allows you to read it.
You can't directly serialize a Stream object. You should first Read the contents into byte[], then serialize that array.
First change your List:
List<byte[]> List = new List<byte[]>();
Then read the streams into this list. Since the Length property is not supported on compression streams, it is simpler to use a MemoryStream as a buffer:
using (MemoryStream ms = new MemoryStream())
{
zip.GetEntry(path).Open().CopyTo(ms);
List.Add(ms.ToArray());
}
And finally serialize the List.

How to I read any file in binary using C#? [duplicate]

This question already has answers here:
C# - How do I read and write a binary file?
(4 answers)
Closed 9 years ago.
The application I'm attempting to create would read the binary code of any file and create a file with the exact same binary code, creating a copy.
While writing a program that reads a file and writes it somewhere else, I was running into encoding issues, so I hypothesize that reading as straight binary will overcome this.
The file being read into the application is important, as after I get this to work I will add additional functionality to search within or manipulate the file's data as it is read.
Update:
I'd like to thank everyone that took the time to answer, I now have a working solution. Wolfwyrd's answer was exactly what I needed.
BinaryReader will handle reading the file into a byte buffer. BinaryWriter will handle dumping those bytes back out to another file. Your code will be something like:
using (var binReader = new System.IO.BinaryReader(System.IO.File.OpenRead("PATHIN")))
using (var binWriter = new System.IO.BinaryWriter(System.IO.File.OpenWrite("PATHOUT")))
{
byte[] buffer = new byte[512];
while (binReader.Read(buffer, 0, 512) != 0)
{
binWriter.Write(buffer);
}
}
Here we cycle a buffer of 512 bytes and immediately write it out to the other file. You would need to choose sensible sizes for your own buffer (there's nothing stopping you reading the entire file if it's reasonably sized). As you mentioned doing pattern matching you will need to consider the case where a pattern overlaps a buffered read if you do not load the whole file into a single byte array.
This SO Question has more details on best practices on reading large files.
Look at MemoryStream and BinaryReader/BinaryWriter:
http://www.dotnetperls.com/memorystream
http://msdn.microsoft.com/en-us/library/system.io.binaryreader.aspx
http://msdn.microsoft.com/en-us/library/system.io.binarywriter.aspx
Have a look at using BinaryReader Class
Reads primitive data types as binary values in a specific encoding.
and maybe BinaryReader.ReadBytes Method
Reads the specified number of bytes from the current stream into a
byte array and advances the current position by that number of bytes.
also BinaryWriter Class
Writes primitive types in binary to a stream and supports writing
strings in a specific encoding.
Another good example C# - Copying Binary Files
for instance, one char at a time.
using (BinaryReader writer = new BinaryWrite(File.OpenWrite("target"))
{
using (BinaryReader reader = new BinaryReader(File.OpenRead("source"))
{
var nextChar = reader.Read();
while (nextChar != -1)
{
writer.Write(Convert.ToChar(nextChar));
nextChar = reader.Read();
}
}
}
The application I'm attempting to create would read the binary code of any file and create a file with the exact same binary code, creating a copy.
Is this for academic purposes? Or do you actually just want to copy a file?
If the latter, you'll want to just use the System.IO.File.Copy method.

Bitmap <-> JPEG Conversion

I have an application that use the image captured by the mobile camera and sends it to a webservice. Currently I am putting the image in a byte[] which then will be transmitted. This is done by:
filename = cameracapturedialog.FileName;
FileStream fs = new FileStream(filename, FileMode.Open);
byte[] ImageByte = new byte[fs.Length]; //file to send
fs.Read(ImageByte, 0, Convert.ToInt32(fs.Length));
But now I would like to perform some processing (resizing), hence I had to put the image into a BITMAP object, and after the processing I will convert it back to JPEG.
Is there a way to convert a JPEG into Bitmap and then back to JPEG without having no changes in the pixels (for testing I will perform no processing on the Bitmap)? Hence if I compare the first JPEG with the second JPEG I need that the files will be exactly the same.
What do you think the best solution is? Can I use something else instead of Bitmap. Any suggestion with some code will be greatly appreciated.
JPG is a lossy format. It will ALWAYS lose information because of the way the encoding algorithm works. So you'll never get the original image from a jpg, no matter what encoder you use.
No. You can save it with Quality=100 which would be almost like the original image. However, the resulting file will be huge.

Categories