Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FileStream to Byte[]: Windows XP vs Windows 8

I recently had to write some code that:

  • UI takes a file (image)
  • Converts to `byte[]
  • Uploads the byte[] to a website (using HttpWebRequest. ContentType is multipart/form-data)
  • Website then reads the stream, use the parameters that I sent with the file, stores the byte[] in a database.

This image is then used in reports and the user can download the image whenever. And this worked fine, until we started testing it on a windows XP machine. Whenever I upload any image from the XP pc, the image wouldn't show. After some debugging and testing and writing this multipart/form-data to a text file, I saw that the byte[] of the file differed on Windows XP vs Windows 8 (or even 7). The generated file's size differed as well.

I'm using VS2012 with .Net 4.0, and did install (and repaired again) .Net 4 on the XP pc. I can only think that either the two operating systems encode differently or perhaps its a difference between 32-bit OS and 64-bit. Obviously I have no idea what is wrong, and don't even know where to start. I'd like to know if someone can just point me in the right direction?

Here is the UI-side code:

//Wrapped around each parameter. The last boundary after the byte[] file >has been omitted.
string boundary = "----------------------------" + >DateTime.Now.Ticks.ToString("x");

//Creating the httpWebRequest as multipart with "POST" method.
httpWebRequest = (HttpWebRequest)WebRequest.Create(_webUploadUrl);
httpWebRequest.ContentType = "multipart/form-data; boundary=" + boundary;
httpWebRequest.Method = "POST";
httpWebRequest.KeepAlive = true;
httpWebRequest.Credentials = >System.Net.CredentialCache.DefaultCredentials;

//Upload stream will be built with all the parameters, followed by the >byte[] file.
Stream uploadStream = new System.IO.MemoryStream();


byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes(boundary + >"\r\n");


string formdataTemplate = "\r\n--" + boundary +
"\r\nContent-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}";

//Parameters:
//Foreach parameter, Wrap in boundary
foreach (string key in _nvcParameters.Keys)
{
    string formitem = string.Format(formdataTemplate, key, >_nvcParameters[key]);
    byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
    uploadStream.Write(formitembytes, 0, formitembytes.Length);
}

byte[] netBytes = System.Text.Encoding.ASCII.GetBytes("\r\n--");
uploadStream.Write(netBytes, 0, netBytes.Length);

//The actual file:           
uploadStream.Write(boundarybytes, 0, boundarybytes.Length);
string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; >filename=\"{1}\"\r\n Content-Type: application/octet-stream\r\n\r\n";
string header = string.Format(headerTemplate, "uplTheFile", _fileName);
byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
uploadStream.Write(headerbytes, 0, headerbytes.Length);

//While file is greater than buffer, write to uploadStream.
byte[] buffer = new byte[1024];
int bytesRead = 0;
long fileSize = pFileStream.Length;            
long uploadedValue = 0;

while ((bytesRead = (pFileStream).Read(buffer, 0, buffer.Length)) != 0)
{
    uploadStream.Write(buffer, 0, bytesRead);
    Application.DoEvents();
}
httpWebRequest.ContentLength = uploadStream.Length;
//Close the original fileStream.
pFileStream.Close();

The website uses UTF8. I can post it if needed, but because the byte[]s differ, I thought the problem might be there.


@Ramhound The use of long? are you referring to the fileSize and uploadedValue variables? The code is part of company's UI-side of the system, very big and I'm just starting to know my way around some parts, anyways, I've checked the Project's properties, (if that is the right place to check). At the build the Platform target is x86. Are you talking about that or something else? Sorry I'm still a student and new to c# (and vs for that matter)

I've opened both files on Windows 8 machine. The win8 file size is 6kb bigger and contains more characters, obviously.

Here is the first few lines of the array. The _ncvParameters are the same (as well as the file uploaded, Here is the first part of the resulting multipart-form (ncvParameters followed by the first few lines of the byte[] file):

Win8:

------------------------------8d00a632401f30e Content-Disposition: form-data; name="o";

25 ------------------------------8d00a632401f30e Content-Disposition: form-data; name="k";

2913 ------------------------------8d00a632401f30e Content-Disposition: form-data; name="u";

255 ------------------------------8d00a632401f30e Content-Disposition: form-data; name="f";

Blue hills.jpg ------------------------------8d00a632401f30e Content-Disposition: form-data; name="m";

image/jpeg ------------------------------8d00a632401f30e Content-Disposition: form-data; name="uplTheFile"; filename="Blue hills.jpg" Content-Type: application/octet-stream

‰PNG

IHDR  €  à   5ÑÜä   sRGB ®Îé   gAMA  ±üa      pHYs  à  ÃÇo¨d  ÿ¥IDATx^ìýg—\7²­ëÿ÷¾gïî–§÷¤H9Š¢DR”—Ú{Ç6²”÷M‘yç¹V$™UÅ–úô>÷|˜@

˜ÌÄ2y×?oݾøáíÛWþ±õŸ†[w€‘õøû-pëÊßnï㺷Ã؇uxK¾í

WinXP:

------------------------------8d00a639ff7bf76 Content-Disposition: form-data; name="o";

25 ------------------------------8d00a639ff7bf76 Content-Disposition: form-data; name="k";

2913 ------------------------------8d00a639ff7bf76 Content-Disposition: form-data; name="u";

255 ------------------------------8d00a639ff7bf76 Content-Disposition: form-data; name="f";

Blue hills.jpg ------------------------------8d00a639ff7bf76 Content-Disposition: form-data; name="m";

image/jpeg ------------------------------8d00a639ff7bf76 Content-Disposition: form-data; name="uplTheFile"; filename="Blue hills.jpg" Content-Type: application/octet-stream

‰PNG

IHDR         ĉ   sRGB ®Îé   gAMA  ±üa    cHRM  z&  €„  ú   €è  u0  ê`  :˜  pœºQ<   IDATWc`    ªÕÈQ   

IEND®B`‚’èÊû:uÊžòÞ°Ë[=)Qä¡w¢%º2§Î~󙉬½×f±¤~¯×1‰H$01#ùßÿâ‹ÿ¯¿¸äÿý‡‹—ü;üX§¿8(ýQ$?º$ÓÿþéÚêÀBTÿpà%•~ÖbºËá þÝü8ù­Ÿ:å_ø(IÿGã‹þâ/Æ Cô¨Í.*›QV


@Xaqron - uploadStream is a memoryStream. The entire multipart-form is written to this stream, which then writes to a byte[]. Which gets streamed to httpWebRequest.

I'm pretty sure its the same image. I've tried it twice just to make sure. I'll triple-check today at the office - Yes, I've done it multiple times now. The same image produces different sizes and different byte[] characters.


Ok, I think I've found the problem. This may have been useful information, but I didn't even think this would be the issue. The file uploaded is an image, which I resize. The resizing method takes a byte[] (the one I thought was incorrectly encoded), writes it to a bitmap. This bitmap is then 'redrawn' to a new size with PixelFormat.Format32bppRgb and InterpolationMode.HighQualityBicubic:

if (pImage.Height < maxHeight && pImage.Width < maxWidth) return pImage;  
using (pImage)  
{  
    Double xRatio = (double)pImage.Width / maxWidth;
    Double yRatio = (double)pImage.Height / maxHeight;
    Double ratio = Math.Max(xRatio, yRatio);
    int nnx = (int)Math.Floor(pImage.Width / ratio);
    int nny = (int)Math.Floor(pImage.Height / ratio);
    System.Drawing.Bitmap cpy = new System.Drawing.Bitmap(nnx, nny, System.Drawing.Imaging.PixelFormat.Format32bppRgb);
    using (System.Drawing.Graphics gr = System.Drawing.Graphics.FromImage(cpy))
    {  
        gr.Clear(System.Drawing.Color.Transparent);

        gr.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

        gr.DrawImage(pImage,
            new System.Drawing.Rectangle(0, 0, nnx, nny),
            new System.Drawing.Rectangle(0, 0, pImage.Width, pImage.Height),
            System.Drawing.GraphicsUnit.Pixel);
    }
    return cpy;
}

I changed the PixelFormat mode to 'DontCare' and the InterpolationMode to Default. Sorry it this would've been obvious, but I thought this was handled by the .net framework?

like image 713
Bezaleel Avatar asked Apr 18 '13 17:04

Bezaleel


1 Answers

Windows XP and newer os'es like 7 and 8 are encoding and decoding things differently. What i can suggest for you is encode your byte array into BASE64 before transferring. Then receive it and decode back to your byte array. .Net has easy methods to encode and decode base64. Since base64 text is 7 bit ascii there will be no problem transferring it.

like image 76
Mert Gülsoy Avatar answered Oct 31 '22 16:10

Mert Gülsoy