8 Replies Latest reply: Aug 24, 2012 6:50 AM by the0bot RSS

    My image is one size, the byte array is another?

    the0bot

      I have a very similar problem, but no solution:

      I need to png encode an Image that is 130 x 30 but the byteArray it was created with is not long enough. I can see it right in front of me.

       

      <?xml version="1.0" encoding="utf-8"?>
      <mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml"
          width="160" height="114" horizontalAlign="center">

       

      <mx:Script>
        <![CDATA[
         import mx.core.Application;
         import mx.core.IFlexDisplayObject;
         import mx.graphics.codec.PNGEncoder;
         import mx.managers.PopUpManager;
        
         private static var instance:Test = null;
         private var strng:String ="";
         private var png:ByteArray;
         private var result:ByteArray;
        
         public static function ready(str:String):void{
          if (instance == null) instance = new Test();
          instance.strng = str;
          instance.show();
         }
         
         private function show() : void {
          result = stringToByteArray(strng);
          if (!this.isPopUp) {
           setPopupHelpWindowStyle(this);
           PopUpManager.addPopUp(this, Application.application  as DisplayObject, false);
           PopUpManager.centerPopUp(this);
          }
          img.load(result);
         }
        
         private static function setPopupHelpWindowStyle(ifdo:IFlexDisplayObject) : void {
          var isc:IStyleClient = IFlexDisplayObject(ifdo) as IStyleClient;
          isc.setStyle("modalTransparency", 1);
         }
        
         private static function stringToByteArray(str:String) : ByteArray {
          var result:ByteArray = new ByteArray();
          var i:int = 0;
          while (i < str.length) {
           result.writeByte(Number("0x" + str.substr(i, 2)));
           i += 2;
          }
          return result;
         }
        
         public function encode():void{
          var coder:PNGEncoder = new PNGEncoder;
          instance.png = coder.encodeByteArray(instance.result, instance.img.width, instance.img.height);
          }
        ]]>
      </mx:Script>
      <mx:Image id="img" x="10" y="10" width="130" height="30"/>
      <mx:Button label="Button" click="encode()"/>
      </mx:TitleWindow>

       

      When I try to encode it I get:

       

      Error: Error #2030: End of file was encountered.
      at flash.utils::ByteArray/readUnsignedInt()
       
      I get an error because bArray is created from a string that is only 3540 characters long, which is only 1720 bytes. I can see the image, and it fills the entire box, but I do not know what type of alogorthm is used to expand the byteArray to fill it.

       

      Is there a method to access the pixels of the image similar to the BitmapData function, where I can iterate through the pixels and read the bits directly from the display to build a new ByteArray? Or a way to make it into a bitmapdata object?

       


      var bmd:BitmapData = ???;
      var useableByteArray:ByteArray = new ByteArray();

      for (var i:int =0; i < img.width; i++){
      for (var j:int = 0; j < img.height; j++){
        useableByteArray.writeByte(bmd.getPixel32(i, j));
      }
      }

       

      Message was edited by: eboda_kcuf

        • 1. Re: My image is one size, the byte array is another?
          Flex harUI Adobe Employee

          Are you looking for BitmapData.draw()?  Also, a common problem is that the ByteArray’s position is not set back to 0 after writing to it so subsequent reads start from the end.

          • 2. Re: My image is one size, the byte array is another?
            the0bot Community Member

            The trouble seems to be that the byteArray used to create the component is to short, since the byte array for a png encoded image needs to be 4 * h * w bytes.  The image appears on the screen, completely fills the 130 x 30 pixel area, and is held in:

             

            <mx:Image id="img" width="130" height="30"/>

             

            The byte array used to load the image is only 1,720 bytes, created from a string using the function above. I do not know what format the bytes are in, if they contain mime or header information or flood fills or anything.  We can make the problem easier perhaps. I see : harui.jpgon my display. The colored area is an image control I would like to png encode. The control is 130 x 30  created by calling img.load(byteArray) with a byte array that is 1720 bytes.

            How can I png encode this image?

             

            Also, If I try: newBitMapData.Draw(img) I get an empty area. Ideally I would simply like to read the area pixel by pixel and create a new byteArray that is the correct number of bytes in length.  Can I gather pixel information directly somehow?

             

            Message was edited by: eboda_kcuf added draw() info.

            • 3. Re: My image is one size, the byte array is another?
              Flex harUI Adobe Employee

              mx:image usually takes a JPG, PNG or GIF so it would be fewer bytes than 4 * h * w.  The bitmapData will have 4 * h * w bytes.

              • 4. Re: My image is one size, the byte array is another?
                the0bot Community Member

                That is the whole problem. I have a byte array, I need the bitmap of the rectangle it occupies....

                • 5. Re: My image is one size, the byte array is another?
                  Flex harUI Adobe Employee

                  Then use BItmapData.draw() on the Image?

                  • 6. Re: My image is one size, the byte array is another?
                    the0bot Community Member

                    Well, after many hours of experimentation and dickering, I managed to get the draw() method to work, somewhat.

                     

                    ( 'img' is the mx:Image that is loaded with the server supplied string after byte conversion
                       'img2' is a duplicate mx:Image 130 x 30 with no image loaded)


                    public function encodeImage():ByteArray{
                      var bd:BitmapData = new BitmapData(130, 30);
                      var bmp:Bitmap = new Bitmap(bd);
                      bmp.bitmapData.draw(img);
                      var jenc:JPEGEncoder = new JPEGEncoder;
                      var ba:ByteArray = jenc.encode(bmp.bitmapData);
                      img2.load(ba);
                      return ba;
                    }
                      


                    The image does not appear in img2 however until I run the function a second time. Futher, the ba:ByteArray cannot be used to create a legitimate jpeg file, as it still produces an end of file error.

                    I have attempted to create a useful jpeg by extending the function:

                     


                    public function encodeImage():ByteArray{
                      var bd:BitmapData = new BitmapData(130, 30);
                      var bmp:Bitmap = new Bitmap(bd);
                      bmp.bitmapData.draw(img);
                      var jenc:JPEGEncoder = new JPEGEncoder;
                      var ba:ByteArray = jenc.encode(bmp.bitmapData);
                      img2.load(ba);
                      var arr:ByteArray = new ByteArray;
                      for (var i:int = 0; i < 130; i++) {
                       for (var j:int = 0; j < 30; j++){
                        var k:uint = bmp.bitmapData.getPixel32(i, j);
                        arr.writeUnsignedInt(k);
                       }
                      }
                      jenc = new JPEGEncoder;
                      myJpg = jenc.encodeByteArray(arr, 130, 30);
                      return ba;
                    }  


                    However, the the byteArray produced by the JPEGEncoder still does not produce an acceptable image. I have reproduced the image by using a screen copy utility to "take a picture" of it.  If I upload the file created this way it is acceptable. I am currently trying to discern the difference between the Encoder produced file and the disk copy and am now looking for a way to try and save the encoder produced file to disk to see if I can open it as a normal jpeg. I am sure there is a flash function to export the byteArray,** I am just a little exasperated with the endless difficulties I encounter with the flash platform.

                     

                    Unfortunately I inherited a rather large project based on SDK 3.6  ( 72 mxml display files and over 300 as3 classes and auxillary files) and it is imperative that new functionality is incorporated in a timely manner without causing interuption of the useability.

                     

                    The current problem is stretching into its second week and I still do not have a solution to what would be a very simple problem on most other platforms (i.e. to take an image that exists within its own container and upload it to a server in ANY standard format. bmp, jpg, gif or png would all be acceptable)  As rediculous as it sounds, so far I have not been able to create a useable file within the flash environment from an existing image that I can not only see, but move or draw a frame around. In addition, the effort required to devlop a way to actually upload the file using internet standard multipart/form-data protocol further required that the payload be constructed one byte at a time then sent using urlLoader.dataFormat = URLLoaderDataFormat.BINARY;

                     

                    I realize that these may be things flash is not designed to do, but as technolgy and internet functionality changes software must adapt to match industry requirements or face extinction. Perhaps this is the reason the flash has been relegated to open source. Hopefully now it will develop in directions that will sustain its existance, but it will require effort that Adobe is apparently unwilling to invest.

                     

                    Until things change I know now to never get involved with any flash-based project.  It is impossible to justify the hours needed to find 'work-arounds' for tasks that should be straight-forward.

                     

                     

                    ** This is a classic example of the difficulties I mentioned. Where is the 'saveToDisk' methiod? I sincerely hope it is not hidden in the same place as the 'uploadThePictureYouSee' method, because I STILL cannot find that one.....
                           

                     

                    Message was edited by: eboda_kcuf

                    • 7. Re: My image is one size, the byte array is another?
                      Flex harUI Adobe Employee

                      Flash does have some idiosyncracies.  Images are loaded asynchronously since they could be coming over a very slow network, so maybe the first image isn’t ready the first time you call encodeImage().  Are you waiting for the right event before running the function?

                       

                      It looks like you have a legitimate JPEG byte array other wise img2 wouldn’t load it.  So, assuming that, is the missing piece how to write that out to a server?  See http://svn.apache.org/viewvc/incubator/flex/trunk/mustella/as3/src/mustella/CompareBitmap. as?view=log for how we write PNGs to a server.

                      • 8. Re: My image is one size, the byte array is another?
                        the0bot Community Member

                        Well, that all actually came out very well, thanx...  I have decided to refactor the code in this project from sdk 3..6 to the latest update, mainly because I need to untangle  the data from the display and to make the system more event driven rather than hard-wired through direct calls. The current system trips all over itself during periods of high server load, which then generates more  lag  because it takes the server much longer too deal with all the bad calls. As my user-base continues to increase it is becoming more critical. I am in a very competitive market, and I am reasonably sure  that my competitors are not yet aware of the situation.

                         

                        Admittedly I am far from an authority on best practice, but have enough common sense to see the problems. My concern now is to avoid common pitfalls and traps.  I have gained a lot of insight and was extremely impressed by the link in the previous post. (I could not shake the impression of roaming  the sacred catacombs that housed the Holy Grail, lol.  This was reinforced by the obvious increase in khaos with each rising level, ending with pandemonium at the top...)

                         

                        Unfortunately the repository no longer exists. Kinda makes me feel like Indian Jones or Lara Croft, about 10 minutes from the start of the story.  I got a glimpse of the goal then an avalanche obscured the path.

                         

                         

                        So my current dilemma: A major part of the functionality of the application includes the acquisition of the image we just accomplished, and the subsequent uploading. This all works very smoothly now, so long as the user is there to click the button, but there are times when the user is not availible that this needs to happen. I understand the security causes for requiring the user to physically click a button to instigate a file transfer, but I must be missing something. Surely there must be a way to give 'pre-approval'?

                        As far as I can see, if the user wants to upload 50,000 files, they have to click 50,000 buttons, which is actually laughable. Last time I checked, security was not spelled 's-t-u-p-i-d-i-t-y'. It is really pretty basic, and I find it rather hard to believe that in all of history, Flex has never uploaded a picture without the user pushing a button....

                         

                        • The files are created within the application, based on user directives and settings. Depending on the complexity, this can take from a few seconds to several minutes up to (concievably) hours to complete.

                         

                        • The upload server is independent of the application. There are a wide variety of choices the user can select from, and they need to enter the url and log information within the application (it is not pre-selected or even selectable from inside the application - it must be physically entered at least once)
                        • I can force the user to explicitly give permission every time the application starts if I need too, but just once would be better. Some users run for hours or days at a time, others log in for 5 minutes 50 times a day....
                        • The application does not require access to the system other than to store the user settings in a local shared object.
                        • The only response from the upload is a 4 word acknowledgement and receipt, which is displayed then discarded.

                         

                        So, there is surely a way for the user to allow the application to handle this in their absence???