【问题标题】:Converting a hex string of a raw image to a bitmap image in JavaScript在 JavaScript 中将原始图像的十六进制字符串转换为位图图像
【发布时间】:2016-04-30 01:43:39
【问题描述】:

简介

我正在从智能卡读取指纹图像数据,如您所知,此数据保存为智能卡中的原始图像。 我正在开发一个客户端程序,它只使用 java 脚本从读卡器的扫描仪中读取图像并在客户端页面中显示。

现在我的问题是:

如何将原始数据的十六进制字符串转换为使用适当的位图图像标题完成的十六进制字符串?请注意,我的图像有widthheight

尝试过的方法:

我已经由get buffered image from raw data 用java 开发了这个程序。另外,我可以通过Hex2Base64 将位图图像的十六进制字符串转换为base64,然后我可以通过base64AsImage 在图像标签中显示base64 字符串。然而,当且仅当十六进制包含标头,而我们的数据是原始数据时,这些函数才能正常工作。

我的代码(仅适用于包含标题的十六进制字符串):

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>

    <script>
        if (!window.atob) {
            var tableStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
            var table = tableStr.split("");

            window.atob = function (base64) {
                if (/(=[^=]+|={3,})$/.test(base64)) throw new Error("String contains an invalid character");
                base64 = base64.replace(/=/g, "");
                var n = base64.length & 3;
                if (n === 1) throw new Error("String contains an invalid character");
                for (var i = 0, j = 0, len = base64.length / 4, bin = []; i < len; ++i) {
                    var a = tableStr.indexOf(base64[j++] || "A"), b = tableStr.indexOf(base64[j++] || "A");
                    var c = tableStr.indexOf(base64[j++] || "A"), d = tableStr.indexOf(base64[j++] || "A");
                    if ((a | b | c | d) < 0) throw new Error("String contains an invalid character");
                    bin[bin.length] = ((a << 2) | (b >> 4)) & 255;
                    bin[bin.length] = ((b << 4) | (c >> 2)) & 255;
                    bin[bin.length] = ((c << 6) | d) & 255;
                };
                return String.fromCharCode.apply(null, bin).substr(0, bin.length + n - 4);
            };

            window.btoa = function (bin) {
                for (var i = 0, j = 0, len = bin.length / 3, base64 = []; i < len; ++i) {
                    var a = bin.charCodeAt(j++), b = bin.charCodeAt(j++), c = bin.charCodeAt(j++);
                    if ((a | b | c) > 255) throw new Error("String contains an invalid character");
                    base64[base64.length] = table[a >> 2] + table[((a << 4) & 63) | (b >> 4)] +
                    (isNaN(b) ? "=" : table[((b << 2) & 63) | (c >> 6)]) +
                    (isNaN(b + c) ? "=" : table[c & 63]);
                }
                return base64.join("");
            };

        }

        function hexToBase64(str) {
            return btoa(String.fromCharCode.apply(null,
                            str.replace(/\r|\n/g, "").replace(/([\da-fA-F]{2}) ?/g, "0x$1 ").replace(/ +$/, "").split(" "))
            );
        }

        function base64ToHex(str) {
            for (var i = 0, bin = atob(str.replace(/[ \r\n]+$/, "")), hex = []; i < bin.length; ++i) {
                var tmp = bin.charCodeAt(i).toString(16);
                if (tmp.length === 1) tmp = "0" + tmp;
                hex[hex.length] = tmp;
            }
            return hex.join(" ");
        }
        function doConvert() {
            var myHex =  document.getElementById('myText').value;
            var myBase64 = hexToBase64(myHex);
            document.getElementById('myImage').src = "data:image/bmp;base64," +  myBase64;
        }
    </script>



</head>
<body>
<div>
    <p>
        Enter Raw Hex:
        <br>
        <textarea rows="4" cols="50" id="myText">Enter Raw Hex String here ...</textarea>
        <br>
        <button id="myButton" onclick="doConvert()"> Click me </button>
        <br>
        <img id="myImage" alt="img1"/>
    </p>
</div>
</body>
</html>

一个part of code解决java中的问题:

private static BufferedImage byte2Buffered(byte[] rawData, int width, int height){
    BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_BYTE_GRAY);
    byte[] array = ((DataBufferByte)image.getRaster().getDataBuffer()).getData();
    System.arraycopy(rawData, 0, array, 0, rawData.length);
    return image;
}

请注意,由于 JavaScript 中没有 BufferedImage 类型,我们无法在 JavaScript 中等效此方法。

【问题讨论】:

  • 你知道颜色编码吗?即灰度或颜色?
  • 还要记住,java 和 javascript 是完全不同的语言。
  • 亲爱的@Matthieu 我的图像是灰度的,当然,java 与 javascript 不同。我绝对知道这个事实 :) 我告诉我我已经在 java 中完成了这个问题,我想在 javascript 中做到这一点
  • 大概,(因为你说你以前在java中做过)你知道文件的确切格式。鉴于此,您可以解码/解释文件头,并且您知道每个像素在输入格式中的表示方式。如果您已经知道这一点,您应该能够将输入读取到缓冲区数组中,然后读取为 xIntTypedArrayBuffer。然后读取每个位并将其渲染到画布(或您正在编码为另一种格式的其他缓冲数组)。
  • 如果您只对将内容写入屏幕感兴趣,那么您无需担心图像编码;您可以简单地将像素数据写入canvas 元素——详情请参阅MDN。如果您需要转码以供存储和以后使用,请尝试使用jimp 或尝试 ImageMagick 的任何包装器库(我还没有找到 ImageMagick 无法完成的处理任务)。请务必注意您所在辖区的生物识别存储法律。

标签: javascript string bitmap hex smartcard


【解决方案1】:

在您的 window.atob 方法中,您已经从一个 8 位整数数组构建了一个字符串(这就是 bin[length] 正在创建的内容。)只需返回该数组而不是字符串。

然后,如果您必须支持旧版浏览器,则需要将每个像素单独写入画布。但是,如果您可以针对现代浏览器,只需构建一个 Uint8ClampedArray,将其放入 ImageData 对象,然后将 putImageData() 放入画布中。

下面是一些工作示例代码。我正在使用随机字节 (data) 填充一个虚拟数组,但您将使用从 atob 返回的字节数组。

var canvas = document.querySelector('canvas'),
    ctx = canvas.getContext('2d'),
  width = canvas.width,
  height = canvas.height,
  pixelLength = width * height,
  data,
  imageData;

// You can use any kind of array, including a
// Uint8ClampedArray, since it is just going to be
// crammed into a clamped array anyway. I'm using a
// Uint8Array just as an example.
data = new Uint8Array(pixelLength);

// Create an array of random data
data = data.map(function (btye) { return Math.floor(Math.random() * 256); });

// The source data is 8-bit grayscale, but it needs 
// to be 32-bit RGBA in a Uint8ClampedArray. The
// structure is simple. For every byte of the gray-
// scale array, write out three copies of that byte 
// and then `256` as 100% opaque.
data = data.reduce(function (carry, current, index) {
    var baseIndex = index * 4;

  carry[baseIndex] = current;
    carry[baseIndex + 1] = current;
    carry[baseIndex + 2] = current;
    carry[baseIndex + 3] = 256;

return carry;
}, new Uint8ClampedArray(pixelLength * 4));

// The Uint8ClampedArray can now be used to build the image
imageData = new ImageData(data, width, height);
ctx.putImageData(imageData, 0, 0);

【讨论】:

  • jsfiddle.net/36gLwqgv/1。我在这里使用reduce 而不是for() 循环。请参阅MDN documentation 了解如何使用它,但请随意使用for()
  • 亲爱的@Andrew 我在 IE11 中发现了这个错误:'Uint8ClampedArray' 未定义。事实上,我有一个从智能卡读取原始图像的 activeX(IE 扩展),所以我需要基于 IE 的程序。虽然我有 IE11,但我希望支持不支持 HTML5 的旧 IE。
  • [我已编辑此评论] 您可以使用字节数组。我建议找到一个 ActiveX 绘图库来将数据 bitbash 转换为图像。我敢肯定有什么可以做的。
  • 亲爱的@Andrew,但我认为您的回答是一个非常好的方法,因为它在 chrome 和 Firefox 中运行良好,而且它只有这个错误:Uint8ClampedArray is undefined 在 IE 中。你知道activeX中的类型是restricted,搞得比较麻烦。
  • 然后,正如我所说,如果您必须支持旧版浏览器,则需要将每个像素单独写入画布。如果您不能使用Uint8ClampedArray,那么您可能无法使用putImageData(),因此您可能必须使用的技术是绘制1x1 像素“矩形”而不是写入像素。这听起来很慢,但可能不是。此外,您可能会发现使用图形库更容易,例如 Fabric.js、EaselJS、Paper.js 等,因为它可以处理跨平台问题。我不能推荐一个。试试看你的想法。
猜你喜欢
  • 2015-01-15
  • 2018-05-13
  • 2019-03-08
  • 2011-03-01
  • 2012-05-23
  • 2014-10-29
  • 2012-01-27
  • 1970-01-01
相关资源
最近更新 更多