微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何有效地读取流上JPEG图像的大小

如何解决如何有效地读取流上JPEG图像的大小

我为我们的业务应用程序编写了一些附加程序,目的是使用 Barcodereader 拍照。

一切正常,但是问题是条形码阅读器每隔一段时间发送一次图片,它们是随机的(取决于图片的大小和波特率)。如果没有完整分析我收到的字节,就无法判断图片是否已加载。

此刻,我的逻辑尝试通过分别搜索FF D8FF D9字节来查找JPEG的开始/结束。问题是图像内部可能出现FF D9个字节。

我显然可以对字节进行一些特定的分析,但是随着Barcodereader不断发送数据,执行耗时的操作(调试,cpu,IO等),而接收字节的操作最终会以 bluescreen >。

我真正想要的是

  1. 读取显示图像大小的字节(我无法 甚至研究大小是否会包含页眉本身/页脚 本身正在考虑...我必须为此计算吗? )。

  2. 检查我是否收到了所有个字节。

我将把接收和使用字节的代码(在发生数据接收的事件,serialPortish上)和正确的完整映像(以字节为单位)放在一个字节中,并且损坏的映像也许会有所帮助。

DataReceivedEvent

        private void ScannerPort_DataReceived(object sender,DataReceivedEventArgs e)
        {
            if (_WaitingForImage)
            {
                List<byte> imageBufferList = new List<byte>(e.RawBuffer);
                {

                    if (imageBufferList[0] == 0x24 && imageBufferList[1] == 0x69)
                    {
                        for (int i = 0; i < 17; i++)
                        {
                            imageBufferList.RemoveAt(0);
                        }
                    }

                    byte[] imageBuffer = imageBufferList.ToArray();
                    _ImageReceiving = false;
                    _WaitingForImage = false;
                    this.OnImageReceived(imageBuffer);
                }

                //imageBufferList.AddRange(e.RawBuffer);

            }

完整字节数组

https://codepen.io/NicolaiWalsemann/pen/KKzxaXg

损坏的字节数组

https://codepen.io/NicolaiWalsemann/pen/YzqONxd

解决方案1 ​​

我可以轻松地创建一个计时器,该计时器在首次调用 DataReceived 事件后等待500ms-2000ms。这样可以确保我拥有所有内容,然后我可以根据需要进行尽可能多的解析。但是显然,总是不合理地等待并不是我想要的。

解决方法

我认为有人已经回答了这个问题:Detect Eof for JPG images

我不能再说了。

由于您将接收大量数据,因此您将需要在运行时进行解析。类似于以下内容。它未经测试,我可能会向后计算计数(大字节序与小字节序)。它还假定一个块有可能跨越2个图像,或者这些块可以拆分FFxx代码和计数。它也没有进行任何优化,但是对于较小的图像可能没问题。

    private List<byte> imageBuffer = new List<byte>();
    private int imageState = 0;
    private int skipBytes = 0;

    private void ScannerPort_DataReceived(object sender,DataReceivedEventArgs e)
    {
        List<byte> tempBuffer = new List<byte>(e.RawBuffer);

        foreach (byte b in tempBuffer)
        {
            _ImageReceiving = true;
            imageBuffer.Add(b);

            switch (imageState)
            {
                case 0: // Searching for FF
                    if(b == 0xFF)
                        imageState = 1;
                    break;
                case 1: // First byte after FF
                    if (b == 0 || b == 1 || (b <= 0xD8 && b >= 0xD1))
                    {
                        // Code is not followed by a count
                        imageState = 0;
                    }
                    else if (b == 0xD9)
                    {
                        // End of image
                        _ImageReceiving = false;
                        this.OnImageReceived(imageBuffer.ToArray());
                        imageBuffer = new List<byte>();
                        imageState = 0;
                    }
                    else
                    {
                        // Code is 
                        imageState = 2;
                    }

                    break;
                case 2: // First count byte,big endian?
                    skipBytes = ((int) b) * 0x100;
                    imageState = 3;
                    break;
                case 3: // Second count byte
                    skipBytes += b;
                    imageState = 4;
                    break;
                case 4: // skip
                    skipBytes--;
                    if (skipBytes == 0) imageState = 0;
                    break;
            }
        }
    }
,

我还没有测试过,我不知道它是否正确。但这就是我要解决的问题。与其他答案相比,我尝试处理一些注意事项;

  • 将字节数组保留为字节数组
  • 单个读取事件可能包含来自多个图像的部分块
  • MemoryStream中组装整个图像
  • 使用块长度信息复制或跳过整个块

如果内存缓冲区超过最大大小,您可能还希望将状态设置回0并停止复制图像。或者,如果在最后一个之后没有遇到新的标头。

private MemoryStream image = new MemoryStream();
private int state = 0;
private bool copy = false;
private int blockLen = -1;

private void ImageReceived(Stream image) {
    // TODO use whole image buffer
}
private void Received(byte[] block)
{
    var i = 0;
    while (i < block.Length)
    {
        if (state == 4 && blockLen > 0)
        {
            var remaining = block.Length - i;
            if (remaining > blockLen)
                remaining = blockLen;
            if (copy)
                image.Write(block,i,remaining);
            i += remaining;
            blockLen -= remaining;
            if (blockLen <= 0)
                state = 0;
        }
        else
        {
            var b = block[i++];
            switch (state)
            {
                case 0:
                    if (b == 0xFF)
                        state = 1;
                    break;
                case 1:
                    if (b == 0xD8) { // SOI
                        copy = true;

                        image.Seek(0,SeekOrigin.Begin);
                        image.SetLength(0);
                        image.WriteByte((byte)0xFF); // the first byte that we already skipped
                    } else if (b == 0xD9) { // EOI
                        if (copy)
                        {
                            image.WriteByte(b);
                            image.Seek(0,SeekOrigin.Begin);

                            ImageReceived(image);
                        }
                        copy = false;
                        state = 0;
                    } else if (b == 0xFF) { // NOOP
                    } else if ((b & 0xF8) == 0xD0) { // RSTn
                        // You could verify that n cycles from 0-7
                        state = 0;
                    } else {
                        state = 2;
                    }
                    break;
                case 2:
                    blockLen = b << 8;
                    state = 3;
                    break;
                case 3:
                    // length includes the 2 length bytes,which we've just skipped
                    blockLen = (blockLen | b) -2;
                    state = 4;
                    break;
            }
            if (copy)
                image.WriteByte(b);
        }
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。