Is it possible to store image into pdf417 barcode? - c#

Is it possible to store(Encode) image/Pictures into pdf417 barcode? if so is there any tutorial or sample code?
The barcode cannot just hold a reference to an image in a database. The customer also expect to be able to store any image he wants.
Thank you.

As ssasa mentionned you could store the image as a byte array:
public static byte[] GetBytes(Image image)
{
byte[] byteArray = new byte[0];
using (MemoryStream stream = new MemoryStream())
{
// you may want to choose another image format than PNG
image.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
stream.Close();
byteArray = stream.ToArray();
}
return byteArray;
}
... or, if it MUST be a string, you could base64 encode it:
public static string GetBase64(Image image)
{
Image yourImage;
// using the function from the first example
var imageBytes = GetBytes(yourImage);
var encodedString = Convert.ToBase64String(imageBytes);
return Encoding.UTF8.GetBytes(encodedString);
}
Remember, though: a PDF417 barcode allows storing up to 2710 characters. While this is more than enough for most structures you'd ever want to encode, it's rather limitating for an image. It may be enough for small-sized bitmaps, monochrome images and/or highly compressed JPEGs, but don't expect being able to do much more than that, especially if you want to be able to store other data along.
If your customers expects to be able to store, as you say, any picture they want, you'd better be lowering their expectations as soon as possible before writing any code.
If it's an option, you may want to consider using QR Codes instead. Not that you'll work miracles with those either but you may like the added storage capacity.

Yes, Department of Defense Common Access Cards (CAC) store JPEG image of the cardholder:

Related

Output of System.Drawing.Image Save is not the same as what fed into Image.FromStream

I am trying to validate an image submitted to backend in Base64 string format by parsing it into an Image object, extracting it from the same Image object and finally comparing input byte array and output byte array assuming these two should be the same or there was something wrong in the input image. Here is the code:
private void UpdatePhoto(string photoBase64)
{
var imageDataInBytes = Convert.FromBase64String(photoBase64);
ValidateImageContent(imageDataInBytes);
}
private void ValidateImageContent(byte[] imageDataInBytes)
{
using (var inputMem = new MemoryStream(imageDataInBytes))
{
var img = Image.FromStream(inputMem, false, true);
using (MemoryStream outputMemStream = new MemoryStream())
{
img.Save(outputMemStream, img.RawFormat);
var outputSerialized = outputMemStream.ToArray();
if (!outputSerialized.SequenceEqual(imageDataInBytes))
throw new Exception("Invalid image. Identified extra data in the input. Please upload another photo.");
}
}
}
and it fails on an image that I know is a valid one.
Is my assumption wrong that output of Image.Save must be the same as what Image.FromStream is fed with? Is there a way to correct this logic to achieve this way of validation correctly?
If you compare the original image with the created image, you will notice a few differences in the metadata: For my sample image, I could observe that some metadata was stripped (XMP data was completely removed). In addition, while the EXIF data was preserved, the endianness it is written in was reversed from little endian to big endian. This alone explains why the data won’t match.
In my example, the actual image data was identical but you won’t be able to tell easily from just looking at the bytes.
If you wanted to produce a result identical to the source, you would have to produce the metadata in the exact same way as the source did. You won’t be able to do so without actually looking closely at the metadata of the original photo though. .NET’s Image simply isn’t able to pertain all the metadata that a file could contain. And even if you were able to extract all the metadata and store it in the right format again, there are lots of fine nuances between metadata serializers that make it very difficult to produce the exact same result.
So if you wanted to compare the images, you should probably strip the metadata and just compare the image data. But then, when you think about how you save the image (Raw), then you will just get the exact same blob of data again, so I wouldn’t expect differences there.

Storing image as hash code C#

Im building a website which will store millions of images so i need a unique id for each image. What Cryptography is best for storing images. Right now this is what my code looks like im using SHA1.
Is there a standard hash used beside sha1 and is it possible that two images could have the same hash code?
Image img = Image.FromFile("image.jpg");
ImageConverter converter = new ImageConverter();
byte[] byteArray = (byte[])converter.ConvertTo(img, typeof(byte[]));
string hash;
using (SHA1CryptoServiceProvidersha1 = new SHA1CryptoServiceProvider())
{
hash = Convert.ToBase64String(sha1.ComputeHash(byteArray));
}
If I understand correctly you want to assign an SHA1 value as a filename so you can detect whether you have that image in your collection already. I don't think this is the best approach (if you're not running a database then maybe it is) but still, if you're planning to have millions of images then (for practical reasons) just think that it's impossible for collisions to occur.
For this purpose I would not recommend SHA256 since the main two advantages (collision resistance + immunity to some theoretical attacks) are not really worth it because it's something around 10 times slower than SHA1 (and you'll be hashing a lot of fairly big files).
You shouldn't be scared about it's 128 bitlength: In order to have a 50% chance of finding a collision in 128 bits you will need to have 18446744073709600000 images in your collection (sqrt of 2^128).
Oh and I don't wanna sound conceited or anything, but hash and cryptography are too different things. In fact, I'd say that hashing is closer to code signing/digital signatures than to cryptography.
You can use both mechanisms.
Use a GUID as a unique file identifier (file system, database, etc.)
Calculate and store an SHA1 or MD5 hash on your image and use that to check for duplicates.
So when an image is uploaded, you can use the hash to check for a possible duplicate. However, if one is found, then you can do a more deterministic check (ie. check the bytes of the files). Realistically speaking, you will probably never get a hash match without the files being the same, but this second check will determine for sure.
Then, once uniqueness is determined, use the GUID for the file identifier or reuse the existing file.
Can two different images have the same hash code? Unlikely. On the other hand, can two copies of the same image have different hashes? Absolutely.
Take a lossless png, open it, and resave it as uncompressed. The pixels of both images will be identical, but the file hashes will be different.
Aside from the pixels, your images will also contain metadata fields such as geolocation, date/time, camera maker, camera model, ISO speed, focal length, etc.
So your hash will be affected by the type of compression and metadata when using the image file in its entirety.
The main question here is: What makes a picture "unique" to you?
For example, if an image is already uploaded, then I download it and wipe out the camera model or comments and re-upload it, would it be a different image to you, or is still the same as the original? How about the location field?
What if I download a lossless png and save it as a lossless tiff which will have the same pixel data?
Based on your requirements and which fields are important, you'll need to create a hash of the combination of the relevant metadata fields (if any) + the actual uncompressed pixel data of the image instead of making a hash using an image file in its entirety.
Of the standard hash algorithms provided in System.Security.Cryptography you'll probably find MD5 to be best suited to this application. But by all means play around with the different ones and see which one works best for you.
Here's a code sample that gets you a hash for the combination of metadata fields and image pixels:
public class ImageHash
{
public string GetHash(string filePath)
{
using (var image = (Bitmap) Image.FromFile(filePath))
return GetHash(image);
}
public string GetHash(Bitmap bitmap)
{
var formatter = new BinaryFormatter();
using (var memoryStream = new MemoryStream())
{
var metafields = GetMetaFields(bitmap).ToArray();
if(metafields.Any())
formatter.Serialize(memoryStream, metafields);
var pixelBytes = GetPixelBytes(bitmap);
memoryStream.Write(pixelBytes, 0, pixelBytes.Length);
using (var hashAlgorithm = GetHashAlgorithm())
{
memoryStream.Seek(0, SeekOrigin.Begin);
var hash = hashAlgorithm.ComputeHash(memoryStream);
return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
}
}
}
private static HashAlgorithm GetHashAlgorithm() => MD5.Create();
private static byte[] GetPixelBytes(Bitmap bitmap, PixelFormat pixelFormat = PixelFormat.Format32bppRgb)
{
var lockedBits = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, pixelFormat);
var bufferSize = lockedBits.Height * lockedBits.Stride;
var buffer = new byte[bufferSize];
Marshal.Copy(lockedBits.Scan0, buffer, 0, bufferSize);
bitmap.UnlockBits(lockedBits);
return buffer;
}
private static IEnumerable<KeyValuePair<string,string>> GetMetaFields(Image image)
{
string manufacturer = System.Text.Encoding.ASCII.GetString(image.PropertyItems[1].Value);
yield return new KeyValuePair<string, string>("manufacturer", manufacturer);
// return any other fields you may be interested in
}
}
And obviously, you'd use this as:
var hash = new ImageHash().GetHash(#"some file path");
Whilst a decent start, this method has areas that can be improved on, such as:
How about the same image after being resized? If that doesn't make it a different picture (as in, if you need tolerance to image resize), then you'll want to resize the input images first to a pre-determined size before hashing.
How about changes in ambient light? Would that make it a different picture? If the answer is no, then you'll need take that into effect too and make the algorithm robust in the face of brightness changes, etc to still result in the same hash regardless of the image brightness having changed.
How about geometric transformations? e.g., if I rotate or mirror an image before re-uploading it, is it still the same image as the original? If so, the algorithm would need to be intelligent enough to produce the same hash after those types of transformations.
How would you like to handle cases where a border is added to an image? There are many such scenarios in the realm of image processing. Some of which have fairly standard solutions, while many others are still being actively worked on.
Performance: this current code may prove time and resource consuming depending on the number & size of images and how much time you can afford to spend on the hashing of each image. If you need it to run faster and/or use up less memory, you may want to downsize your images to a pre-determined size before getting their hash.

How do I store arbitrary binary data in a binary serialized class?

Using C#/.NET for my application, I've got a series of classes in my main data model that represent "binary" (as opposed to text) content. I've got a inheritance setup like this:
Basically, the abstract class BinaryContent contains a MemoryStream that stores arbitrary binary data. That data is read from a file on disk. Each type of binary data I plan to store will be a derived type, such as ImageContent and FontContent. Those derived types will interpret the binary data in BinaryContent.Content. ImageContent for example, would create a BitmapImage (stored in an ImageSource) from the MemoryStream. FontContent would of course create a font from the BinaryContent.Content. I chose this way of doing things because I wanted to be able to basically store a copy of the content file (ie an image) and not have to rely on the file being in a particular location on disk time after time.
I'm also storing instances of these classes in a "project file" using binary serialization. I've done this to basically "package" everything together. I'm having trouble when I attempt to deserialize the MemoryStream, it seems. The problem happens when I create the image from the MemoryStream. When the following method runs after deserialization, a FileFormatexception occurs.
private void RefreshImageFromContent()
{
BitmapImage image = null;
if (Content != null &&
Content.Length != 0L)
{
image = new BitmapImage();
image.BeginInit();
image.StreamSource = Content;
image.EndInit(); //throws FileFormatException
}
Image = image;
}
The FileFormatException message is:
"The image cannot be decoded. The image header might be corrupted."
Inner Exception: "Exception from HRESULT: 0x88982F61"
My best guess right now is that something is happening to corrupt the data in BinaryContent.Content when during serialization or deserialization.
This leads me to ask 2 questions.
Does anyone have any suggestions to fix this problem?
Does anyone have other suggested ways to store arbitrary binary data that is going to be (de)serialized?
Please feel free to ask for clarification on anything about my question.
Thanks.
What is the content.Position at image.StreamSource = Content;?
It is likely that the position of the stream is not set to the start (or the correct position in thw stream).

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.

passing the right BytesArray into the MemoryStream for Image

there a way to determine that I am passing the right byte array to the MemoryStream if I want to create an Image out of byte array.
MemoryStream mStream = new MemoryStream();
mStream.Write(byteArray, 0, byteArray.Lenth);
Image imgObj = Image.FromStream(mStream);
How can I, if possible Correct the byteArray that it is a valid byteArray for an Image?
This is a really ominous question, surely you must know where you are reading your data from? When you create an image using Image.FromStream, an ArgumentException will be thrown if it cannot recognise the format. Why don't you use that mechanism for identifying an incorrect stream of data, rather than re-invent the wheel?
I've done a bit of programatic image manipulation myself. The thing you'll want to do is find the spec for the image format that you are modifying and make sure you do everythign you should. For example png files are chunked and have checksums on each section so if you change something in that chunk you have to recalculate the checksum at the end of the section.
After reading your questions and your comments, i think what you're trying is to manipulate the image by manipulating the byte array before you put it into the Image class. And now you claim that your byte array is corrupt for this image format and how you can correct it.
So the answer to this question would be: You corrupted it, you'll fix it.
But to really solve your problem, if your goal is to manipulate the picture itself, just load it into an interims Image and use the Graphics class to manipulate your picture. Afterwards put the result into the real image object you like. Ready, without any hassle about working on the byte array.
here's the answer Image Processing for Dummies with C# and GDI+
OT: i don't know how to put links on comments so I put it in the answers.

Categories