I'm writing a Ruby/Rhomobile application that takes an image, encodes it in base64 and sends to the server(that is running C# on ASP.NET), as part of a bigger XML.
However, once I try to decode the base64 and save it to the hard disk, the resulting file does not work as an image.
Here's the relevant ruby code:
image_element = REXML::Element.new("image")
image_element.text = Base64.encode64(open(Rho::RhoApplication::get_blob_path(self.image_uri)) { |io| io.read })
form_element.add_element(image_element)
And here is my C# code:
var doc = new XmlDocument();
doc.LoadXml(Server.UrlDecode(Request.Form[0]));
var imageBase64 = doc.SelectNodes("//image")[0];
var imageBytes = imageBase64.InnerText;
using(var imgWriter = new FileStream(#"c:\img.jpg",FileMode.Create))
{
imgWriter.Write(imageBytes,0,imageBytes.Length);
}
I would investigate your call to Server.UrlDecode. It seems like that could corrupt your data.
It seems like the "+" sign is of specific concern, per this SO question. Server.UrlDecode uses HttpServerUtility.UrlDecode, and here's the documentation for it.
Related
I want to attach pdf from url into CRM "activitymimeattachment". Everything works fine but im getting empty pdf attachments (even the size is the same as original pdf). Could it be some problem with Encoding or converting? Maybe somebody could help me with this?
I see that email is created with attachment which is empty, but the size is the same as for original pdf.
Entity attachment = new Entity("activitymimeattachment");
attachment["subject"] = "Attachment";
string fileName = "Invoice.pdf";
attachment["filename"] = fileName;
WebClient wc = new WebClient();
string theTextFile = wc.DownloadString(url);
byte[] fileStream = Encoding.ASCII.GetBytes(theTextFile);
attachment["body"] = Convert.ToBase64String(fileStream);
attachment["mimetype"] = "application/pdf";
attachment["attachmentnumber"] = 1;
attachment["objectid"] = new EntityReference("email", emailguid);
attachment["objecttypecode"] = "email";
service.Create(attachment);
I believe the encoding is issue. The PDF is neither a string nor an ASCII file so these lines are at fault:
string theTextFile = wc.DownloadString(url);
byte[] fileStream = Encoding.ASCII.GetBytes(theTextFile);
I would suggest changing your web client to download a binary file i.e. application/pdf and save the file locally e.g to d:\temp\invoice.pdf.
Then you can do this:
var bytes = File.ReadAllBytes(#"d:\temp\invoice.pdf");
var body = Convert.ToBase64String(bytes);
In short, avoid trying to put the PDF into a string, or using the ASCII encoding to get its byte array. It's a binary file until you convert it to Base64.
Of course you can also probably get your web client to download the file into memory and convert it to Base64 without writing the file locally. I just wanted the simplest example to make the point about the encoding.
Thank You for advice #Aron. I actually have found a solution which is very simnply. I just used another method from WebClient class. The main thing I needed to change DownloadString(url) method into DownloadData(url) method:
WebClient wc = new WebClient();
byte[] theTextFile = wc.DownloadData(url);
attachment["body"] = Convert.ToBase64String(theTextFile);enter code here
I am trying to convert byte[] to base64 string format so that i can send that information to third party. My code as below:
byte[] ByteArray = System.IO.File.ReadAllBytes(path);
string base64Encoded = System.Convert.ToBase64String(ByteArray);
I am getting below error:
Exception of type 'System.OutOfMemoryException' was thrown. Can you
help me please ?
Update
I just spotted #PanagiotisKanavos' comment pointing to Is there a Base64Stream for .NET?. This does essentially the same thing as my code below attempts to achieve (i.e. allows you to process the file without having to hold the whole thing in memory in one go), but without the overhead/risk of self-rolled code / rather using a standard .Net library method for the job.
Original
The below code will create a new temporary file containing the Base64 encoded version of your input file.
This should have a lower memory footprint, since rather than doing all data at once, we handle it several bytes at a time.
To avoid holding the output in memory, I've pushed that back to a temp file, which is returned. When you later need to use that data for some other process, you'd need to stream it (i.e. so that again you're not consuming all of this data at once).
You'll also notice that I've used WriteLine instead of Write; which will introduce non base64 encoded characters (i.e. the line breaks). That's deliberate, so that if you consume the temp file with a text reader you can easily process it line by line.
However, you can amend per your needs.
void Main()
{
var inputFilePath = #"c:\temp\bigfile.zip";
var convertedDataPath = ConvertToBase64TempFile(inputFilePath);
Console.WriteLine($"Take a look in {convertedDataPath} for your converted data");
}
//inputFilePath = where your source file can be found. This is not impacted by the below code
//bufferSizeInBytesDiv3 = how many bytes to read at a time (divided by 3); the larger this value the more memory is required, but the better you'll find performance. The Div3 part is because we later multiple this by 3 / this ensures we never have to deal with remainders (i.e. since 3 bytes = 4 base64 chars)
public string ConvertToBase64TempFile(string inputFilePath, int bufferSizeInBytesDiv3 = 1024)
{
var tempFilePath = System.IO.Path.GetTempFileName();
using (var fileStream = File.Open(inputFilePath,FileMode.Open))
{
using (var reader = new BinaryReader(fileStream))
{
using (var writer = new StreamWriter(tempFilePath))
{
byte[] data;
while ((data = reader.ReadBytes(bufferSizeInBytesDiv3 * 3)).Length > 0)
{
writer.WriteLine(System.Convert.ToBase64String(data)); //NB: using WriteLine rather than Write; so when consuming this content consider removing line breaks (I've used this instead of write so you can easily stream the data in chunks later)
}
}
}
}
return tempFilePath;
}
I have an example in C# and have to write the same in PHP.
request = request.Replace(sign, string.Empty);
byte[] sha1Request;
using (var shaM = new SHA1Managed())
{
sha1Request = shaM.ComputeHash(Encoding.UTF8.GetBytes(request));
}
log.InfoFormat($"request={request}. sha1Request={Convert.ToBase64String(sha1Request)}. Sign={sign}", request, Convert.ToBase64String(sha1Request));
var pubKey = (RSACryptoServiceProvider)FrontInterface.GetCertificate(checkFrontCertificateCod.Value).PublicKey.Key;
var isValid = pubKey.VerifyData(Encoding.UTF8.GetBytes(Convert.ToBase64String(sha1Request)), new SHA1CryptoServiceProvider(), Convert.FromBase64String(sign));
if (!isValid)
{
throw new Exception("Wrong digital sign");
}
So, I may not convert string to bytes in php and line sha1Request = shaM.ComputeHash(Encoding.UTF8.GetBytes(request));
will be in PHP: sha1Request =sha1(request, true);
Am I rigth? If not, please help me to convert in PHP this line.
Thanks a lot.
Note that sha1 should not really be used any more for security relevant applications, it is out of date.
C# Version:
string text = "<Hällo World>";
byte[] sha1;
using (var shaM = new SHA1Managed())
{
sha1 = shaM.ComputeHash(Encoding.UTF8.GetBytes(text));
}
string encoded = Convert.ToBase64String(sha1);
Console.Write(encoded);
PHP Version:
$text = "<Hällo World>";
// Encode as UTF8 if necessary (May not be necessary if string is already utf-8)
$text = utf8_encode($text);
// Calculate SHA1
$sha1 = sha1($text, TRUE);
// Convert to Base64
$encoded = base64_encode($sha1);
echo($encoded);
Both versions should output
1nSiStZRa/quRru7Sqe+ejupqfs=
Note that the call to utf8_encode should only be there if the string you work with is not actually already encoded in utf8.
If the string is a literal in a *.php file, this depends on how the file is stored on the disk. (What character set it uses).
If the string is retrieved from a web request or from a database or from reading a file, this also depends on what character set the web form, the database or the external file use.
I want to download text and html parts from mime message and store it in the database and later if needed to download attachments. I need this because I don't want to store the attachments in my database to save disk space and bandwidth. They will be downloaded on demand later. I am not sure if I can do that and still be able to use MimeParser from MimeKit
I am planning to do that:
Get message body structure and find the text and html parts
Download text and html body parts using ImapFolder.GetStream and store in database preserving mime tree structure by saving section names along with headers. Attachment will not be downloaded
Later I want to show the message in the UI but I want to delay parsing until the mail message needs to be shown in the UI.
This is my progress so far
var msgSummaries = remoteFolder.Fetch(new int[] { remoteMessage.Index }, MessageSummaryItems.BodyStructure);
var stream = remoteFolder.GetStream(remoteMessage.Index, msgSummaries[0].HtmlBody.PartSpecifier);
//at this point i am saving the stream to the database and later i am trying to convert it to mime entity like that
var parser = new MimeParser(ParserOptions.Default, stream, true);
var mimeEntity = parser.ParseEntity(cancellationToken);
Unfortunatelly the stream doesn't contain mime part headers and cannot be parsed and I don't see an option to request headers inside GetStream method like this
FETCH 1 (BODY.PEEK[2.MIME] BODY.PEEK[2])
Any suggestions?
Well, first of all, have you tried:
var mimeEntity = remoteFolder.GetBodyPart (remoteMessage.Index, msgSummaries[0].HtmlBody);
or, if you really want to use streams:
var headerStream = remoteFolder.GetStream (remoteMessage.Index, msgSummaries[0].HtmlBody.PartSpecifier + ".MIME");
var contentStream = remoteFolder.GetStream (remoteMessage.Index, msgSummaries[0].HtmlBody.PartSpecifier);
var stream = new MemoryStream ();
headerStream.CopyTo (stream);
headerStream.Dispose ();
contentStream.CopyTo (stream);
contentStream.Dispose ();
stream.Position = 0;
//at this point i am saving the stream to the database and later i am trying to convert it to mime entity like that
var parser = new MimeParser(ParserOptions.Default, stream, true);
var mimeEntity = parser.ParseEntity(cancellationToken);
From my android I am trying to send an image with a class of data, to an IIS webservice. (C#)
The problem is I get 400 Bad request.
The image is being encoded to Base64. And then placed into json with the rest of the class elements.
My guess is that Base64 is not valid inside a Json. So the server does not understand it.
If I set the string to be "", the post is accepted fine.
So the question is, how do I make my Base64 valid from within a Json array? ( I tried URL.Encode with no success).
Or How should you send an image from android to webservice?
Gson gson = new Gson();
String json = gson.toJson(record); // record has param { String base64Photo }
How big is the image? I'm pretty sure you are surpassing the IIS Json size limit (default is almost 4 MB).
Check this http://geekswithblogs.net/frankw/archive/2008/08/05/how-to-configure-maxjsonlength-in-asp.net-ajax-applications.aspx or this http://www.webtrenches.com/post.cfm/iis7-file-upload-size-limits
Good luck!
I'll be honest - I've never uploaded an image from Android to an IIS webservice but in every other context I've always just used a File. It's easy to create a file and upload it as a MultipartEntity. Plus you avoid having to use Base64 all together, which is good because it saves you the roughly 33% increased overhead that comes with using Base64.
private File createFileFromBm(Bitmap pic){
File f = new File(context.getCacheDir(), "image");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
pic.compress(CompressFormat.JPEG, 100, bos);
byte[] data = bos.toByteArray();
try{
FileOutputStream fos = new FileOutputStream(f);
fos.write(data);
fos.close();
} catch (IOException e){
Log.e(TAG, e.toString());
}
return f;
}
Here's how you create a MultipartEntity
MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE;
entity.addPart("photo", new FileBody(file, "image/jpeg"));
httpPost.setEntity(entity);
return httpClient.execute(httpPost, responseHandler);
I used an HttpPost here and a BasicResponseHandler to receive the JSON output from the server for processing but you can do whatever you like.