Bitmap 之 getPixels() 的 stride
学习Graphics中遇到位图(Bitmap)中getPixels()方法,对该方法的用法大体理解,但对其中的stride参数却不明白具体的用法以及用意,现记述过程如下:
Android英文SDK中有关getPixels()方法的介绍如下:
public void getPixels (int[] pixels, int offset, int stride, int x, int y, int width, int height)
Returns in pixels[] a copy of the data in the bitmap. Each value is a packed int representing a Color. The stride parameter allows the caller to allow for gaps in the returned pixels array between rows. For normal packed results, just pass width for the stride value.
Parameters
| pixels | The array to receive the bitmap's colors |
|---|---|
| offset | The first index to write into pixels[] |
| stride | The number of entries in pixels[] to skip between rows (must be >= bitmap's width). Can be negative. |
| x | The x coordinate of the first pixel to read from the bitmap |
| y | The y coordinate of the first pixel to read from the bitmap |
| width | The number of pixels to read from each row |
| height | The number of rows to read |
Throws
| IllegalArgumentException | if x, y, width, height exceed the bounds of the bitmap, or if abs(stride) < width. |
|---|---|
| ArrayIndexOutOfBoundsException | if the pixels array is too small to receive the specified number of pixels. |
看完英文文档仍然不甚明白,于是去搜了下中文Android文档相应内容, getPixels()
public void getPixels (int[] pixels, int offset, int stride, int x, int y, int width, int height)
把位图的数据拷贝到pixels[]中。每一个都由一个表示颜色值的int值来表示。幅度参数(stride)表明调用者允许的像素数组行间距。对通常的填充结果,只要传递宽度值给幅度参数。
参数
pixels 接收位图颜色值的数组
offset 写入到pixels[]中的第一个像素索引值
stride pixels[]中的行间距个数值(必须大于等于位图宽度)。可以为负数
x 从位图中读取的第一个像素的x坐标值。
y 从位图中读取的第一个像素的y坐标值
width 从每一行中读取的像素宽度
height 读取的行数
异常
IllegalArgumentExcepiton 如果x,y,width,height越界或stride的绝对值小于位图宽度时将被抛出。
ArrayIndexOutOfBoundsException 如果像素数组太小而无法接收指定书目的像素值时将被抛出。
看完后仍然对Stride解释中的"行间距"不太明白,去查了下Stride在英语中的原义,Stride在柯林斯中的英英释义如下:
1 If you stride somewhere, you walk there with quick, long steps.
stride意为"大踏步快速前进"
2 A stride is a long step which you take when you are walking or running.
stride在此做名词,意为"大步"
3 Someone's stride is their way of walking with long steps.
指代某人具体迈大步的方式.
于是可以把stride理解为人行走过程中所迈大步的一段距离,而在此方法中可以理解为每行的像素数,至于用处是什么,还要继续寻找答案.
然后去StackOverFlow去搜了搜"getPixels() stride"关键字,查找到如下信息:
1 In most cases the stride is the same as the width. The stride is useful if you are trying to copy/draw a sub-region of a Bitmap. For instance, if you have a 100x100 bitmap and you want to draw the 50x50 top-right corner, you can use a width of 50px and a stride of 100px.(注:stride绝对值要大于等于位图的宽度)
2 Stride is number of bytes used for storing one image row.
Most of the images are 4 byte aligned.
So you will see stride as 154, width 50 and image alignment as 4 byte.
上面内容表示stride参数有两种用处
第一种:
可以截取图片中部分区域或者图片拼接.
截图:假设读取像素值的原图片宽为w,高为h,此时设置参数pixels[w*h], 参数stride为 w ,参数offset为0,参数x ,y为截图的起点位置,参数width和height为截图的宽度和高度,则此方法运行后,返回的pixels[]数组中从pixels[0]至pixels[width*height-1]里存储的是从图片( x , y )处起读取的截图大小为width * height的像素值.
示例:修改Android SDK自带的AipDemo程序中BitmapDecode示例,更换图像为自制四角四色图: 
图像大小为100*100,想截取图片右上1/4图像(图上黄色部分)修改程序部分代码为:
- int[] pixels = new int[w*h];
- mBitmap2.getPixels(pixels, 0, w, 50, 0, w/2, h/2);
- mBitmap3 = Bitmap.createBitmap(pixels, 0, w, w, h, Bitmap.Config.ARGB_8888);
- mBitmap4 = Bitmap.createBitmap(pixels, 0, w, w, h, Bitmap.Config.ARGB_4444);
- String txt = String.valueOf(pixels[10]);
- Log.i("myBitmapDecode", "w = " + w + "; h = " + h);
- Log.i("myBitmapDecode", "pixels[0] = " + pixels[0] + "; pixels[1] = " + pixels[1] + "; pixels[10] = " + pixels[10]);
- Log.i("myBitmapDecode", "pixels[w] = " + pixels[w] + "; pixels[h] = " + pixels[h] + "; pixels[w*h-1] = " + pixels[w*h-1]);
运行结果: 
I/myBitmapDecode( 660): w = 100; h = 100
I/myBitmapDecode( 660): pixels[0]-16777216; pixels[1] = -16777216; pixels[10] = -4352
I/myBitmapDecode( 660): pixels[w]-16777216; pixels[h] = -16777216; pixels[w*h-1] = 0
我们看到右边两副ARGB_8888,ARGB_4444图像隐约只在左上角显示原图右上的1/4黄色部分,其余部分为背景色白色,那么问题又来了,此时ARGB_8888,ARGB_4444图像大小为多少?还是原图的大小(100*100)吗,或者是(50*50)了,不然背景色为何是画布的背景色呢(白色)?那么把 pixels[100*100]数组设初始值看下情况(通过Log.i()我查到了pixels中存储的像素值为百万左右的负整数(-16777216),所以这里胡乱取个数-2578654做为初始值,颜色不太好,请见谅),修改后代码如下:
- int[] pixels = new int[w*h];
- for(int i=0; i<w*h; i++){
- pixels[i] = -2578654;
- }
- mBitmap2.getPixels(pixels, 0, w, 50, 0, w/2, h/2);
- mBitmap3 = Bitmap.createBitmap(pixels, 0, w, w, h, Bitmap.Config.ARGB_8888);
- mBitmap4 = Bitmap.createBitmap(pixels, 0, w, w, h, Bitmap.Config.ARGB_4444);
- String txt = String.valueOf(pixels[10]);
- Log.i("myBitmapDecode", "w = " + w + "; h = " + h);
- Log.i("myBitmapDecode", "pixels[0] = " + pixels[0] + "; pixels[1] = " + pixels[1] + "; pixels[10] = " + pixels[10]);
- Log.i("myBitmapDecode", "pixels[w] = " + pixels[w] + "; pixels[h] = " + pixels[h] + "; pixels[w*h-1] = " + pixels[w*h-1]);
运行结果:

I/myBitmapDecode( 727): pixels[0] = -16777216; pixels[1] = -16777216; pixels[10] = -4352
I/myBitmapDecode( 727): pixels[w] = -16777216; pixels[h] = -16777216; pixels[w*h-1] = -2578654
我们可以看到结果了,如果pixels[]中的数值为int默认值(0)的话,图片相应的部分就为背景色,如果设置为别的初始值而在运行中没有被修改的话,背景色就是修改值对应的RGB颜色.
原图位置(offset)
下面设置下getPixels[]方法中offset,使得黄色部分截图出现在它在原图中的位置,
offset = x + y*w ,本例代码如下:
- int[] pixels = new int[w*h];
- for(int i=0; i<w*h; i++){
- pixels[i] = -2578654;
- }
- mBitmap2.getPixels(pixels, 50, w, 50, 0, w/2, h/2;
- mBitmap3 = Bitmap.createBitmap(pixels, 0, w, w, h, Bitmap.Config.ARGB_8888);
- mBitmap4 = Bitmap.createBitmap(pixels, 0, w, w, h, Bitmap.Config.ARGB_4444);
- String txt = String.valueOf(pixels[10]);
- Log.i("myBitmapDecode", "w = " + w + "; h = " + h);
- Log.i("myBitmapDecode", "pixels[0] = " + pixels[0] + "; pixels[1] = " + pixels[1] + "; pixels[10] = " + pixels[10]);
- Log.i("myBitmapDecode", "pixels[w] = " + pixels[w] + "; pixels[h] = " + pixels[h] + "; pixels[w*h-1] = " + pixels[w*h-1]);
运行结果:
I/myBitmapDecode( 761): w = 100; h = 100
I/myBitmapDecode( 761): pixels[0] = -2578654; pixels[1] = -2578654; pixels[10] = -2578654
I/myBitmapDecode( 761): pixels[w] = -2578654; pixels[h] = -2578654; pixels[w*h-1] = -2578654
当然可以用这个方法进行更复杂的运算,诸如截取素材图片修改目标图片(已存储至pixels数组中)的指定区域!!
背景色设置(pixels[])
背景颜色与pixels[]初始值一致,如红色RED(-65536 0xffff0000),黄色YELLOW(-256 0xffffff00),具体详见下面附注
- int[] pixels = new int[w*h];
- for(int i=0; i<w*h; i++){
- pixels[i] = -65536; // Color.RED : -65536 (0xffff0000)
- }
- mBitmap2.getPixels(pixels, 50, w, 50, 0, w/2, h/2);
- mBitmap3 = Bitmap.createBitmap(pixels, 0, w, w, h, Bitmap.Config.ARGB_8888);
- Log.i("myBitmapDecode", "w = " + w + "; h = " + h);
- Log.i("myBitmapDecode", "pixels[0] = " + pixels[0] + "; pixels[1] = " + pixels[1] + "; pixels[10] = " + pixels[10] + "; pixels[50] = " + pixels[50]);
- Log.i("myBitmapDecode", "pixels[w] = " + pixels[w] + "; pixels[h] = " + pixels[h] + "; pixels[w*h-1] = " + pixels[w*h-1]);
- for(int i=0; i<w*h; i++){
- pixels[i] = -256; // Color.YELLOW : -256 (0xffffff00)
- }
- mBitmap2.getPixels(pixels, 50*100 + 50, w, 50, 50, w/2, h/2);
- mBitmap4 = Bitmap.createBitmap(pixels, 0, w, w, h, Bitmap.Config.ARGB_4444);
- Log.i("myBitmapDecode", "w = " + w + "; h = " + h);
- Log.i("myBitmapDecode", "pixels[0] = " + pixels[0] + "; pixels[1] = " + pixels[1] + "; pixels[10] = " + pixels[10] + "; pixels[50] = " + pixels[50]);
- Log.i("myBitmapDecode", "pixels[w] = " + pixels[w] + "; pixels[h] = " + pixels[h] + "; pixels[w*h-1] = " + pixels[w*h-1]);
运行结果:

I/myBitmapDecode( 1671): w = 100; h = 100
I/myBitmapDecode( 1671): pixels[0] = -65536; pixels[1] = -65536; pixels[10] = -65536; pixels[50] = -16777216
I/myBitmapDecode( 1671): pixels[w] = -65536; pixels[h] = -65536; pixels[w*h-1] = -65536
I/myBitmapDecode( 1671): w = 100; h = 100
I/myBitmapDecode( 1671): pixels[0] = -256; pixels[1] = -256; pixels[10] = -256; pixels[50] = -256
I/myBitmapDecode( 1671): pixels[w] = -256; pixels[h] = -256; pixels[w*h-1] = -16735513
图片拼接:
假设两张图片大小都为 w * h ,getPixels()方法中设置参数pixels[2*w*h],参数offset = 0,stride = 2*w读取第一张图片,再次运行getPixels()方法,设置参数offset = w,stride = 2*w,读取第二张图片,再将pixels[]绘制到画布上就可以看到两张图片已经拼接起来了.
示例如下:
- int w = mBitmap2.getWidth();
- int h = mBitmap2.getHeight();
- int[] pixels = new int[2*w*h];
- for(int i=0; i<2*w*h; i++){
- pixels[i] = -2578654;
- }
- mBitmap2.getPixels(pixels, 0, 2*w, 0, 0, w, h);
- mBitmap2.getPixels(pixels, w, 2*w, 0, 0, w, h);
- mBitmap3 = Bitmap.createBitmap(pixels, 0, 2*w, 2*w, h, Bitmap.Config.ARGB_8888);
- String txt = String.valueOf(pixels[10]);
- Log.i("myBitmapDecode", "w = " + w + "; h = " + h);
- Log.i("myBitmapDecode", "pixels[0] = " + pixels[0] + "; pixels[1] = " + pixels[1] + "; pixels[10] = " + pixels[10]);
- Log.i("myBitmapDecode", "pixels[w] = " + pixels[w] + "; pixels[h] = " + pixels[h] + "; pixels[w*h-1] = " + pixels[w*h-1]);
- Log.i("myBitmapDecode", "pixels[2*w-1] = " + pixels[2*w-1] + "; pixels[2*w] = " + pixels[2*w] + "; pixels[2*w*h-1] = " + pixels[2*w*h-1]);
运行结果: 
I/myBitmapDecode( 989): w = 100; h = 100
I/myBitmapDecode( 989): pixels[0] = -16777216; pixels[1] = -16777216; pixels[10] = -16777216
I/myBitmapDecode( 989): pixels[w] = -16777216; pixels[h] = -16777216; pixels[w*h-1] = -16777216
I/myBitmapDecode( 989): pixels[2*w-1] = -3328; pixels[2*w] = -16777216; pixels[2*w*h-1] = -16735513
第二种:
stride表示数组pixels[]中存储的图片每行的数据,在其中可以附加信息,即
stride = width + padding,如下图所示
这样可以不仅仅存储图片的像素信息,也可以储存相应每行的其它附加信息.
最后,stride参数的意义及用处总结如下:
1 用来表示pixels[]数组中每行的像素个数,用于行与行之间区分,绝对值必须大于参数width,但不必大于所要读取图片的宽度w(在width < w 时成立).(stride负数有何作用不知,存疑).另,pixels.length >= stride * height,否则会抛出ArrayIndexOutOfBoundsException异常
2 stride > width时,可以在pixels[]数组中添加每行的附加信息,可做它用.
附注(Color颜色对应值):
Bitmap 之 getPixels() 的 stride的更多相关文章
- (转)C#进行图像处理的几种方法(Bitmap,BitmapData,IntPtr)
转自 http://blog.sina.com.cn/s/blog_628821950100wh9w.html C#进行图像处理的几种方法 本文讨论了C#图像处理中Bitmap类.BitmapData ...
- Android项目刮刮奖详解(四)
Android项目刮刮奖详解(三) 前言 上一期我们已经是完成了刮刮卡的基本功能,本期就是给我们的项目增加个功能以及美化一番 目标 增加功能 用户刮卡刮到一定程度的时候,清除遮盖层 在遮盖层放张图片, ...
- 使用C#进行图像处理的几种方法(转)
本文讨论了C#图像处理中Bitmap类.BitmapData类和unsafe代码的使用以及字节对齐问题. Bitmap类 命名空间:System.Drawing 封装 GDI+ 位图,此位图由图形图像 ...
- C#的图像处理方法--(作者:http://conner-wang.spaces.live.com转载)
使用C#进行图像处理的几种方法 本文讨论了C#图像处理中Bitmap类.BitmapData类和unsafe代码的使用以及字节对齐问题. Bitmap类 命名空间:System.Drawing 封装 ...
- C#GDI+图像处理
支持格式:BMP.GIF.JPEG.EXIF.PNG.TIFF.ICON.WMF.EMF等,几乎涵盖所有常用格式 图像类: Image类:Bitmap和Metafile的类提供功能的抽象基类. Met ...
- WPF学习(11)2D绘图
本篇我们来学习WPF的绘图,在2D绘图中主要有这么几个重要的类:Drawing.Visual和Shape,顺便讲下Brush和BitmapEffect. 1 2D绘图 1.1Drawing类 Draw ...
- wpf,vb,位图剪裁的方法
‘ 貌似WPF对GDI+不提供支持,要达到剪裁图像的方法,可以使用image.clip,’不过clip只是对图片的一个遮挡拦截效果,并不改变本身的图片资源.‘下面的代码提供了剪裁图片资源的方法. Di ...
- WPF:通过BitmapSource的CopyPixels和Create方法来切割图片
原文 WPF:通过BitmapSource的CopyPixels和Create方法来切割图片 BitmapSource是WPF图像的最基本类型,它同时提供两个像素相关的方法就是CopyPixels和C ...
- libass简明教程
[时间:2019-05] [状态:Open] [关键词:字幕,libass,字幕渲染,ffmpeg, subtitles, video filter] 0 引言 libass库则是一个轻量级的对ASS ...
随机推荐
- poj3280 区间dp
//Accepted 15880 KB 250 ms #include <cstdio> #include <cstring> #include <iostream> ...
- WebGrid Enterprise免费下载
WebGrid.NET Enterprise是一个为ASP.NET平台下WEB开发而设计的高级数据表格控件.WebGrid.NET为复杂的分层次导航交互式企业级信息传输提供了全面而先进的功能,它允许用 ...
- js注册验证
var user = $("user");var userCheck = $("userCheck");var pwd = $("pwd") ...
- Python 字符串处理大全.
Python 字符串 字符串是Pyhton中常用的数据类型,我们可以使用引号来创建字符串 . 创建字符串很简单 , 就不说了 . Python 访问字符串中的值 鬼叔本着简洁 使用的设计目的 , 在设 ...
- int和char的相同和不同。
int和char在存储量上有不同而且在编程的时候,这样才是正确的,如果这样的话,这是一个区别. 第二:这个和上面的道理应该是差不多的.输出97 98. 总的来说,int和char都是一个定义量器的 ...
- svn认证失败时的解决
删除用户目录下的.subversion文件夹,这个文件夹记录了密码! rm .subversion/ -rf
- win7下环境搭建
1.Python下载 https://www.python.org/downloads/windows/ 选择需要安装的版本,我偷懒装的可执行文件. 下载之后双击安装就OK啦,安装过程中有一项偷懒的选 ...
- linux常用命令:3文件搜索命令
文件搜索命令 1. 命令名:find 命令所在路径:/bin/find 执行权限:所有用户 语法:find [搜索范围] [匹配条件] 功能描述:文件搜索 文件搜索类型 通过文件名搜索 -name ...
- Recaman's Sequence_递推
Description The Recaman's sequence is defined by a0 = 0 ; for m > 0, am = am−1 − m if the rsultin ...
- 内存回收,Dispose,Close,Finalie(C#中的析构函数)
NET中的资源分托管和非托管,所谓的托管是指CLR(通用语言运行时)中进行管理的资源,它可以由CLR自动进行内存回收. 也就是大家熟知的GC(垃圾回收机制). 而对于 非托管资源,比如数据库连接,CO ...