【问题标题】:How to sychronously get the width and height from a base64 string of image data?如何从base64图像数据字符串中同步获取宽度和高度?
【发布时间】:2017-04-30 05:52:45
【问题描述】:

有没有办法同步从 base64 编码的图像数据中获取图像的宽度和高度?可能是通过标题信息。

我必须非常清楚地说明这一点。我对异步方法不感兴趣。如果您想知道异步不起作用的原因,请继续。甚至不要评论。

这是我对数据进行编码的示例代码。编码是同步的。我正在使用这个call

var base64ImageData:String = DisplayObjectUtils.getBase64ImageDataString(displayObject, DisplayObjectUtils.PNG, null, true);

这是我的数据解码代码。我在 AS3 中发现的唯一解码方法是异步的。我正在使用这个call

var bitmapData:BitmapData = DisplayObjectUtils.getBitmapDataFromBase64(bitmapDataString);

让我再说一遍,我正在寻找一个同步动作。它不能是异步的。

更多信息:
我在 ActionScript3 工作,它是 JavaScript 的兄弟。如果它适用于 JavaScript,它很可能适用于 AS3。但我不能和dom一起工作。不向 dom 添加图像并检查值。

有用的技巧:
如果可以将宽度和高度添加到 base64 流中,然后稍后再获取它,那也可以。

【问题讨论】:

    标签: javascript arrays actionscript-3 flash bitmapdata


    【解决方案1】:

    这仅适用于 png 的 首先是转换base64做一个缓冲区(Uint8array)然后读取字节16-20(宽度)和20-24(高度)作为int32值

    function getPngDimensions(base64) {
      let header = base64.slice(0, 50)
      let uint8 = Uint8Array.from(atob(header), c => c.charCodeAt(0))
      let dataView = new DataView(uint8.buffer, 0, 28)
    
      return {
        width: dataView.getInt32(16),
        height: dataView.getInt32(20)
      }
    }
    
    // Just to get some random base64 images
    var random = (bottom, top) => Math.floor( Math.random() * ( 1 + top - bottom ) ) + bottom
    var canvas = document.createElement('canvas')
    canvas.width = random(10, 100)
    canvas.height = random(10, 100)
    console.log(`canvas width: ${canvas.width}, height: ${canvas.height}`)
    var base64 = canvas.toDataURL().split(',')[1]
    console.log(base64)
    
    var dimensions = getPngDimensions(base64)
    console.log(dimensions)

    【讨论】:

    • 谢谢你。如果我可以将它转换为 ActionScript3,我会检查它作为答案,但它可能超出了我的范围。 AS3 有一个名为 ByteArray() 的类用于处理字节数组。文档help.adobe.com/en_US/as3/dev/…。 API 文档help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/…。这是 JS 和 AS 不同的一个领域,我还不能全部破译。
    • 仍然想知道为什么要使用 flash :P 是不是已经死了?但是对不起兄弟,我对 AS 了解不多
    • 没问题。我会弄清楚。既然您想知道,对我来说,Flash 就像一个工具集或艺术家画布。作为一个工具集,我可以用它完成任务。作为画布,我可以使用它轻松创建矢量或光栅艺术和动画。我每天看它的方式是 Flash 或 (Flex) 是一个工具箱。人们说 HTML5 是所有酷孩子都在使用的,Flash 太不酷了。我不在乎。我不是在跟上卡戴珊人的步伐。我会继续使用 Flex,如果 HTML 赶上来那就太好了,也许我也会使用它。出于某种原因,开发人员是狂热者。我只是一个内容创作者。
    • @1.21gigawatts c 是箭头函数中的参数,不必声明。这就像写["a","b","c"].map(a => a.uppercase())["a","b","c"].map(function(a){ return a.uppercase() }
    • 它仅适用于 png 因为大小信息位于字节位置 16 和 20 作为浮点值。 jpeg 也有此信息,但它具有不同的字节结构
    【解决方案2】:

    以下内容不起作用,但它正在尝试将 @Endless 答案转换为 AS3。到目前为止我有这个:

    protected function windowedapplication1_applicationCompleteHandler(event:FlexEvent):void {
        var base64ImageData:String = DisplayObjectUtils.getBase64ImageDataString(this, DisplayObjectUtils.PNG, null, true);
        var size:Object = getPngDimensions(base64ImageData);
    }
    
    public function getPngDimensions(base64:String):Point {
        base64 = base64.split(',')[1];
        trace(base64.length);
        base64 = base64.replace(/\n/g, "");
        trace(base64.length);
        //var header:String = base64.slice(0, 52); // 50 gave error later on
        var header:String = base64.slice(0, base64.length);
        var base64Decoder:Base64Decoder = new Base64Decoder();
        var byteArray:ByteArray;
    
        base64Decoder.reset();
        base64Decoder.decode(header);
    
        // base64Decoder.toByteArray(); ==>
        // Error: A partial block (2 of 4 bytes) was dropped. Decoded data is probably truncated!
        // added the whole length (52 works as well)
        byteArray = base64Decoder.toByteArray();
        byteArray.position = 0;
    
        //var width:String = byteArray.readUTFBytes(0);
        //var value:ByteArray = new ByteArray();
        //value.readBytes(byteArray, 0, 28);
        var thing:Number = byteArray.readDouble(); // -8.091055181950927E-264
        byteArray.position = 0;
        var thing2:Number = byteArray.readFloat(); // -2.5073895107184266E-33
        byteArray.position = 0;
        var width:Number = byteArray.readFloat();
        byteArray.position = 16;
        var width:Number = byteArray.readFloat();
        byteArray.position = 20;
        var width:Number = byteArray.readFloat();
        byteArray.position = 28;
        var width:Number = byteArray.readFloat(); // 1.1074230549312416E-38
        byteArray.position = 0;
        var other:String = byteArray.readUTFBytes(byteArray.length);
        // other == "PNG\r\n\n"
    
        var point:Point = new Point();
        point.x = int(width);
        point.y = int(height);
    
        return point;
    }
    

    如果我使用ByteArray.readUTFBytes(),我会得到“PNG”,但没有宽度或高度。

    【讨论】:

    • 很好 (+1)... 来不及提出这个建议。我想到的另一件事是非常hacky并且只有在浏览器中使用.swf时才有用:使用ExternalInterface加载使用base64data创建<img>元素(让浏览器为你解码),然后阅读.width/.height 属性
    • 感谢您的建议。我试图避免外部接口,除非没有其他办法。我想如果我更了解 ByteArrays,我可以翻译其他答案。
    【解决方案3】:

    “如果我使用 ByteArray.readUTFBytes(),我会得到“PNG”,但没有宽度或高度。”

    不要以UTF 格式读取字节,因为这只会提取文本字符。您需要十进制值。

    • readDoublereadFloat 太多了,它们每个动作读取 8 个字节。 PNG 格式每个宽度或高度值仅使用 4 个字节,因此只需读取(无符号)整数。
    • 请记住,每个 read 操作都会自动移动 byteArray 位置。例如,要知道 bytePos-1 的值,您必须“走过”/阅读它,这样您最终会到达 bytePos-2,或者对于 Double 类型,您最终会到达 bytePos-9。

    看看你的代码是否得到了预期的宽度和高度值......

    public function getPngDimensions(base64:String):Point 
    {
        base64 = base64.split(',')[1];
        trace("Base64 length A : " + base64.length);
        base64 = base64.replace(/\n/g, "");
        trace("Base64 length B : " + base64.length);
        //var header:String = base64.slice(0, 52); // 50 gave error later on
        var header:String = base64.slice(0, base64.length);
        var base64Decoder:Base64Decoder = new Base64Decoder();
        var byteArray:ByteArray;
    
        base64Decoder.reset();
        base64Decoder.decode(header);
    
        // base64Decoder.toByteArray(); ==>
        // Error: A partial block (2 of 4 bytes) was dropped. Decoded data is probably truncated!
        // added the whole length (52 works as well)
        byteArray = base64Decoder.toByteArray();
        byteArray.position = 0;
    
        //# Get Width and Height values
        //# type Int is 4 bytes long so pointer auto-moves ahead by 4 bytes during Read action
        byteArray.position = 16; //start position for values...
        var width:int = byteArray.readUnsignedInt(); //reads 4 bytes, stops at Pos 20
        var height:int = byteArray.readUnsignedInt(); //reads 4 bytes, stops at Pos 24
    
        //# Double check (if needed)
        //trace("PNG width  : " + width);
        //trace("PNG height : " + height);
    
        //# Return as Point
        var point:Point = new Point();
        point.x = width; point.y = height;
        return point;
    }
    

    【讨论】:

    • 耶!有效!谢谢你,谢谢你教会了我一些新东西!如果有办法将两个答案标记为正确,我会同时标记这个答案和@Endless 答案。虽然需求可能为零,但 StackOverflow 可以在涉及不同语言时实现多个答案。因此,虽然 Endless 的答案是 JavaScript,但您的答案是 ActionScript。一个答案对 JavaScript 开发人员来说是正确的,另一个对 ActionScript 开发人员来说是正确的。
    • @1.21gigawatts 只需将工作部件(readInt 等)放入您自己的答案中并将其标记为正确。我的逻辑是,由于这是一个 AS3 问题,我和@Endless 只是为您自己的实现提供了有用的解决方案。
    • 对于任何想像我一样了解更多的人,我发现这两个类展示了如何创建 PNG 和 JPEG。 PNG github.com/mikechambers/as3corelib/blob/master/src/com/adobe/… 和 JPG github.com/mikechambers/as3corelib/blob/master/src/com/adobe/…。现在从他们那里取回价值更有意义。另一个无需加载整个文件即可获取 JPG 尺寸的类anttikupila.com/flash/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-25
    • 1970-01-01
    • 2014-07-15
    • 2019-05-20
    相关资源
    最近更新 更多