-1

I am trying to save a byte array (of an image) to the file system using C# and it isn't working using either method I have tried, here is code sample 1:

string path = @"c:\ppd" + g.ToString() + ".jpg";
        using (MemoryStream inputStream = new MemoryStream(image))
        {
            Image returnImage = Image.FromStream(inputStream);
            returnImage.Save(path, ImageFormat.Jpeg);
        }

With this code I get 'Parameter is not valid' when sending the data to the service. So that's obviously the wrong code for the array, so I hit google and came up with this code:

string path = @"c:\ppd\" + g.ToString() + ".jpg";
        using (MemoryStream inputStream = new MemoryStream(image))
        {
            using (Stream file = File.Create(path))
            {
                byte[] buffer = new byte[8 * 1024];
                int len;
                while ((len = inputStream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    file.Write(buffer, 0, len);
                }
            }
        }

This code writes the file to the file system, but when you try to open it it helpfully says 'This is not a valid bitmap file, or it's format is not currently supported.

We get the byteArray from Flex using:

bitmapData.getPixels(0, 0, bitmapData.width, bitmapData.height);

And the bitmapData comes from the Android camera (via the Distriqt Camera ANE). The image displays fine in the app, but I have no idea where to go next with this, please help.

EDIT: The code in Flex to get the byteArray is:

<s:BitmapImage id="bitmapImage" width="100%"
                 maxHeight="{this.height/2}" 
                 source="{profileModel.captureBitmapPreview}"
                 />

<s:Button click="{dispatchEvent(new PictureEvent
                      (PictureEvent.UPLOAD,
                      0, pictureModel.captureBitmapPreview.getPixels(new Rectangle(0,0,pictureModel.captureBitmapPreview.width,pictureModel.captureBitmapPreview.height))))}"/>
/* this is the alternative which still doesn't work **/
<s:Button click="{dispatchEvent(new PictureEvent
                      (PictureEvent.UPLOAD,
                      0, bitmapImage.getPixels(new Rectangle(0,0,bitmapImage.width,bitmapImage.height))))}"/>

PictureEvent takes 3 parameters, type:String, id:int = 0, image:ByteArray = null.

SECOND EDIT: Here is the code that creates the bitmapData:

private function camera_capturedImageHandler(evt:CameraDataEvent):void
    {
        Camera.instance.setPresetMode(CameraMode.PRESET_MEDIUM);
        Camera.instance.addEventListener(CameraEvent.VIDEO_FRAME, camera_videoFrameHandler, false, 0, true);

        if (_captureBitmapData.width != evt.data.width || _captureBitmapData.height != evt.data.height)
        {
            _captureBitmapData = new BitmapData(evt.data.width, evt.data.height, false);
        }
        _captureBitmapData.draw(evt.data);
        var tbd:BitmapData = new BitmapData(FlexGlobals.topLevelApplication.width, FlexGlobals.topLevelApplication.height, false)
        tbd = applyOrientation(_bitmapData, "6");
        profileModel.captureBitmapPreview.copyPixels(tbd, new Rectangle(0, ((FlexGlobals.topLevelApplication.height/2)-(FlexGlobals.topLevelApplication.height/4)), FlexGlobals.topLevelApplication.width, FlexGlobals.topLevelApplication.height/2), new Point(0, 0));
    }

THIRD EDIT: I has done some testing and discovered that this code should work, it is a variation on the first block above that throws 'Parameter is not valid'

ImageConverter imageConverter = new ImageConverter();
        Bitmap bm = (Bitmap)imageConverter.ConvertFrom(image);

        if (bm != null && (bm.HorizontalResolution != (int)bm.HorizontalResolution || bm.VerticalResolution != (int)bm.VerticalResolution))
        {
            bm.SetResolution((int)(bm.HorizontalResolution + 0.5f),(int)(bm.VerticalResolution + 0.5f));
        }

        bm.Save(path, ImageFormat.Jpeg);

So now I am sure the error is with the byteArray, but I genuinely cannot see what I am doing wrong. I have the bitmapData and it is valid, and it looks like I am collecting the data I need, the written file is nearly 700Kb in size, but something is wrong. If someone could tell me what is wrong on the Flex side of this equation I would be forever grateful. I have the BitmapImage on the display list, it is bound to the model correctly and I have tried different ways of pointing to the source and drawing up the rectangle.

Shaine Fisher
  • 315
  • 1
  • 3
  • 20
  • getPixels only returns pixels. You will need to create a new bitmap and assign its pixels before you will be able to save it or convert it to a JPEG. Here is an example: http://richardleggett.co.uk/blog/2006/08/11/getpixels/ – Lorek Oct 09 '15 at 13:51
  • So (for example) if the pixels were assigned to a bitmap on the stage called 'bitmapImage' and I did bitmapImage.bitmapData.getPixels (...) that would actually work? In which case I have a further question, do I use the 'bitmapImage' height and width or the bitmapData height and width for the Rectangle? – Shaine Fisher Oct 09 '15 at 13:59
  • When you "getPixels" you only get pixels. You don't get all of the other image data like format. If you create a new Bitmap and assign the pixels manually you will then be able to call Save. Show the code where you get the pixels from Flex and I might be able to help more. – Lorek Oct 09 '15 at 14:10
  • amended the question to (hopefully) clarify. – Shaine Fisher Oct 09 '15 at 14:42
  • @Lorek did you get a chance to take a look? My head hurts, lol – Shaine Fisher Oct 10 '15 at 12:52
  • No, I have not. My head hurts, too. If you have the bitmap pixels you should be able to create a Bitmap, set its pixels, then call Save. If that isn't working for you I don't know what to tell you. Sorry. – Lorek Oct 11 '15 at 19:09
  • Well as you can see I create the bitmapData, I bind a bitmapImage to the data and then I use the bitmap as the source for the byteArray, so I feel like I am all good here, however, I did do a few experiments with various sources etc and variations in c# and came to a surprising conclusion, I have 22,765 image stored in a SQL database that are exactly the same, and they work with Flex, so this has been going on for a while. Sadly as I changed to a graph database I decided these needed to be actual images now so I have backed myself into a sort of geeky corner :( – Shaine Fisher Oct 12 '15 at 10:27
  • Hi, You could use something like the Image ANE to convert the bitmap data to jpg byte array before trying to send to your server? http://airnativeextensions.com/extension/com.distriqt.Image Will greatly reduce the amount of data you are sending as well? – Michael Oct 12 '15 at 22:54
  • @Michael, that would be a solution yes, but I have decided that sadly the ANE I was using doesn't fulfill the needs I have, so I am back to using the camera again. I present the byteArray (pixel data) to the app (which works perfectly as a placeholder) and send the file data (full byte array) to the server and process it in C# (rotate, crop, create thumbnail), I was, in this instance, trying to solve a problem that wasn't there, I wanted contacts really, but chose Camera as a shortcut. But I will tell you something, in any other situation I would use this, it is brilliant. – Shaine Fisher Oct 13 '15 at 09:22
  • Can someone tell me about the downvote on this question please? Feedback would be good so I can avoid this situation in the future. – Shaine Fisher Oct 20 '15 at 09:30

1 Answers1

0

Ok, so @Lorek was right, the byteArray just contains pixel data and no formatting information. We don't know why this is the case but based on that knowledge and a little digging in the database I realised that this has been the situation for a while and I needed a solution that would solve it. So in answer to the question 'How do you convert pixel data from a byteArray into an image?' I came up with this, still need a little help, but basically this solves the issue I am having (more after the code)

Bitmap bitmap = new Bitmap(150, 150, PixelFormat.Format32bppRgb);
BitmapData bmData = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
IntPtr pNative = bmData.Scan0;
Marshal.Copy(image, 0, pNative, image.Length);
bitmap.UnlockBits(bmData);
bitmap.Save(path, ImageFormat.Png);

So I change the Rectangle size in Flex so I knew what I was working with, and posted the btyeArray to this method, which beautifully writes out a PNG for me.

It's slightly blue, well it's really blue and I am not quite sure why, take a look: http://ec2-52-89-85-67.us-west-2.compute.amazonaws.com/imagedata/ppd/3898ae89-e4e0-4d03-97d7-dac4e3b618d5.png It is supposed to be black: http://ec2-52-89-85-67.us-west-2.compute.amazonaws.com/imagedata/ppd/capture.png

So any of you .Net people know what happened and can advise me (I heard somewhere that I need to switch the order of the colors so instead of rgb it gets switched around, but I have no idea how or why this would be the issue).

EDIT Here is the solution to that, it's slow, it's pointless and it takes too long: http://www.codeproject.com/Articles/2056/Image-Processing-for-Dummies-with-C-and-GDI-Part-3

Or if maybe we can solve the actual Flex issue that's be great although I have given up all hope of SO being useful for Flex support any more

Thanks you everyone for your patience.

Shaine Fisher
  • 315
  • 1
  • 3
  • 20
  • I just tried to access those PNGs and got 404 errors. Can you put the images somewhere as bitmaps so I can see the uncompressed data? – Lorek Oct 22 '15 at 14:25
  • Sadly not, they were scrap images and when I started migrating my old image data I deleted them, sorry :( – Shaine Fisher Oct 22 '15 at 18:26