【问题标题】:How to rotate image from cameraUI for iOS in actionscript 3.0如何在 actionscript 3.0 中从适用于 iOS 的 cameraUI 旋转图像
【发布时间】:2013-02-20 00:41:43
【问题描述】:

我正在我的 Flash 构建器中使用 actionscript 3.0 构建一个应用程序。这是this question 的后续问题,它有效,但是当我拍照时,图像向左旋转。如何检查用户拿着手机的方式?然后我用什么代码将图像旋转到相应的位置?

提前致谢!

编辑: 我正在使用此代码来旋转图像,但它似乎只旋转正在显示的图像而不是图像文件,有什么想法吗?

var mat:Matrix = new Matrix();
mat.translate(-W/2, -H/2);
mat.rotate(Math.PI/2);
mat.translate(+W/2, +H/2);
mat.concat(myObj.transform.matrix);
myObj.transform.matrix = mat;

~我的

【问题讨论】:

    标签: iphone ios actionscript-3 flash-builder


    【解决方案1】:

    当您激活 cameraUI 视图时,您无法获取 stage.orientation 数据,所以这是我解决相同问题的方法,请注意此控制器具有许多可重用功能,我首先从 media promise 获取原始图像数据(此原始数据具有 EXIF 数据,我将读取这些数据以从相机获取图像方向)然后将此 byteArray 转换为 BitmapData,然后根据需要调整大小和缩放。需要注意的一件事是,如果您将原始图像数据转换为位图数据,您将丢失 EXIF 数据,因此请在修改图像之前阅读它,希望这会有所帮助,我很晚才在这里发布我知道但网络上没有其他解决方案和也许有人会在某个时候需要这个。干杯

    SnapshotController.as

    package controllers
    {
    
        import flash.display.BitmapData;
        import flash.display.JPEGEncoderOptions;
        import flash.display.Loader;
        import flash.display.LoaderInfo;
        import flash.display.Sprite;
        import flash.events.Event;
        import flash.events.IEventDispatcher;
        import flash.events.MediaEvent;
        import flash.filesystem.File;
        import flash.filesystem.FileMode;
        import flash.filesystem.FileStream;
        import flash.geom.Matrix;
        import flash.geom.Rectangle;
        import flash.media.CameraUI;
        import flash.media.MediaPromise;
        import flash.media.MediaType;
        import flash.utils.ByteArray;
        import flash.utils.IDataInput;
    
        import mx.utils.Base64Encoder;
    
        import classes.APIupload;
    
    
        public class SnapshotController
        {
            private var cameraUI:CameraUI = new CameraUI();
            private var dataSource:IDataInput; 
            private var tempDir:File = new File();
            private var imageOrientation:int = 0 ;
    
    
            public function SnapshotController()
            {
    
            }
    
            public function LaunchCameraUI():void
            {
    
                if( CameraUI.isSupported ) {
                    trace( "Initializing camera..." ); 
                    cameraUI.addEventListener( MediaEvent.COMPLETE, imageSelected ); 
                    cameraUI.launch( MediaType.IMAGE ); 
                } else {
                    trace( "CameraUI is not supported."); 
                }
            }
    
            private function imageSelected( event:MediaEvent ):void {
                trace( "Media selected..." ); 
                var imagePromise:MediaPromise = event.data; 
    
    
                dataSource = imagePromise.open(); 
                if( imagePromise.isAsync ) {
                    trace( "Asynchronous media promise." ); 
                    var eventSource:IEventDispatcher = dataSource as IEventDispatcher; 
                    eventSource.addEventListener( Event.COMPLETE, onMediaLoaded );
                } else {
                    trace( "Synchronous media promise." ); 
                    readMediaData(); 
                }
            } 
            private function onMediaLoaded( event:Event ):void {
                trace("Media load complete"); 
                readMediaData();
            } 
    
            private function readMediaData():void { 
                var imageBytes:ByteArray = new ByteArray(); 
                dataSource.readBytes( imageBytes );
    
                imageOrientation = getOrientation(imageBytes);
    
                //saveImageFile(imageBytes);
                //Saving this byteArray will save a big file with the EXIF in it.
    
                var loader:Loader = new Loader();
                loader.contentLoaderInfo.addEventListener(Event.INIT, onMediaPromiseLoaded);
                loader.loadBytes(imageBytes);
    
            } 
    
    
            private function onMediaPromiseLoaded(e:Event):void
            {
                trace("Media file loaded");
                var base64Enc:Base64Encoder = new Base64Encoder();
                var mpLoaderInfo:LoaderInfo = e.target as LoaderInfo;
                mpLoaderInfo.removeEventListener(Event.COMPLETE, onMediaPromiseLoaded);
    
                var scale:Number = 0.25;
                var matrix:Matrix = new Matrix();
                matrix.scale(scale, scale);
    
    
                var jpgQuality:int = 80;
    
    
                var bmd:BitmapData = new BitmapData(mpLoaderInfo.width*scale, mpLoaderInfo.height*scale);
                bmd.draw(mpLoaderInfo.content,matrix,null,null,null,true);  
    
                var rotatedBMD:BitmapData = rotateBitmapData(bmd, imageOrientation);
                var bytes:ByteArray = rotatedBMD.encode(new Rectangle(0,0, rotatedBMD.width , rotatedBMD.height), new JPEGEncoderOptions(jpgQuality), bytes);
    
    
    
    
                saveImageFile(bytes); //this is the smaller file saved. it does not have EXIF data but you can write your own using AS3 eXIF class.
    
            } 
    
            private function rotateBitmapData( bitmapData:BitmapData, degree:int = 0 ) :BitmapData
            {
                var newBitmap:BitmapData;
                var matrix:Matrix = new Matrix();
                matrix.rotate( degree * (Math.PI / 180)  );
    
                if ( degree == 90 ) {
                    newBitmap = new BitmapData( bitmapData.height, bitmapData.width, true );
                    matrix.translate( bitmapData.height, 0 );
                } else if ( degree == -90 || degree == 270) {
                    newBitmap = new BitmapData( bitmapData.height, bitmapData.width, true );
                    matrix.translate( 0, bitmapData.width );
                } else if ( degree == 180 ) {
                    newBitmap = new BitmapData( bitmapData.width, bitmapData.height, true );
                    matrix.translate( bitmapData.width, bitmapData.height );
                }else if(degree == 0){
                    newBitmap = new BitmapData( bitmapData.width, bitmapData.height, true );
                    //matrix.translate( bitmapData.width, bitmapData.height );
                }
    
                newBitmap.draw( bitmapData, matrix, null, null, null, true )
                return newBitmap;
            }
    
            private function saveImageFile(ba:ByteArray):void{
                var now:Date = new Date(); 
                var filename:String = "IMG" + now.fullYear + now.month + now.day + now.hours + now.minutes + now.seconds + ".jpg";
                var temp:File = File.documentsDirectory.resolvePath( filename );
                var stream:FileStream = new FileStream(); 
                stream.open( temp, FileMode.WRITE ); 
                stream.writeBytes( ba ); 
                stream.close();
            }
    
    
    
            private function getOrientation(jpeg:ByteArray):int{
                if (jpeg == null) {
                    return 0;
                }
                var offset:int = 0;
                var length:int = 0;
    
    
                while (offset + 3 < jpeg.length && (jpeg[offset++] & 0xFF) == 0xFF) {
                    var marker:int = jpeg[offset] & 0xFF;
    
                    // Check if the marker is a padding.
                    if (marker == 0xFF) {
                        continue;
                    }
                    offset++;
    
                    // Check if the marker is SOI or TEM.
                    if (marker == 0xD8 || marker == 0x01) {
                        continue;
                    }
                    // Check if the marker is EOI or SOS.
                    if (marker == 0xD9 || marker == 0xDA) {
                        break;
                    }
    
                    // Get the length and check if it is reasonable.
                    length = pack(jpeg, offset, 2, false);
                    if (length < 2 || offset + length > jpeg.length) {
                        trace("Invalid length");
                        return 0;
                    }
    
                    // Break if the marker is EXIF in APP1.
                    if (marker == 0xE1 && length >= 8 &&
                        pack(jpeg, offset + 2, 4, false) == 0x45786966 &&
                        pack(jpeg, offset + 6, 2, false) == 0) {
                        offset += 8;
                        length -= 8;
                        break;
                    }
    
                    // Skip other markers.
                    offset += length;
                    length = 0;
                }
    
                if (length > 8) {
                    // Identify the byte order.
                    var tag:int = pack(jpeg, offset, 4, false);
                    if (tag != 0x49492A00 && tag != 0x4D4D002A) {
                        trace("Invalid byte order");
                        return 0;
                    }
                    var littleEndian:Boolean = (tag == 0x49492A00);
    
                    // Get the offset and check if it is reasonable.
                    var count:int = pack(jpeg, offset + 4, 4, littleEndian) + 2;
                    if (count < 10 || count > length) {
                        trace( "Invalid offset");
                        return 0;
                    }
                    offset += count;
                    length -= count;
    
                    // Get the count and go through all the elements.
                    count = pack(jpeg, offset - 2, 2, littleEndian);
                    while (count-- > 0 && length >= 12) {
                        // Get the tag and check if it is orientation.
                        tag = pack(jpeg, offset, 2, littleEndian);
                        if (tag == 0x0112) {
                            // We do not really care about type and count, do we?
                            var orientation:int = pack(jpeg, offset + 8, 2, littleEndian);
                            switch (orientation) {
                                case 1:
                                    return 0;
                                case 3:
                                    return 180;
                                case 6:
                                    return 90;
                                case 8:
                                    return 270;
                            }
                            trace( "Unsupported orientation");
                            return 0;
                        }
                        offset += 12;
                        length -= 12;
                    }
                }
    
                trace( "Orientation not found");
                return 0;
    
            }
    
            private function pack(bytes:ByteArray,offset:int,length:int,
                                  littleEndian:Boolean):int {
                var step:int = 1;
                if (littleEndian) {
                    offset += length - 1;
                    step = -1;
                }
    
                var value:int = 0;
                while (length-- > 0) {
                    value = (value << 8) | (bytes[offset] & 0xFF);
                    offset += step;
                }
                return value;
            }
    
        }
    }
    

    【讨论】:

      【解决方案2】:

      您可以使用Stage.deviceOrientationStage.orientation* 来确定手机的方向。

      *不确定这个是否适用于 iOS

      您要旋转的是 BitmapData 结果本身(即创建一个带有旋转图像的新 BitmapData)还是只是旋转显示列表上的 Bitmap?

      编辑:

      好的,下面是一些旋转 BitmapData 对象的代码:

      function rotateBitmapData(angle:int, source:BitmapData):BitmapData
      {
          var newWidth:int = source.rect.width;
          var newHeight:int = source.rect.height;
          if (angle==90 || angle==270)
          {
              newWidth = source.rect.height;
              newHeight = source.rect.width;
          }
          var newBmd:BitmapData = new BitmapData(newWidth, newHeight, source.transparent);
          var tx:Number = 0;
          var ty:Number = 0;
          if (angle==90 || angle==180)
          {
              tx = newWidth;
      }
          if (angle==180 || angle==270)
          {
              ty = newHeight;
          }
          var matrix:Matrix = new Matrix();
          matrix.createBox(1, 1, Math.PI*angle/180, tx, ty);
          newBmd.draw(source, matrix);
          return newBmd;
      }
      

      角度应为 0,90,180 或 270。它将返回一个新的 BitmapData 对象旋转指定角度。

      【讨论】:

      • 数据,我想旋转数据,我编辑了旋转图像的代码,它可以工作,但只在显示中,我真的需要它来旋转文件(数据)
      • 嘿,Lee,非常感谢您提供的信息,我发布了其余代码,将其更改为 byteArray,但从 bitmapData 到 byteArray 的转换需要一分钟多一点的时间。您知道实现这一目标的更快更有效的方法吗?
      • jpeg 编码器非常慢——尤其是在移动设备上。其他 jpeg 编码器可用,它们可能会(稍微)提供更好的结果。或者您可以使用异步编码器,这样应用程序在编码时不会冻结。但这将是一个不同的问题
      • 太好了,我会提出一个不同的问题并编辑它,如果你能帮助stackoverflow.com/questions/15009938/…,新问题就在这里
      • 我知道的唯一异步编码器是我自己的:github.com/LeeBurrows/Async-Image-Encoders,但新问题可能会吸引更好的解决方案;)
      【解决方案3】:

      你可以使用StageOrientationEvent.ORIENTATION_CHANGING事件:

      stage.addEventListener(StageOrientationEvent.ORIENTATION_CHANGING, OrientationChangeHandler);
      
      private function OrientationChangeHandler(e:StageOrientationEvent):void
              {
                  switch (e.afterOrientation)
                  {
      
      
                      case StageOrientation.DEFAULT :
      
                      break;
                  case StageOrientation.ROTATED_RIGHT :
      
                      break;
                  case StageOrientation.ROTATED_LEFT :
      
                      break;
                  case StageOrientation.UPSIDE_DOWN :
      
                      break;
                  }
              }
      

      这可以帮助你。

      【讨论】:

      • 嗨 Vipul,感谢您的回答,但我似乎无法进入 switch 语句。我正在尝试使用我在问题的编辑部分中发布的代码来旋转它,但它似乎只适用于显示中的图像,而不是文件(这是我真正想要的)
      猜你喜欢
      • 1970-01-01
      • 2011-02-26
      • 2016-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多