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

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

看来得手工处理一下把底色统一了,原图分辨率挺高的,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. Javascript对象的几种创建方式

    (1) 工厂模式 Function(){ Var child = new object() Child.name = “欲泪成雪” Child.age=”20” Return child; } Var ...

  2. BootStrap框架引入文件

    bootstrap -- 框架 引入需要的  这是外网的------************************************************************* < ...

  3. django 视图 使用orm values_list()方法获取 指定的 多个字段的数据

    from .models import UserInfodata_set = UserInfo.objects.all().values_list("user_name", &qu ...

  4. Linux中一些 不是很常用的配置修改

    1,让虚拟机屏幕最大化 :查看-->自动调整大小-->自动适应客户机 2,让虚拟机取消屏保: system --> preferences --> Screensaver

  5. 版本控制(.git + .svn)

    git 分布式版本控制系统 底层C语言 按元数据方式存储,采用SHA-1哈希算法(内容完整性好) 结合GitHub,为开源项目免费提供Git存储 git config --global user.na ...

  6. day 12 课后作业

    # -*- coding: utf-8 -*-# @Time : 2019/1/4 20:49# @Author : Endless-cloud# @Site : # @File : day 12 课 ...

  7. 考试题 T1

    题意分析 就是让你求 \[\sum_{i=1}^{|S|}val[i][gcd(a[i],x)=y]\] 那么接下来就是化简式子 \[\sum_{i=1}^{|S|}val[i][gcd(\frac{ ...

  8. java中mongo的条件查询

    @Override public Page<ProductInfo> findAll(Pageable pageable, ProductInfo productInfo) { //创建一 ...

  9. 新人须知的网站文件和MySQL数据库备份流程思路

    昨天老左再次遇到一个网友告知使用的一台服务器自己无意中点击主机商面板的导致服务器被重新安装系统(居然这也可以),问问是否可以恢复数据.这个同学和之前遇到好几次的网友真相似,从开始购买服务器,到自己网站 ...

  10. 基于python的几种排序算法的实现

    #!usr/bin/python3 # -*- coding: utf-8 -*- # @Time : 2019/3/28 10:26 # @Author : Yosef-夜雨声烦 # @Email ...