I got a MySql backup file containing a column like:
CREATE TABLE `person` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`profilepicture` blob,
)
The content of this row profilepicture is encoded in the backup file to some kind of dump, starting (in a text editor) like this:
INSERT INTO `tbox_account_transaction` VALUES (8,'?\?\?0JFIF\0\0\0\0\0\0[...]');
How can I decode this from the .sql backup file in c#? It is not Base64, but I do not recognize what else it might be. I don't want to restore the backup.sql file to MySql but instead decode the blob from the backup file.
The bytes you are seeing are almost certainly the initial bytes of a JPEG image. The readable string "JFIF" starting at the fifth byte is the clue (see https://en.wikipedia.org/wiki/JPEG_File_Interchange_Format).
Many of the other binary bytes are null or else non-printable characters. All the weird \? or \0 sequences are the client's best effort at representing these bytes on your text display.
The easiest way to access this data is to restore the dump file to a MySQL instance (even a local one running on a laptop), and then use SQL in your C# code to access the binary contents of the profilepicture blob.
Either save the data from one blob to a .jpg file as #Tommaso Belluzzo suggests, or else just display it directly, if you can. I'm not a C# programmer, but it seems there's a Bitmap class for this (see https://msdn.microsoft.com/en-us/library/8tda2c3c(v=vs.85).aspx).
It's outside the scope of a Stack Overflow answer to give a tutorial on how to write SQL in a C# application. There are plenty of resources available for that.
That looks like a jpg file header. Try the following (blob is a String typed variable containing the profilepicture):
using (MemoryStream stream = new MemoryStream(buffer))
{
Image image = Image.FromStream(stream, true, true);
image.Save("C:\\Test.jpg", ImageFormat.Jpeg);
}
Related
I have binary data stored in database which I need to convert them back for backup purposes. Most of them are .doc files with images attached in document. My method to restore them is to write binary data to byte string and write those bytes to the file like mydoc.doc. The problem is, it works for txt files and it actually works for text part of .doc file as well. Since most of the .doc files contain jpeg attached, after conversion I get some readable text and random characters which I believe are there for picture attached in doc file. Any help is appreciated. Thanks in advance...
Note: Binary data is stored in image data type in database. Database contains file path and name (which doesn't exist now) and corresponding binary data stored in image type, so from path I can detect the file type that it was before... some of them are .txt (which I was able to convert perfectly), some of them are .doc (which is problem because of attahcmens inside it)
Here is my code:
string s = "D0CF11E0A1B11AE100000000000000000000"; // note: string is for example
var bytes = GetBytesFromByteString(s).ToArray();
File.WriteAllBytes("C:\\temp\\test.doc", bytes);
A .doc file is not a string or even a text or ASCII. It is a raw binary file format.
So if your database cell contains a BLOB (Binary Large Object) simply treat it as an array of bytes and write it out to a (binary) file. No conversions, no encodings, nothing.
Edit
Whoever designed this database, they designed to store all kinds of files as an image (in the sense of memory-dump-image) i.e. a series of raw bytes in a cell of type image.
You should treat these bytes exactly as mentioned above: A series of raw bytes.
I've got an angular webapp where I accept images in base64 and store them in T-SQL varbinary. However, I have existing data stored in SQL-Server that appears to be in a different binary. I need both binaries to work with the same Read/Update methods in C#.
In the service I'm trying to convert a base64 string to SQL Server's varbinary and vice versa.
Manually in SSMS, I can take just the base64 string and insert into a row like this:
Cast(#base64ImgStr as varbinary(max))
But the result is different when I try to insert from C#:
Convert.FromBase64String(base64);
(same input). Since the binary is different the image doesn't show. I need a method in C# that provides the same binary as the one in T-SQL.
I must be around the solution, since I can cast and get the proper base64 in SQL Server (again, not in C#) like this:
cast('' as xml).value('xs:base64Binary(sql:variable("#source"))', 'varchar(max)')
Instead of base64 I get back Unicode symbols, otherwise I'd paste in an example.
I need to get the base64 without calling the SQL Server base64Binary method, because my service reads images like this:
Encoding.ASCII.GetString(varbinary)
If I convert the manually inserted varbinary (Cast(#base64ImgStr as varbinary(max))) into varchar(max), I get a base64 string and the image displays appropriately in my webapp.
But, this is not so when I use the C# method to create the binary. With the type of varbinary I get from Convert.FromBase64String(base64), I need an intermediate conversion in SQL Server (xs:base64binary) to reverse the binary to base64. With no intermediate conversion I get Unicode symbols and no image displays in the webapp. I don't want an intermediate conversion because I want consistent results whether users upload images or someone inserts images manually.
I don't see a method on the Convert class that gives me the same type of binary. But that seems to be exactly what I need. I suspect Unicode. Please help!
This worked for me:
var image = Convert.FromBase64String(base64);
string hex = BitConverter.ToString(image);
hex = hex.Replace("-", "");
hex = "0x" + hex;
This hex can be saved in a varbinary(MAX) field without casting or converting and will show as an image in the browser.
Wee bit of background to set the scene : we've told a client he can provide us with images of any type and we'll put them on his reports. I've just had a quick run through of doing this and found that the reports (and other things between me and them) are all designed to only use SVGs.
I thought I'd struck gold when I found online that you can convert an image from a jpg or PNG into an SVG using free tools but alas I've not yet succeeded in getting an SVG stored as bytes in the DB in a format that allows me to use it again after reading it back out.
Here's a quick timeline of what followed leading up to my problem.
I use an online tool to generate an SVG from a PNG (e.g., MobileFish)
I can open and view it in Firefox and it looks ok
I ultimately need the SVG to be stored as bytes in the DB, from where the report will pull it via a webpage that serves it up as SVG. So I write it as bytes into a SQL data script. The code I use to write these bytes is included below.
I visit said webpage and I get an error that there is an "XML parsing error on Line 1 Column 1" and it shows some of my bytes. They begin "3C73"
I revisit the DB and compare the bytes I've just written there with some pre-existing (and working ones). While my new ones begin "3C73", the others begin "0xFFFE".
I think I've probably just pointed out something really fundamental but it hasn't clicked.
Can someone tell me what I've done that means my bytes aren't stored in the correct encoding/format?
When I open my new SVG in Notepad++ I can see the content includes the following which could be relevant :
<image width="900" height="401" xLink:href="data:image/png;base64,
(base 64 encoded data follows for 600+ lines)
Here's the brains of the code that turns my SVG into the bytes to be stored in DB :
var bytes = File.ReadAllBytes(file);
using (var fs = new StreamWriter(file + ".txt"))
{
foreach (var item in bytes)
{
fs.Write(String.Format("{0:X2}",item));
}
}
Any help appreciated.
Cheers
Two things:
SVGs are vector images, not bitmap files. All that online tool is doing is taking a JPEG and creating a SVG file with a JPEG embedded in it. You aren't really getting the benefit of a true SVG image. If you realise and understand that, then no worries.
SVG files are just text. In theory there is no reason you can't just store them as strings in your db. As long as the column is big enough. However normally if you are storing unstructured files in a db, the preferred column type to use is a "Blob".
http://technet.microsoft.com/en-us/library/bb895234.aspx
Converting your SVG file to hex is just making things slower and doubling the size of your files. Also when you convert back, you have to be very careful about the string encoding you are using. Which, in fact, sounds like the problem you are having.
I am suspecting you are doing it incorrectly. SVG is simply and XML based vector image format. I guess your application might be using SVG image element and you need to convert your png image to base64 encoded string .
I want to create a binary file and store string data in it, I used this sample:
FileStream fs = new FileStream("c:\\test.data", FileMode.Create);
BinaryWriter bw = new BinaryWriter(fs);
bw.Write(Encoding.ASCII.GetBytes("david stein"));
bw.Close();
but when I opened created file by this sample (test.data) in notepad, it has string data in it ("david stein"), now my question is that whats the difference between this binary writing and text writing when the result is string?
I'm looking to create a data in binary file until user can not open and read my data by note pad and if user open it in notepad see real binary data .
in some files when you open theme in text editors you can not read file content like jpg files contents,they do not use any encryption methods,what about it?how can i wite my data like this?
now my question is that whats the difference between this binary writing and text writing when the result is string?
The data in a file is always "a sequence of bytes". In this case, the sequence of bytes you've written is "the bytes representing the text 'david stein'" in the ASCII encoding. So yes, if you open the file in any editor which tries to interpret the bytes as text in a way which is compatible with ASCII, you'll see the text "david stein". Really it's just a load of bytes though - it all depends on how you interpret them.
If you'd written:
File.WriteAllText("c:\\test.data", "david stein", Encoding.ASCII);
you'd have ended up with the exact same sequence of bytes. There are any number of ways you could have created a file with the same bytes in. There's nothing about File.WriteAllText which "marks" the file as text, and there's nothing about FileStream or BinaryWriter which marks the file as binary.
EDIT: From comments:
I'm looking to create a data in binary file until user can not open and read my data by note pad
Well, there are lots of ways of doing that with different levels of security. Ideally, you'd want some sort of encryption - but then the code reading the data would need to be able to decrypt it as well, which means it would need to be able to get a key. That then moves the question to "how do I store a key".
If you only need to verify the data in the file (e.g. check that it matches something from elsewhere) then you could use a cryptographic hash instead.
If you only need to prevent the most casual of snoopers, you could use something which is basically just obfuscation - a very weak form of encryption with no "key" as such. Anyone who dceompiled your code would easily be able to get at the data in that case, but you may not care too much about that.
It all depends on your requirements.
All data is binary. A text file is binary data that happens to be a limited subset that represent valid characters, but it's still binary.
The way text editors typically differentiate a text file from a binary file is they scan a certain portion of the file for zero values, \0. These never exist in text-only files and almost always exist in binary files.
I have simple database in Access .mdb file, but I don't know how to deal with: "parameter not valid" exception when Im creating Image from stream.
I'v read that I need to strip 78 bytes offset (from here) but I still get a "parameter not valid" error
when I call FromStream, even after stripping off the first 78 bytes.
This doesn't work for me:
byte[] abytPic = (byte[])dt.Rows[0]["Photo"]; byte arrary with image
if ((abytPic[0] == 21) && (abytPic[1] == 28)) //It's true
{
byte[] abytStripped = new byte[abytPic.Length - 78];
System.Buffer.BlockCopy(abytPic, 78, abytStripped, 0, abytPic.Length - 78);
msPic = new emoryStream(abytStripped);
}
If you are reading the data directly from MS Access, you do not need to strip any header information.
Assuming the image is stored as a BLOB, which is the most common, here is code to read in the array of bytes from the database and store as an image file (sorry, VB instead of C#):
Dim varBytes() As Byte
Using cn As New OleDbConnection(myConnectionString)
cn.Open()
sqlText = "SELECT [myColumn] " _
& "FROM [myTable] " _
& "WHERE ([mySearchCriteria] = '" & mySearchTerm & "')"
Using cm As New OleDbCommand(sqlText, cn)
Dim rdr As OleDbDataReader
rdr = cm.ExecuteReader
rdr.Read()
varBytes = rdr.GetValue(0)
End Using
End Using
My.Computer.FileSystem.WriteAllBytes(myPath & "\myFile.emf", varBytes, True)
This example that I had laying around is one where I knew the files in the database were .emf images. If you know the extension, you can put it on the file name. If you don't, you can leave it blank and then open the resulting with an image viewer; it should start. If you need to find the extension or file type, once it is saved as a file, you can open it with any hex editor and the file type will be available from the header information.
Your question is a little bit unclear, so I'm not sure the above code is exactly what you want, but it should get you a lot closer.
EDIT:
This is the VB code that takes the array of bytes, loads it into a MemoryStream object, and then creates an Image object from the Stream. This bit of code worked just fine, and displayed the image in a picturebox on my form.
Dim img As Image
Dim str As New MemoryStream(varBytes)
img = Image.FromStream(str)
PictureBox1.Image = img
If the C# equivalent of this is not working for you, then the problem is likely in how the image is stored in the MS Access database.
EDIT:
If the image in your database is stored as a 'Package' and not a 'Long binary data', then you will need to strip the header information that MS Access adds. I've been playing with the 'Package' type of image storage with a simple .jpg file. The header in this case is much longer than 78 bytes. In this instance, it's actually 234 bytes, and MS Access also added some information to the end of the original file; about 292 bytes in this case.
It looks like your original approach was correct, you will just need to determine how many bytes to strip off the front and rear of the Byte array for your situation.
I determined it for my file by comparing the original image file, and the file exported from the database, (not to a Stream object, see my first code) in a hex editor. Once I figured out how much information (header and footer) was added by MS Access, I then knew how many bytes needed to be stripped.
EDIT:
The size of the header added by MS Access when the image is stored as 'Package' varies depending on the file type, and the original location (full path information) of the image when it was dumped into the MS Access database. So, even for the same file type, you may have a different number of bytes to strip from the header for each file.
This makes it a lot more difficult, because then you will have to scan the byte array until you find the normal start-of-file information for that file type, and then strip everything before it.
All this headache is one of the reasons that it is better to store images as BLOBs 'Long binary data' in a database. Retrieval is much easier. I don't know if you have the option to do this, but if so, it would be a good idea.
I do not believe that your problem is with the database. "Parameter not valid" exceptions when dealing with imaging can be a total pain as I have dealt with them before. They're not very clear on what the problem is.
How exactly was the image placed into the database? There could be a problem with writing the image into the database before you've even attempted to pull it. Also, what file type is the image?
EDIT Here is some sample code that I've used before to get an image from a byte array.
//takes an array of bytes and converts them to an image.
private Image getImageFromBytes(byte[] myByteArray)
{
System.IO.MemoryStream newImageStream = new System.IO.MemoryStream(myByteArray, 0, myByteArray.Length);
return Image.FromStream(newImageStream, true);
}