byte array created in ActionScript to be used in C# - c#

I have an application that asks users to upload a photo via flash. Flash then turns this photo into a byte array. Here is that code:
var rect:Rectangle=new Rectangle(0,0,imageWidth,imageHeight);
// create BitmapData
var bmd:BitmapData=new BitmapData(imageWidth,imageHeight,true,0);
bmd.draw(myMovieClip);// get the image out of the MovieClip
// create byte array
var binaryData:ByteArray = new ByteArray();
binaryData.position=0;// start at the beginning
binaryData.writeBytes(bmd.getPixels(rect));
After the byte array is created, it is base64 encoded and posted to an IIS server that houses an .ashx handler. In the handlers ProcessRequest method the following code is used to write the data out to a file:
try
{
// Convert from base64string to binary array and save
byte[] contents = Convert.FromBase64String(encodedData); //encodedData is the Base64 encoded byte array from flash
File.WriteAllBytes(fullPath, (byte[])contents);
context.Response.Write("result=1");
}
catch (Exception ex)
{
context.Response.Write("errMsg=" + ex.Message + "&result=0");
}
So far so good. No problems up to this point.
The problem occurs after retrieving the byte data that is stored in the file and attempting to recreate the image on the server side in C#.
When I try the following:
try
{
var fileBytes = File.ReadAllBytes(path);
Bitmap bmp;
using (var ms = new MemoryStream(fileBytes))
{
ms.Position = 0;
using (var i = Image.FromStream(ms, false, true))
{
bmp = new Bitmap(i);
}
}
}
catch (Exception ex)
{
//error: ex.Message is always “the parameter is not valid”
}
The program always throws on this line with the message “the parameter is not valid”
using (var i = Image.FromStream(ms, false, true))
Any advice is greatly appreciated.

BitmapData.getPixels() is just a ByteArray of 32 bit uint values (ARGB) for each pixel, are you sure C# Image.FromStream can handle such format correct? As an alternative you can encode your image to PNG or JPG bytes (there are several PNG/JPG encoders, flex version or as3corelib)

Its turns out that fsbmain is correct above. Image.FromStream does not have the ability to take the data from BitmapData.getPixels() and create an image from it.
In order to get back to the original image, I needed to use Bitmap.SetPixel() and loop thru the byte array setting the ARGB values as shown below:
(please note that the height and width are prepended to the byte array. Thats why I'm using Buffer.BlockCopy to split the array up into the parts that I need)
static void Main(string[] args)
{
string path = #"C:\data\TUIxMTA0ODM5\imagea.b64";
string imagepath = #"C:\data\newPic.jpg";
try
{
//get the data from the file
var f = File.ReadAllBytes(path);
//get the height and width of the image
var newArr = new byte[4];
Buffer.BlockCopy(f, 0, newArr, 0, 4);
var height = ReadShort(newArr, 0);
var width = ReadShort(newArr, 2);
//get the pixel data
var myArr = new byte[f.Length - 4];
Buffer.BlockCopy(f, 4, myArr, 0, f.Length - 4);
//create the new image
var bmp = new Bitmap(width, height);
int counter = 0;
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
bmp.SetPixel(x, y, Color.FromArgb(myArr[counter], myArr[++counter], myArr[++counter], myArr[++counter]));
counter++;
}
}
bmp.Save(imagepath, System.Drawing.Imaging.ImageFormat.Jpeg);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public static short ReadShort(byte[] buffer, int offset)
{
return (short)((buffer[offset + 0] << 8) + buffer[offset + 1]);
}
I hope this helps.

Related

how to control TIFF image header's 1st IFD offset value while generating TIFF?

I would like to know is there a way to control the 4 byte data in TIFF image header which stores the 1st IFD offset value.
I have a situation, when I scan three different image and store directly into file system, it comes with the value [4949 002A 00000080] (hex)
But, using libTiff .net api, when I combine all three images and create one single TIFF, the last four bytes in the header are coming with random value, which is 1st IFD offset.
I have a requirement, where 1st IFD offset should be 00000080.
I am using C# with libTiff .net api to generate TIFF.
Please find the snippet of Code:
Below code creates a Tiff file using the image captured:
using (FileStream file = new FileStream("C:\\imgs\\front.tif", FileMode.Create, System.IO.FileAccess.Write))
{
streamBitmapFront.WriteTo(file);
}
using (FileStream file = new FileStream("C:\\imgs\\gray.tif", FileMode.Create, System.IO.FileAccess.Write))
{
streamBitmapFront2.WriteTo(file);
}
using (FileStream file = new FileStream("C:\\imgs\\rear.tif", FileMode.Create, System.IO.FileAccess.Write))
{
streamBitmapRear.WriteTo(file);
}
front.tif, gray.tif and rear.tif have the correct header data. [4949 002A 00000080] (hex)
Below code uses libTiff.net api to bind all there images and create single tiff image.
using (Tiff output = Tiff.Open( path + uiString + ".IMG", "w"))
{
using (Tiff header = Tiff.Open("C:\\imgs\\gray.tif", "r"))
{
WritePage(output, header, 1, 3, uiString);
}
using (Tiff header = Tiff.Open("C:\\imgs\\front.tif", "r"))
{
WritePage(output, header, 2, 3, uiString);
}
using (Tiff header = Tiff.Open("C:\\imgs\\rear.tif", "r"))
{
WritePage(output, header, 3, 3, uiString);
}
}
public static void WritePage(Tiff output, Tiff input, int pageNumber, int numberOfPages, String name)
{
int height = input.GetField(TiffTag.IMAGELENGTH)[0].ToInt();
int width = input.GetField(TiffTag.IMAGEWIDTH)[0].ToInt();
int samplesPerPixel = 1;
int bitsPerSample = input.GetField(TiffTag.BITSPERSAMPLE)[0].ToInt();
int scanlineSize = input.ScanlineSize();
byte[][] buffer = new byte[height][];
for (int i = 0; i < height; ++i)
{
buffer[i] = new byte[scanlineSize];
input.ReadScanline(buffer[i], i);
}
output.SetField(TiffTag.IMAGEWIDTH, width / samplesPerPixel);
output.SetField(TiffTag.IMAGELENGTH, height);
output.SetField(TiffTag.SAMPLESPERPIXEL, samplesPerPixel);
output.SetField(TiffTag.ORIENTATION, BitMiracle.LibTiff.Classic.Orientation.TOPLEFT);
output.SetField(TiffTag.PLANARCONFIG, PlanarConfig.CONTIG);
output.SetField(TiffTag.SUBFILETYPE, 0);
output.SetField(TiffTag.PHOTOMETRIC, Photometric.MINISWHITE);
output.SetField(TiffTag.ROWSPERSTRIP, height);
if (pageNumber == 1)
{
output.SetField(TiffTag.STRIPOFFSETS, input.GetField(TiffTag.STRIPOFFSETS)[0].ToIntArray()[0]);
//output.SetField(TiffTag.COMPRESSION, Compression.JPEG);
output.SetField(TiffTag.BITSPERSAMPLE, 8);
output.SetField(TiffTag.XRESOLUTION, 120.0);
output.SetField(TiffTag.YRESOLUTION, 120.0);
output.SetField(TiffTag.DOCUMENTNAME, name + "G.JPEG");
}
else
{
if ( pageNumber == 2 )
output.SetField(TiffTag.DOCUMENTNAME, name + "F.TIFF");
if (pageNumber == 3 )
output.SetField(TiffTag.DOCUMENTNAME, name + "R.TIFF");
output.SetField(TiffTag.BITSPERSAMPLE, 1);
output.SetField(TiffTag.COMPRESSION, Compression.CCITT_T6);
output.SetField(TiffTag.XRESOLUTION, 200.0);
output.SetField(TiffTag.YRESOLUTION, 200.0);
}
output.SetField(TiffTag.RESOLUTIONUNIT, ResUnit.INCH);
output.SetField(TiffTag.SUBFILETYPE, FileType.PAGE);
output.SetField(TiffTag.PAGENUMBER, pageNumber, numberOfPages);
for (int i = 0; i < height; ++i)
output.WriteScanline(buffer[i], i);
output.WriteDirectory();
}
Once TIFF image with three pages created the header value is inconsistent.
[4949 002A 0003B210] (hex)
[Update 1]
Stackoverflow answer described about calling output.CheckpointDirectory(); before writing any data into the file. I tried that method also and found, now the last four bytes of the header is changed and it is always same unlike, earlier it was always random. Now I am getting 00000010
Thanks

How Can I Edit Bytes As They Pass Through A Stream?

My goal is to have a file stream open up a user-chosen file, then, it should stream the files bytes through in chunks (buffers) of about 4mb (this can be changed it's just for fun). As the bytes travel (in chunks) through the stream, I'd like to have a looping if-statement see if the bytes value is contained in an array I have declared elsewhere. (The code below will build a random array for replacing bytes), and the replacement loop could just say something like the bottom for-loop. As you can see I'm fairly fluent in this language but for some reason the editing and rewriting of chunks as they are read from a file to a new one is eluding me. Thanks in advance!
private void button2_Click(object sender, EventArgs e)
{
GenNewKey();
const int chunkSize = 4096; // read the file by chunks of 4KB
using (var file = File.OpenRead(textBox1.Text))
{
int bytesRead;
var buffer = new byte[chunkSize];
while ((bytesRead = file.Read(buffer, 0, buffer.Length)) > 0)
{
byte[] newbytes = buffer;
int index = 0;
foreach (byte b in buffer)
{
for (int x = 0; x < 256; x++)
{
if (buffer[index] == Convert.ToByte(lst[x]))
{
try
{
newbytes[index] = Convert.ToByte(lst[256 - x]);
}
catch (System.Exception ex)
{
//just to show why the error was thrown, but not really helpful..
MessageBox.Show(index + ", " + newbytes.Count().ToString());
}
}
}
index++;
}
AppendAllBytes(textBox1.Text + ".ENC", newbytes);
}
}
}
private void GenNewKey()
{
Random rnd = new Random();
while (lst.Count < 256)
{
int x = rnd.Next(0, 255);
if (!lst.Contains(x))
{
lst.Add(x);
}
}
foreach (int x in lst)
{
textBox2.Text += ", " + x.ToString();
//just for me to see what was generated
}
}
public static void AppendAllBytes(string path, byte[] bytes)
{
if (!File.Exists(path + ".ENC"))
{
File.Create(path + ".ENC");
}
using (var stream = new FileStream(path, FileMode.Append))
{
stream.Write(bytes, 0, bytes.Length);
}
}
Where textbox1 holds the path and name of file to encrypt, textBox2 holds the generated cipher for personal debugging purposes, button two is the encrypt button, and of course I am using System.IO.
Indeed you have a off by one error in newbytes[index] = Convert.ToByte(lst[256 - x])
if x is 0 then you will have lst[256], however lst only goes between 0-255. Change that to 255 should fix it.
The reason it freezes up is your program is EXTREMELY inefficient and working on the UI thread (and has a few more errors like you should only go up to bytesRead in size when processing buffer, but that will just give you extra data in your output that should not be there. Also you are reusing the same array for buffer and newbytes so your inner for loop could modify the same index more than once because every time you do newbytes[index] = Convert.ToByte(lst[256 - x]) you are modifying buffer[index] which will get checked again the next itteration of the for loop).
There is a lot of ways you can improve your code, here is a snippet that does similar to what you are doing (I don't do the whole "find the index and use the opposite location", I just use the byte that is passed in as the index in the array).
while ((bytesRead = file.Read(buffer, 0, buffer.Length)) > 0)
{
byte[] newbytes = new byte[bytesRead];
for(int i = 0; i < newbytes.Length; i++)
{
newbytes[i] = (byte)lst[buffer[i]]))
}
AppendAllBytes(textBox1.Text + ".ENC", newbytes);
}
This may also lead to freezing but not as much, to solve the freeing you should put all of this code in to a BackgroundWorker or similar to run on another thread.

WindowsForm - Load picturebox.image from a xml

I'm having trouble loading an image "string" in the PictureBox control.
I am not able to find a way to charge it and do not know if it is possible to do it that way.
I tried the following code, but without success:
1st
var s= "0x89504E470D0A1A0A0000000D49484452000000900000005B0802000000130B9B9
8000000017352474200AECE1CE90000000467414D410000B18F0BFC6105000000097048597300000EC300000EC301C76FA8640000013B49444154785EEDD6410D00211443418470C4BF333C808977F8C9242B8094CE9675F7F10D4A600D3AABA3FE045CD8B01F8C0B736146B14C8030C2CA7E7977104618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB863DFFBF32F5C2C8C5B40000000049454E44AE426082";
picture.Image = Base64ToImage(s);
static Image Base64ToImage(string base64String)
{
byte[] imageBytes = Convert.FromBase64String(base64String);
MemoryStream ms = new MemoryStream(imageBytes);
return Image.FromStream(ms, true);
}
Can anyone help!?
This seems to be a red rectangle 91*144 if decoded properly.
remove 0x and space from string.
convert string to byte[] - I used converter found on StackOverFlow the one by CainKellye (How can I convert a hex string to a byte array?)
string s = "89504E470D0A1A0A0000000D49484452000000900000005B0802000000130B9B98000000017352474200AECE1CE90000000467414D410000B18F0BFC6105000000097048597300000EC300000EC301C76FA8640000013B49444154785EEDD6410D00211443418470C4BF333C808977F8C9242B8094CE9675F7F10D4A600D3AABA3FE045CD8B01F8C0B736146B14C8030C2CA7E7977104618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB86114618616502841156F6CB863DFFBF32F5C2C8C5B40000000049454E44AE426082";
byte[] imageBytes = StringToByteArrayFastest(s);
MemoryStream ms = new MemoryStream(imageBytes);
Bitmap bmp = (Bitmap)Image.FromStream(ms);
pictureBox1.Image = bmp;
and the result is:
I don't think s is a base 64 string, it looks more like hexadecimal - it even still has 0x in front of it and the 'digits' are no higher than F. You should definitely remove the 0x in front. To get a base 64 string, you could use the code from this website (I haven't tested it):
public static string ConvertHexStringToBase64(string hexString)
{
if (hexString.Length % 2 > 0)
throw new FormatException("Input string was not in a correct format.");
if (Regex.Match(hexString, "[^a-fA-F0-9]").Success == true)
throw new FormatException("Input string was not in a correct format.");
byte[] buffer = new byte[hexString.Length / 2];
int i=0;
while (i < hexString.Length) {
buffer[i / 2] = byte.Parse(hexString.Substring(i, 2), System.Globalization.NumberStyles.HexNumber);
i += 2;
}
return Convert.ToBase64String(buffer);
}

"Parameter not valid" error when trying to save the image converted from byte

currently I am testing a script that tries to save an image file converted from a string of HEX, however, when I try to execute the Save command, parameter not valid appears.
// Some junk hex image data
string hexImgData = #"FFD8FFE000104A46494600010200006400640000FFFFD9";
// Call function to Convert the hex data to byte array
byte[] newByte = ToByteArray(hexImgData);
MemoryStream memStream = new MemoryStream(newByte);
// Save the memorystream to file
Bitmap.FromStream(memStream).Save("C:\\img.jpg");
// Function converts hex data into byte array
public static byte[] ToByteArray(String HexString)
{
int NumberChars = HexString.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
{
bytes[i / 2] = Convert.ToByte(HexString.Substring(i, 2), 16);
}
return bytes;
}
Currently I am still in the process of looking what causes this, please advice.
As was mentioned in the comments, your bitmap format is wrong, all you have is some random hex data and the Bitmap.FromStream method has no idea what to do with it. If you look at this link which discusses how to create a bitmap file with a hex editor it discusses the BitmapHeader, BitmapInfoHeader, and the Pixel RGB Data. I was able to create a bitmap using your code by taking the data from their example and using it.
string bitmapHeader = "424D860000000000000036000000";
string bitmapInfoHeader = "280000000500000005000000010018000000000050000000C40E0000C40E00000000000000000000";
string pixelData = "0000FF0000FF0000FF0000FF0000FF000000FF0000FF0000FF0000FF0000FF000000FF0000FF0000FF0000FF0000FF000000FF0000FF0000FF0000FF0000FF000000FF0000FF0000FF0000FF0000FF00";
string hexImgData = bitmapHeader + bitmapInfoHeader + pixelData;
// Call function to Convert the hex data to byte array
byte[] newByte = ToByteArray(hexImgData);
MemoryStream memStream = new MemoryStream(newByte);
pictureBox1.Image = Bitmap.FromStream(memStream);
It seems you need convert incoming string from Base64 to byte array like this:
byte[] encodedDataAsBytes = System.Convert.FromBase64String(encodedData);

zlib from C++ to C#(How to convert byte[] to stream and stream to byte[])

My task is to decompress a packet(received) using zlib and then use an algoritm to make a picture from the data
The good news is that I have the code in C++,but the task is to do it in C#
C++
//Read the first values of the packet received
DWORD image[200 * 64] = {0}; //used for algoritm(width always = 200 and height always == 64)
int imgIndex = 0; //used for algoritm
unsigned char rawbytes_[131072] = {0}; //read below
unsigned char * rawbytes = rawbytes_; //destrination parameter for decompression(ptr)
compressed = r.Read<WORD>(); //the length of the compressed bytes(picture)
uncompressed = r.Read<WORD>(); //the length that should be after decompression
width = r.Read<WORD>(); //the width of the picture
height = r.Read<WORD>(); //the height of the picture
LPBYTE ptr = r.GetCurrentStream(); //the bytes(file that must be decompressed)
outLen = uncompressed; //copy the len into another variable
//Decompress
if(uncompress((Bytef*)rawbytes, &outLen, ptr, compressed) != Z_OK)
{
printf("Could not uncompress the image code.\n");
Disconnect();
return;
}
//Algoritm to make up the picture
// Loop through the data
for(int c = 0; c < (int)height; ++c)
{
for(int r = 0; r < (int)width; ++r)
{
imgIndex = (height - 1 - c) * width + r;
image[imgIndex] = 0xFF000000;
if(-((1 << (0xFF & (r & 0x80000007))) & rawbytes[((c * width + r) >> 3)]))
image[imgIndex] = 0xFFFFFFFF;
}
}
I'm trying to do this with zlib.NET ,but all demos have that code to decompress(C#)
private void decompressFile(string inFile, string outFile)
{
System.IO.FileStream outFileStream = new System.IO.FileStream(outFile, System.IO.FileMode.Create);
zlib.ZOutputStream outZStream = new zlib.ZOutputStream(outFileStream);
System.IO.FileStream inFileStream = new System.IO.FileStream(inFile, System.IO.FileMode.Open);
try
{
CopyStream(inFileStream, outZStream);
}
finally
{
outZStream.Close();
outFileStream.Close();
inFileStream.Close();
}
}
public static void CopyStream(System.IO.Stream input, System.IO.Stream output)
{
byte[] buffer = new byte[2000];
int len;
while ((len = input.Read(buffer, 0, 2000)) > 0)
{
output.Write(buffer, 0, len);
}
output.Flush();
}
My problem:I don't want to save the file after decompression,because I have to use the algoritm shown in the C++ code.
How to convert the byte[] array into a stream similiar to the one in the C# zlib code to decompress the data and then how to convert the stream back into byte array?
Also,How to change the zlib.NET code to NOT save files?
Just use MemoryStreams instead of FileStreams:
// Assuming inputData is a byte[]
MemoryStream input = new MemoryStream(inputData);
MemoryStream output = new MemoryStream();
Then you can use output.ToArray() afterwards to get a byte array out.
Note that it's generally better to use using statements instead of a single try/finally block - as otherwise if the first call to Close fails, the rest won't be made. You can nest them like this:
using (MemoryStream output = new MemoryStream())
using (Stream outZStream = new zlib.ZOutputStream(output))
using (Stream input = new MemoryStream(bytes))
{
CopyStream(inFileStream, outZStream);
return output.ToArray();
}
I just ran into this same issue.
For Completeness... (since this stumped me for several hours)
In the case of ZLib.Net you also have to call finish(), which usually happens during Close(), before you call return output.ToArray()
Otherwise you will get an empty/incomplete byte array from your memory stream, because the ZStream hasn't actually written all of the data yet:
public static void CompressData(byte[] inData, out byte[] outData)
{
using (MemoryStream outMemoryStream = new MemoryStream())
using (ZOutputStream outZStream = new ZOutputStream(outMemoryStream, zlibConst.Z_DEFAULT_COMPRESSION))
using (Stream inMemoryStream = new MemoryStream(inData))
{
CopyStream(inMemoryStream, outZStream);
outZStream.finish();
outData = outMemoryStream.ToArray();
}
}
public static void DecompressData(byte[] inData, out byte[] outData)
{
using (MemoryStream outMemoryStream = new MemoryStream())
using (ZOutputStream outZStream = new ZOutputStream(outMemoryStream))
using (Stream inMemoryStream = new MemoryStream(inData))
{
CopyStream(inMemoryStream, outZStream);
outZStream.finish();
outData = outMemoryStream.ToArray();
}
}
In this example I'm also using the zlib namespace:
using zlib;
Originally found in this thread:
ZLib decompression
I don't have enough points to vote up yet, so...
Thanks to Tim Greaves for the tip regarding finish before ToArray
And Jon Skeet for the tip regarding nesting the using statements for streams (which I like much better than try/finally)

Categories

Resources