惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Forbes - Security
Forbes - Security
A
Arctic Wolf
M
MIT News - Artificial intelligence
T
Threat Research - Cisco Blogs
T
The Exploit Database - CXSecurity.com
C
CERT Recently Published Vulnerability Notes
NISL@THU
NISL@THU
L
Lohrmann on Cybersecurity
Martin Fowler
Martin Fowler
A
About on SuperTechFans
P
Palo Alto Networks Blog
Project Zero
Project Zero
The GitHub Blog
The GitHub Blog
WordPress大学
WordPress大学
Blog — PlanetScale
Blog — PlanetScale
博客园_首页
大猫的无限游戏
大猫的无限游戏
Cisco Talos Blog
Cisco Talos Blog
P
Proofpoint News Feed
D
DataBreaches.Net
Cyberwarzone
Cyberwarzone
T
Tor Project blog
IT之家
IT之家
P
Proofpoint News Feed
Help Net Security
Help Net Security
S
Securelist
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
C
CXSECURITY Database RSS Feed - CXSecurity.com
Microsoft Azure Blog
Microsoft Azure Blog
V2EX - 技术
V2EX - 技术
K
Kaspersky official blog
Hugging Face - Blog
Hugging Face - Blog
MongoDB | Blog
MongoDB | Blog
B
Blog
N
News and Events Feed by Topic
The Cloudflare Blog
S
Schneier on Security
P
Privacy & Cybersecurity Law Blog
T
The Blog of Author Tim Ferriss
Recorded Future
Recorded Future
Last Week in AI
Last Week in AI
The Last Watchdog
The Last Watchdog
Hacker News - Newest:
Hacker News - Newest: "LLM"
L
LangChain Blog
I
InfoQ
F
Full Disclosure
The Register - Security
The Register - Security
阮一峰的网络日志
阮一峰的网络日志
H
Hacker News: Front Page
V
V2EX

博客园 - HotSky

Chrome启用CDP(chrome-devtools-protocol)进行远程操控 WPF 让ScrollViewer支持按住鼠标中键拖拽滚动内容 WPF 让ScrollViewer支持鼠标中键滚动缩放内容 Nodejs使用 nodejs中写sql需要用in时的写法 C#城市最短路径 C#Animation Sqlite PDF附录A: 内容流操作码 WPF FPS类 生命模拟 C# Sql帮助类,可扩展 WPF WriteableBitmap通过GDI+绘制帮助类 Alpha混合 WPF支持任意快捷键+鼠标组合的绑定类 WPF阻止窗体被系统缩放,使用显示器DPI WPF DataGrid自动增长序号列 C#访问或修改私有类、函数、变量、属性 WPF一个简单的属性编辑控件
Bmp读写二值图
HotSky · 2024-07-08 · via 博客园 - HotSky
public class Bmp : IDisposable
{
    /*
        * 每行像素数据必须是4的倍数
        * 黑白二值图0表示黑,1表示白
        */
    public int Width { get => _width; }
    public int Height { get => Math.Abs(_height); }
    public int BitCount { get => _bitCount; }
    public int XResolution { get => _xresolution > 0 ? _xresolution : 96; }
    public int YResolution { get => _yresolution > 0 ? _yresolution : 96; }

    public void Dispose()
    {
        _br?.Dispose();
        _readStream?.Dispose();
        _writeStream?.Dispose();
    }

    Stream _readStream;
    BinaryReader _br;
    MemoryStream _writeStream;
    public Bmp(string path): this(File.OpenRead(path))
    {
    }

    public Bmp(int width, int height, int bitCount)
    {
        _width = width;
        _height = height;
        _bitCount = (short)bitCount;
        LoadStride();
        _imageSize = _stride * Math.Abs(_height);
        ResetWriteStream();
    }

    public Bmp(Stream stream)
    {
        _readStream = stream;
        _br = new BinaryReader(_readStream);

        char[] bm = _br.ReadChars(2);
        if (bm[0] != 'B' || bm[1] != 'M') throw new InvalidDataException();
        _fileSize = _br.ReadInt32();
        _reserved1 = _br.ReadInt16();
        _reserved2 = _br.ReadInt16();
        _offBits = _br.ReadInt32();
        _headSize = _br.ReadInt32();
        _width = _br.ReadInt32();
        _height = _br.ReadInt32();
        _planes = _br.ReadInt16();
        _bitCount = _br.ReadInt16();
        _compressionType = _br.ReadInt32();
        _imageSize = _br.ReadInt32();
        _xresolution = _br.ReadInt32();
        _yresolution = _br.ReadInt32();
        _clrUsed = _br.ReadInt32();
        _clrImportant = _br.ReadInt32();
        LoadStride();
        ReadStreamToWriteStream();
    }

    private void ReadStreamToWriteStream()
    {
        if (_writeStream != null)
            _writeStream.Dispose();
        _writeStream = new MemoryStream();
        byte[] bs = new byte[1024];
        _writeStream.Seek(0, SeekOrigin.Begin);
        _readStream.Seek(_offBits, SeekOrigin.Begin);
        CopyStream(_readStream, _writeStream);
    }

    int _fileSize = 0;
    /// <summary>
    /// 必须是0
    /// </summary>
    short _reserved1 = 0;
    /// <summary>
    /// 必须是0
    /// </summary>
    short _reserved2 = 0;
    /// <summary>
    /// 像素数据开始的字节偏移量
    /// </summary>
    int _offBits = 0;
    /// <summary>
    /// 图片头数据长度
    /// </summary>
    int _headSize = 0;
    int _width = 0;
    /// <summary>
    /// 正数时像素字节流流从左下角开始右上角结束,负数时左上角开始,右下角结束,通常是正数
    /// </summary>
    int _height = 0;
    /// <summary>
    /// 平面数,总是等于1
    /// </summary>
    short _planes = 1;
    /// <summary>
    /// 色宽[1,4,8,16,24,32]
    /// </summary>
    short _bitCount = 0;
    /// <summary>
    /// 压缩,0表示无压缩,1表示8位压缩(只用于8色宽),2表示4位压缩(只用于4色宽),3表示(只用于16、32色宽),4表示jpeg(只用于打印机),5表示png(只用于打印机)
    /// </summary>
    int _compressionType = 0;
    /// <summary>
    /// 图片像素数据区长度未压缩时可以是0
    /// </summary>
    int _imageSize = 0;
    /// <summary>
    /// pixels per meter
    /// </summary>
    int _xresolution = 0;
    /// <summary>
    /// pixels per meter
    /// </summary>
    int _yresolution = 0;
    /// <summary>
    /// 使用的调色板颜色索引数量,0表示所有;大于色宽等于24位则没有颜色索引
    /// </summary>
    int _clrUsed = 0;
    /// <summary>
    /// 对图像显示有重要影响的颜色索引数量,0表示所有
    /// </summary>
    int _clrImportant = 0;

    int _stride = 0;
    public int Stride
    {
        get
        {
            if(_stride == 0)
                LoadStride();
            return _stride;
        }
    }

    void LoadStride()
    {
        _stride = (int)Math.Floor(_width / 8d);
        _stride += (4 - (_stride % 4));
    }

    public int GetOffset(int x, int y, bool containsHead = false)
    {
        int offsetx = (int)Math.Floor(x / 8d);
        int offset = offsetx + Stride * (_height > 0 ? _height - 1 - y : y);
        return (containsHead ? _offBits : 0) + offset;
    }

    public Color GetPixel(int x, int y)
    {
        switch (_bitCount)
        {
            case 1:
                {
                    byte[] bs = ReadBytes(x, y);
                    int p = bs[0] & (int)Math.Pow(2, 7 - (x % 8));
                    return p == 0 ? Color.Black : Color.White;
                }
            default:
                break;
        }
        return Color.Empty;
    }

    byte[] ReadBytes(int x, int y)
    {
        switch (_bitCount)
        {
            case 1:
                {
                    _writeStream.Seek(GetOffset(x, y), SeekOrigin.Begin);
                    return new byte[] { (byte)_writeStream.ReadByte() };
                }
            default:
                break;
        }
        return new byte[0];
    }

    public void SetPixel(int x, int y, Color color)
    {
        ValidWriteStream(true);
        switch (_bitCount)
        {
            case 1:
                {
                    byte[] bs = ReadBytes(x, y);
                    _writeStream.Seek(GetOffset(x, y), SeekOrigin.Begin);
                    int v = color.ToArgb() == Color.White.ToArgb() ? 1 : 0;
                    int pow = (int)Math.Pow(2, 7 - (x % 8));
                    if ((bs[0] & pow) == v) return;
                    if(v == 1)
                        _writeStream.WriteByte((byte)(bs[0] | pow));
                    else
                        _writeStream.WriteByte((byte)(bs[0] - pow));
                    return;
                }
            default:
                break;
        }
    }

    public void Save(Stream stream)
    {
        int fileHeadSize = 14;
        _headSize = 40;
        int colorSize = 0;//颜色索引字节长度
        switch (_bitCount)
        {
            case 1:
                {
                    colorSize = 8;
                    break;
                }
            default:
                break;
        }
        _offBits = fileHeadSize + _headSize + colorSize;
        int fileSize = _offBits + _imageSize;

        //file head; length:14
        stream.Write(new byte[] { (byte)'B', (byte)'M' }, 0, 2);
        stream.Write(BitConverter.GetBytes(fileSize), 0, 4);
        stream.Write(BitConverter.GetBytes(_reserved1), 0, 2);
        stream.Write(BitConverter.GetBytes(_reserved2), 0, 2);
        stream.Write(BitConverter.GetBytes(_offBits), 0, 4);

        //image head; length:40
        stream.Write(BitConverter.GetBytes(_headSize), 0, 4);
        stream.Write(BitConverter.GetBytes(_width), 0, 4);
        stream.Write(BitConverter.GetBytes(_height), 0, 4);
        stream.Write(BitConverter.GetBytes(_planes), 0, 2);
        stream.Write(BitConverter.GetBytes(_bitCount), 0, 2);
        stream.Write(BitConverter.GetBytes(_compressionType), 0, 4);
        stream.Write(BitConverter.GetBytes(_imageSize), 0, 4);
        stream.Write(BitConverter.GetBytes(_xresolution), 0, 4);
        stream.Write(BitConverter.GetBytes(_yresolution), 0, 4);
        stream.Write(BitConverter.GetBytes(_clrUsed), 0, 4);
        stream.Write(BitConverter.GetBytes(_clrImportant), 0, 4);
            
        //color used
        switch (_bitCount)
        {
            case 1:
                {
                    stream.Write(new byte[] { 0, 0, 0, 0 }, 0, 4);
                    stream.Write(new byte[] { 255, 255, 255, 0 }, 0, 4);
                    break;
                }
            default:
                break;
        }

        //body
        _writeStream.Seek(0, SeekOrigin.Begin);
        CopyStream(_writeStream, stream);
    }

    void CopyStream(Stream source, Stream target)
    {
        byte[] bs = new byte[1024];
        int len;
        do
        {
            len = source.Read(bs, 0, bs.Length);
            if (len > 0)
                target.Write(bs, 0, len);
        } while (len > 0);
    }

    bool ValidWriteStream(bool resetIfInvalid)
    {
        bool valid = true;
        if (_writeStream == null || !_writeStream.CanWrite)
            valid = false;

        if (!valid && resetIfInvalid)
            ResetWriteStream();
        return valid;
    }

    void ResetWriteStream()
    {
        byte[] bs = new byte[_imageSize];
        if (_readStream != null)
            _readStream.Read(bs, 0, bs.Length);
        _writeStream = new MemoryStream(bs);
    }
}

使用参考:

using(Bmp bmp = new Bmp(@"C:\Users\admin\Pictures\5.bmp"))
{
    Color color = bmp.GetPixel(10, 10);
    Color color1 = bmp.GetPixel(444, 0);
    ;
}
using (Bmp bmp = new Bmp(10, 10, 1))
{
    for (int i = 0; i < bmp.Width; i++)
    {
        for (int j = 0; j < bmp.Height; j+=2)
            bmp.SetPixel(i, j, Color.White);
    }
    using(FileStream fs = File.OpenWrite("C:\\Users\\admin\\Pictures\\4.bmp"))
        bmp.Save(fs);
}