昨天想基于一张图片做个手机锁屏来着,原图如下:

主要是嫌白底太丑了,一开始是想画图工具直接油漆桶伺候,然而一浇上去就发现问题了,变成了这样:

看来得手工处理一下把底色统一了,原图分辨率挺高的,SetPixel显然会太慢,所以只能LockBits咯。

LockBits的使用方法和参数什么的都可以百度和MSDN,不多说,直接贴一个BitmapWrapper先:

 unsafe class BitmapWrapper
{
private readonly Bitmap bmp;
private readonly BitmapData bmpData; private readonly byte* scan0;
private readonly int byteCount; public BitmapWrapper(Bitmap bitmap)
{
bmp = bitmap;
bmpData = bmp.LockBits(
new Rectangle(, , bmp.Width, bmp.Height),
ImageLockMode.ReadWrite,
bmp.PixelFormat); scan0 = (byte*) bmpData.Scan0;
// byteCount = bmpData.Stride / bmpData.Width;
byteCount = bmpData.PixelFormat.ToString().IndexOf("") > ? : ;
}
public Bitmap UnWrapper()
{
bmp.UnlockBits(bmpData);
return bmp;
}
public void SetPixel(Point point, Color color)
{
int offset = (point.X - ) * byteCount + (point.Y - ) * bmpData.Stride;
scan0[offset] = color.B;
scan0[offset + ] = color.G;
scan0[offset + ] = color.R;
if (byteCount == )
scan0[offset + ] = color.A;
}
public Color GetPixel(Point point)
{
int offset = (point.X - ) * byteCount + (point.Y - ) * bmpData.Stride;
Color color = Color.FromArgb(
scan0[offset + ],
scan0[offset + ],
scan0[offset]
);
if (byteCount == )
color = Color.FromArgb(scan0[offset + ], color);
return color;
}
}

注意代码里头有一句注掉了,那里是我出现第一个问题的地方。。。
本来是想计算每一像素占的字节数,那就拿每行的字节数除每一行的像素数咯,于是就错了。。。
MSDN查BitmapData.Stride可以看到备注里面的一句话:

跨距是单行像素(一个扫描行)的宽度,舍入为一个 4 字节的边界。

所以跨距其实应该是等于这样的:Stride = byteCount * Width + ((byteCount * Width) % 4) == 0 ? 0 : (4 - (byteCount * Width) % 4)
于是不知道该怎么反解byteCount,所以用了19行的那个方法,暂时忽略其他情况吧。。。

第二个问题是发生在存取RGB三个byte值的时候。
因为每个像素的RGB三个值是从高位到低位放置的,所以SetPixel里面应该是这样:

scan0[offset] = color.B;
scan0[offset + ] = color.G;
scan0[offset + ] = color.R;

而不是这样:

scan0[offset] = color.R;
scan0[offset + ] = color.G;
scan0[offset + ] = color.B;

第三个问题发生在保存图片的时候。。。本来是这么写的:

bmp.Save("Juven.bmp");

打开图片再用油漆桶,发现还是和原来差不多,底色里面仍然参杂了高度接近纯白的灰色斑点。
因为Save不管你文件扩展名是什么的啊!通通默认Jpeg啊!一压缩就前功尽弃了!所以应该改成这样:

bmp.Save(@"Juven.bmp", ImageFormat.Bmp);

这样就对了,油漆桶后的效果如下(上传前转回jpg了,所以这张图的底色其实还是不纯的):

既然都走到这一步了,就干脆走得远一点,直接代码做成品了:

 Bitmap bmp = new Bitmap(src);
BitmapWrapper wrapper = new BitmapWrapper(bmp); byte r, g, b;
for (int y = ; y <= bmp.Height; y++)
{
for (int x = ; x <= bmp.Width; x++)
{
Point point = new Point(x, y);
Color cr = wrapper.GetPixel(point);
if (cr.R + cr.G + cr.B >= )
{
if (x < )
{
r = ;
g = ;
b = ;
}
else if (x > )
{
r = ;
g = ;
b = ;
}
else
r = g = b = ;
wrapper.SetPixel(point, Color.FromArgb(r, g, b));
}
else break;
} for (int x = bmp.Width; x > ; x--)
{
Point point = new Point(x, y);
Color cr = wrapper.GetPixel(point);
if (cr.R + cr.G + cr.B >= )
{
if (x < )
{
r = ;
g = ;
b = ;
}
else if (x > )
{
r = ;
g = ;
b = ;
}
else
r = g = b = ;
wrapper.SetPixel(point, Color.FromArgb(r, g, b));
}
else break;
}
}
57 wrapper.UnWrapper();
bmp.Save(target);

成品图如下:

最后想说的是,巴萨梅球王求轻虐十个以内啊!

[C#]LockBits使用笔记的更多相关文章

  1. C#数字图像处理算法学习笔记(三)--图像几何变换

    C#数字图像处理算法学习笔记(三)--图像几何变换 几何图像处理包括 图像的平移变换,镜像变换,旋转变换,伸缩变换,在这里仅以水平镜像为例,通过代码来理解其基本操作方式: 翻转前:

  2. 项目笔记---CSharp图片处理

    原文:项目笔记---CSharp图片处理 项目笔记---CSharp图片处理 最近由于项目上需要对图片进行二值化处理,就学习了相关的图片处理上的知识,从开始的二值化的意义到动态阀值检测二值化等等,并用 ...

  3. C#数字图像处理算法学习笔记(一)--C#图像处理的3中方法

    C#数字图像处理算法学习笔记(一)--C#图像处理的3中方法 Bitmap类:此类封装了GDI+中的一个位图,次位图有图形图像及其属性的像素数据组成.因此此类是用于处理像素数据定义的图形的对象.该类的 ...

  4. git-简单流程(学习笔记)

    这是阅读廖雪峰的官方网站的笔记,用于自己以后回看 1.进入项目文件夹 初始化一个Git仓库,使用git init命令. 添加文件到Git仓库,分两步: 第一步,使用命令git add <file ...

  5. js学习笔记:webpack基础入门(一)

    之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...

  6. SQL Server技术内幕笔记合集

    SQL Server技术内幕笔记合集 发这一篇文章主要是方便大家找到我的笔记入口,方便大家o(∩_∩)o Microsoft SQL Server 6.5 技术内幕 笔记http://www.cnbl ...

  7. PHP-自定义模板-学习笔记

    1.  开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2.  整体架构图 ...

  8. PHP-会员登录与注册例子解析-学习笔记

    1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...

  9. NET Core-学习笔记(三)

    这里将要和大家分享的是学习总结第三篇:首先感慨一下这周跟随netcore官网学习是遇到的一些问题: a.官网的英文版教程使用的部分nuget包和我当时安装的最新包版本不一致,所以没法按照教材上给出的列 ...

随机推荐

  1. PHP一句话木马Webshell变形免杀总结

    0×00 前言 大部分Webshell查杀工具都是基于关键字特征的,通常他们会维护一个关键字列表,以此遍历指定扩展名的文件来进行扫描,所以可能最先想到的是各种字符串变形,下面总结了一些小的方法,各种不 ...

  2. 喝最烈的酒、挖最大的DONG——工具与技巧篇

    本文作者:i春秋签约作家——黑色镰刀 0×00 前言 在这个科技发达的时代,很多时候工具都可以代替人做很多事情,之前我就有谈起过有企业将人工智能运用于网络安全方面,像如今,也有更多更人性化更智能的工具 ...

  3. 查看npm全局安装位置

    查看npm全局安装位置:npm config get prefix 设置位置:npm config set prefix 填写位置

  4. 【javascrpt】——图片预览和上传,兼容IE 9-

    下载DEMO:https://github.com/CaptainLiao/zujian/tree/master/Upload 对于现代浏览器来说,要实现图片预览非常简单: 1.fileReader. ...

  5. 字符串模式匹配算法2 - AC算法

    上篇文章(http://www.cnblogs.com/zzqcn/p/3508442.html)里提到的BF和KMP算法都是单模式串匹配算法,也就是说,模式串只有一个.当需要在字符串中搜索多个关键字 ...

  6. ASP.NET MVC 发布后 IE 访问出现布局错乱问题

    ASP.NET MVC 网页debug启动跑一切正常,[Chrome],[FireFox],[Edge],[IE11] 发布后,使用机器名访问,[IE11]出现布局不正常的问题, 在head里:加↓可 ...

  7. nginx的几种负载均衡策略

    转自https://www.cnblogs.com/1214804270hacker/p/9325150.html 一.关于Nginx的负载均衡 在服务器集群中,Nginx起到一个代理服务器的角色(即 ...

  8. 如何在CentOS 7上使用vsftpd(FTP)的配置文件介绍

    vsftpd.conf - vsftpd的配置文件. 描述 vsftpd.conf可用于控制vsftpd行为的各个方面. 默认情况下,vsftpd在/etc/vsftpd.conf位置查找此文件. 但 ...

  9. C#-WebForm-LinQ(一)-LinQ:语言集成查询(Language Integrated Query)-增删改查、属性扩展

    LinQ-语言集成查询(Language Integrated Query) 高集成化的数据库访问技术 LINQ 2 SQL 实际是将数据库的表映射成程序中的类 会把数据库的表名原封不动的变成类名 数 ...

  10. i2c_smbs 函数

    i2c_smbus系列函数有: s32 i2c_smbus_read_byte(const struct i2c_client *client); s32 i2c_smbus_write_byte(c ...