BMP文件操作详细说明by goodoo-程序员宅基地

技术标签: struct  tiff  fp  存储  windows  delete  

1. BMP文件结构及其存取
数字图像在外存储器设备中的存储形式是图像文件,图像必须按照某个已知的、公认的数据存储顺序和结构进行存储,才能使不同的程序对图像文件顺利进行打开或存盘操作,实现数据共享。图像数据在文件中的存储顺序和结构称为图像文件格式。目前广为流传的图像文件格式有许多种,常见的格式包括BMP、GIF、JPEG、TIFF、PSD、DICOM、MPEG等。在各种图像文件格式中,一部分是由某个软硬件厂商提出并被广泛接受和采用的格式,例如BMP、GIF和PSD格式;另一部分是由各种国际标准组织提出的格式,例如JPEG、TIFF和DICOM,其中JPEG是国际静止图像压缩标准组织提出的格式,TIFF是由部分厂商组织提出的格式,DICOM是医学图像国际标准组织提出的医学图像专用格式。
BMP文件是Windows操作系统所推荐和支持的图像文件格式,是一种将内存或显示器的图像数据不经过压缩而直接按位存盘的文件格式,所以称为位图(bitmap)文件,因其文件扩展名为BMP,故称为BMP文件格式,简称BMP文件。本书对图像的算法编程都是针对BMP图像文件的,因此在本章中我们详细介绍BMP文件结构及其读写操作,以加深对图像数据的理解。
1.1  BMP文件结构
如图1-7所示,BMP图像文件被分成4个部分:位图文件头(Bitmap File Header)、位图信息头(Bitmap Info Header)、颜色表(Color Map)和位图数据(即图像数据,Data Bits或Data Body)。
第1部分为位图文件头BITMAPFILEHEADER,是一个结构体类型,该结构的长度是固定的,为14个字节。其定义如下:
typedef struct tagBITMAPFILEHEADER
{
    WORD bfType;        
    DWORD bfSize;
    WORD bfReserved1;   
    WORD bfReserved2;
     DWORD bfOffBits;
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;
BITMAPFILEHEADER结构的各个域详细说明如下:
—  bfType:位图文件类型,必须是0x424D,即字符串“BM”,也就是说,所有的“*.bmp”文件的头两个字节都是“BM”。
—  bfSize:位图文件大小,包括这14个字节。
—  bfReserved1, bfReserved2:Windows保留字,暂不用。
—  bfOffBits:从文件头到实际的位图数据的偏移字节数,图1-7中前3个部分的长度之和。
第2部分为位图信息头BITMAPINFOHEADER,也是一个结构体类型的数据结构,该结构的长度也是固定的,为40个字节(WORD为无符号16位整数,DWORD为无符号32位整数,LONG为32位整数)。其定义如下:
typedef struct tagBITMAPINFOHEADER
{
    DWORD biSize;            
    LONG biWidth;           
    LONG biHeight;          
    WORD biPlanes;          
    WORD biBitCount         
    DWORD biCompression;
    DWORD biSizeImage;      
    LONG biXPelsPerMeter;   
    LONG biYPelsPerMeter;   
    DWORD biClrUsed;    
    DWORD biClrImportant;   
} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;
BITMAPINFOHEADER结构的各个域的详细说明如下:
—  biSize:本结构的长度,为40个字节。
—  biWidth:位图的宽度,以像素为单位。
—  biHeight:位图的高度,以像素为单位。
—  biPlanes:目标设备的级别,必须是1。
—  biBitCount:每个像素所占的位数(bit),其值必须为1(黑白图像)、4(16色图)、8(256色)、24(真彩色图),新的BMP格式支持32位色。
—  biCompresssion:位图压缩类型,有效的值为BI_RGB(未经压缩)、BI_RLE8、BI_RLE4、BI_BITFILEDS(均为Windows定义常量)。这里只讨论未经压缩的情况,即biCompression=BI_RGB。
—  biSizeImage:实际的位图数据占用的字节数,该值的大小在第4部分位图数据中有具体解释。
—  biXPelsPerMeter:指定目标设备的水平分辨率,单位是像素/米。
—  biYPelsPerMeter:指定目标设备的垂直分辨率,单位是像素/米。
—  biClrUsed:位图实际用到的颜色数,如果该值为零,则用到的颜色数为2的biBitCount次幂。
—  biClrImportant:位图显示过程中重要的颜色数,如果该值为零,则认为所有的颜色都是重要的。
第3部分为颜色表。颜色表实际上是一个RGBQUAD结构的数组,数组的长度由biClrUsed指定(如果该值为零,则由biBitCount指定,即2的biBitCount次幂个元素)。RGBQUAD结构是一个结构体类型,占4个字节,其定义如下:
typedef struct tagRGBQUAD
{
    BYTE rgbBlue;
    BYTE rgbGreen;
    BYTE rgbRed;
    BYTE rgbReserved;
}RGBQUAD;
RGBQUAD结构的各个域的详细说明如下:
—  rgbBlue:该颜色的蓝色分量;
—  rgbGreen:该颜色的绿色分量;
—  rgbRed:该颜色的红色分量;
—  rgbReserved:保留字节,暂不用。
有些位图需要颜色表;有些位图(如真彩色图)则不需要颜色表,颜色表的长度由BITMAPINFOHEADER结构中biBitCount分量决定。对于biBitCount值为1的二值图像,每像素占1bit,图像中只有两种(如黑白)颜色,颜色表也就有21=2个表项,整个颜色表的大小为个字节;对于biBitCount值为8的灰度图像,每像素占8bit,图像中有28=256种颜色,颜色表也就有256个表项,且每个表项的R、G、B分量相等,整个颜色表的大小为个字节;而对于biBitCount=24的真彩色图像,由于每像素3个字节中分别代表了R、G、B三分量的值,此时不需要颜色表,因此真彩色图的BITMAPINFOHEADER结构后面直接就是位图数据。
第4部分是位图数据,即图像数据,其紧跟在位图文件头、位图信息头和颜色表(如果有颜色表的话)之后,记录了图像的每一个像素值。对于有颜色表的位图,位图数据就是该像素颜色在调色板中的索引值;对于真彩色图,位图数据就是实际的R、G、B值(三个分量的存储顺序是B、G、R)。下面分别就2色、16色、256色和真彩色位图的位图数据进行说明:
—  对于2色位图,用1位就可以表示该像素的颜色,所以1个字节能存储8个像素的颜色值。
—  对于16色位图,用4位可以表示一个像素的颜色。所以一个字节可以存储2个像素的颜色值。
—  对于256色位图,1个字节刚好存储1个像素的颜色值。
—  对于真彩色位图,3个字节才能表示1个像素的颜色值。
需要注意两点:
第一,Windows规定一个扫描行所占的字节数必须是4的倍数,不足4的倍数则要对其进行扩充。假设图像的宽为biWidth个像素、每像素biBitCount个比特,其一个扫描行所占的真实字节数的计算公式如下:
DataSizePerLine = (biWidth * biBitCount /8+ 3) / 4*4
那么,不压缩情况下位图数据的大小(BITMAPINFOHEADER结构中的biSizeImage成员)计算如下:
biSizeImage = DataSizePerLine * biHeight
第二,一般来说,BMP文件的数据是从图像的左下角开始逐行扫描图像的,即从下到上、从左到右,将图像的像素值一一记录下来,因此图像坐标零点在图像左下角。
1.2.2  BMP图像文件的读写
分析了BMP文件结构后,让我们用简单的C程序实现一个给定BMP位图文件的读写操作,来进一步巩固对图像数据的理解,这也是我们后续图像可视化编程的基础。此部分的代码以及后面两节所讲述的代码在工程chap1-1中的bmpReadWrite.cpp文件中,读者可以查阅。
1.BMP文件的读入
BMP文件分为4个组成部分,那么BMP文件的读入也要按照4个组成部分依次进行处理,即先处理BITMAPFILEHEADER结构,然后是BITMAPINFOHEADER结构、颜色表,最后是位图数据。
首先,有关BITMAPFILEHEADER、BITMAPINFOHEADER、RGBQUAD等结构的定义包含在头文件“Windows.h”中,应把其包含进来。
#include "Windows.h"
其次,为了后面对图像进行修改及存盘方便,我们定义了几个全局变量,用来存放读入图像的位图数据、宽、高、颜色表及每像素位数等信息。所定义的全局变量如下:
unsigned char *pBmpBuf;//读入图像数据的指针
int bmpWidth;//图像的宽
int bmpHeight;//图像的高
RGBQUAD *pColorTable;//颜色表指针
int biBitCount;//图像类型,每像素位数
根据BMP文件结构,BMP文件读入操作的基本流程如图1-8所示。
readBmp()函数实现了BMP文件的读取操作,下面的代码是对readBmp()函数的说明和实现。
/***********************************************************************
* 函数名称:
*     readBmp()
*
*函数参数:
*    char *bmpName -文件名字及路径
*
*返回值:
*    0为失败,1为成功
*
*说明:给定一个图像文件名及其路径,读图像的位图数据、宽、高、颜色表及每像素
*      位数等数据进内存,存放在相应的全局变量中
***********************************************************************/
bool readBmp(char *bmpName)
{
    //二进制读方式打开指定的图像文件
    FILE *fp=fopen(bmpName,"rb");
    if(fp==0) return 0;
    //跳过位图文件头结构BITMAPFILEHEADER
    fseek(fp, sizeof(BITMAPFILEHEADER),0);
    //定义位图信息头结构变量,读取位图信息头进内存,存放在变量head中
    BITMAPINFOHEADER head; 
    fread(&head, sizeof(BITMAPINFOHEADER), 1,fp);
    //获取图像宽、高、每像素所占位数等信息
    bmpWidth = head.biWidth;
    bmpHeight = head.biHeight;
    biBitCount = head.biBitCount;
    //定义变量,计算图像每行像素所占的字节数(必须是4的倍数)
    int lineByte=(bmpWidth * biBitCount/8+3)/4*4;
    //灰度图像有颜色表,且颜色表表项为256
    if(biBitCount==8){
        //申请颜色表所需要的空间,读颜色表进内存
        pColorTable=new RGBQUAD[256];
        fread(pColorTable,sizeof(RGBQUAD),256,fp);
    }
    //申请位图数据所需要的空间,读位图数据进内存
    pBmpBuf=new unsigned char[lineByte * bmpHeight];
    fread(pBmpBuf,1,lineByte * bmpHeight,fp);
    //关闭文件
    fclose(fp);
    return 1;
}
2.BMP文件的存盘
给定图像路径名以及图像的数据,对图像的写操作也是按照BMP文件4个组成部分进行分别处理的。其基本流程如图1-9所示。
saveBmp()函数实现了BMP文件的写操作,该函数的说明及代码实现如下。
/*****************************************
* 函数名称:
*     saveBmp()
*
*函数参数:
*    char *bmpName-文件名字及路径
*    unsigned char *imgBuf-待存盘的位图数据
*    int width-以像素为单位待存盘位图的宽
*    int  height-以像素为单位待存盘位图高
*    int biBitCount-每像素所占位数
*    RGBQUAD *pColorTable-颜色表指针
*返回值:
*    0为失败,1为成功
*
*说明:给定一个图像位图数据、宽、高、颜色表指针及每像素所占的位数等信息,
*      将其写到指定文件中
***********************************************************************/
bool saveBmp(char *bmpName, unsigned char *imgBuf, int width, int height,
             int biBitCount, RGBQUAD *pColorTable)
{
    //如果位图数据指针为0,则没有数据传入,函数返回
    if(!imgBuf)
        return 0;
    //颜色表大小,以字节为单位,灰度图像颜色表为1024字节,彩色图像颜色表大小为0
    int colorTablesize=0;
    if(biBitCount==8)
        colorTablesize=1024;
    //待存储图像数据每行字节数为4的倍数
    int lineByte=(width * biBitCount/8+3)/4*4;
    //以二进制写的方式打开文件
    FILE *fp=fopen(bmpName,"wb");
    if(fp==0) return 0;
    //申请位图文件头结构变量,填写文件头信息
    BITMAPFILEHEADER fileHead;
    fileHead.bfType = 0x4D42;//bmp类型
    //bfSize是图像文件4个组成部分之和
    fileHead.bfSize= sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)
        + colorTablesize + lineByte*height;
    fileHead.bfReserved1 = 0;
    fileHead.bfReserved2 = 0;
    //bfOffBits是图像文件前3个部分所需空间之和
    fileHead.bfOffBits=54+colorTablesize;
    //写文件头进文件
    fwrite(&fileHead, sizeof(BITMAPFILEHEADER),1, fp);
    //申请位图信息头结构变量,填写信息头信息
    BITMAPINFOHEADER head;
    head.biBitCount=biBitCount;
    head.biClrImportant=0;
    head.biClrUsed=0;
    head.biCompression=0;
    head.biHeight=height;
    head.biPlanes=1;
    head.biSize=40;
    head.biSizeImage=lineByte*height;
    head.biWidth=width;
    head.biXPelsPerMeter=0;
    head.biYPelsPerMeter=0;
    //写位图信息头进内存
    fwrite(&head, sizeof(BITMAPINFOHEADER),1, fp);
    //如果灰度图像,有颜色表,写入文件
    if(biBitCount==8)
        fwrite(pColorTable, sizeof(RGBQUAD),256, fp);
    //写位图数据进文件
    fwrite(imgBuf, height*lineByte, 1, fp);
    //关闭文件
    fclose(fp);
    return 1;
}
对于readBmp()和saveBmp()函数的简单调用如下:
void main()
{
    //读入指定BMP文件进内存
    char readPath[]="dog.BMP";
    readBmp(readPath);
    //输出图像的信息
    printf("width=%d,height=%d, biBitCount=%d/n",bmpWidth,bmpHeight, biBitCount);
    //将图像数据存盘
    char writePath[]="dogcpy.BMP";
    saveBmp(writePath, pBmpBuf, bmpWidth, bmpHeight, biBitCount, pColorTable);
    //清除缓冲区,pBmpBuf和pColorTable是全局变量,在文件读入时申请的空间
    delete []pBmpBuf;
    if(biBitCount==8)
        delete []pColorTable;
}
该main()函数将指定BMP文件读入内存,将图像信息打印输出,最后又原样存入指定文件中。读者可以打开程序当前目录下的“dog.bmp”和“dogcpy.bmp”两个文件进行对比。
以上对于BMP文件的读写函数仅针对灰度图像(biBitCount=8)和彩色图像(biBitCount=24)两种格式,对于其他如biBitCount=1的图像类型,读者可以根据需要,自己对程序作简单的修改即可实现。本书中后续的代码实现也都是围绕灰度和彩色两种格式进行的,希望读者予以注意。
1.2.3  BMP图像位图数据的访问
上面main()函数将图像文件读入内存,又写到文件里去,那么在读入图像数据后、写入文件前的一段时间里,图像的数据是在内存中存在的,这也是我们可以修改(访问)图像数据的时机所在。
假设内存中位图数据的指针为pBmpBuf,一行像素所占的字节数为lineByte(4的倍数)那么,对于灰度图像,第i行第j列的像素指针(所在的存储空间位置)为pBmpBuf+i*lineByte+j,*(pBmpBuf+i*lineByte+j)是该像素的灰度值,如果想让该像素变成指定颜色,只需要给*(pBmpBuf+i*lineByte+j)赋指定的值即可;对于彩色图像,每像素占3个字节,那么pBmpBuf+i*lineByte+j*3+0、pBmpBuf+i*lineByte+j*3+1、pBmpBuf+i*lineByte+j*3+2分别代表了第i行第j列像素B、G、R三个分量的指针,若想给该点指定一种颜色,则需要给三个分量分别赋值。
下面的main()函数中,将读入的图像数据左下角1/4部分置成黑色并存盘,图1-10所示是程序运行前后图像的变化情况。
void main()
{
    //读入指定BMP文件进内存
    char readPath[]="dog.BMP";
    readBmp(readPath);
    //输出图像的信息
    printf("width=%d,height=%d,biBitCount=%d/n",bmpWidth,bmpHeight,biBitCount);
    //循环变量,图像的坐标
    int i,j;
    //每行字节数
    int lineByte=(bmpWidth*biBitCount/8+3)/4*4;
    //循环变量,针对彩色图像,遍历每像素的三个分量
    int k;
    //将图像左下角1/4部分置成黑色
    if(biBitCount==8){//对于灰度图像
        for(i=0;i             for(j=0;j                 *(pBmpBuf+i*lineByte+j)=0;
            }
        }
    }
    else if(biBitCount==24){//彩色图像
        for(i=0;i             for(j=0;j                 for(k=0;k<3;k++)//每像素RGB三个分量分别置0才变成黑色
                    *(pBmpBuf+i*lineByte+j*3+k)=0;
            }
        }
    }
    //将图像数据存盘
    char writePath[]="dogcpy.BMP";
    saveBmp(writePath, pBmpBuf, bmpWidth, bmpHeight, biBitCount, pColorTable);
    //清除缓冲区,pBmpBuf和pColorTable是全局变量,在文件读入时申请的空间
    delete []pBmpBuf;
    if(biBitCount==8)
        delete []pColorTable;
}
图1-10  数据修改后图像对比
1.2.4  灰度图像的颜色表
如表1-2所示,灰度图像的颜色表是一个256个表项的RGBQUAD结构体数组(具体参看BMP文件结构中对颜色表的描述),而每个RGBQUAD中的R、G、B分量的值是相等的。随着颜色表数组下标从0到255变化,颜色表数组元素中R、G、B分量也从0到255依次变化。灰度图像的位图数据每像素一个字节,其值为0到255之间的一个,当显示一幅灰度图像时,系统根据像素值,到颜色表数组下标与之对应的表项(数组元素)中查看颜色,根据该表项中的颜色显示像素。由于灰度图像颜色表每个表项中R、G、B分量相等,因此只有图像亮度信息,没有颜色信息,因而显示出的灰度图像也就没有颜色了。
表1-2  灰度图像的颜色表
B
G
R
保 留 位
0
0
0
不确定
1
1
1
不确定
2
2
2
不确定
3
3
3
不确定
M
M
M
M
254
254
254
不确定
255
255
255
不确定
从以上的解释中我们知道,图像颜色表决定了图像的颜色,如果对灰度图像的颜色表数据进行改变,图像颜色自然也就被改变了。下面的main()函数,把灰度图像颜色表的蓝色分量进行了改变。
void main()
{
    //读入指定BMP文件进内存
    char readPath[]="dog.BMP";
    readBmp(readPath);
    //输出图像的信息
    printf("width=%d,height=%d,biBitCount=%d/n",bmpWidth,bmpHeight,biBitCount);
    //改变灰度图像的颜色表蓝色分量的值,查看前后变化
    if(biBitCount==8){
        for(int i=0; i<256;i++){
            pColorTable[i].rgbBlue = 255-pColorTable[i].rgbBlue;
        }
    }
    //将图像数据存盘
    char writePath[]="dogcpy.BMP";
    saveBmp(writePath, pBmpBuf, bmpWidth, bmpHeight, biBitCount, pColorTable);
    //清除缓冲区,pBmpBuf和pColorTable是全局变量,在文件读入时申请的空间
    delete []pBmpBuf;
    if(biBitCount==8)
        delete []pColorTable;
}

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/xjmeng001/article/details/6041268

智能推荐

oracle 12c 集群安装后的检查_12c查看crs状态-程序员宅基地

文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态

解决jupyter notebook无法找到虚拟环境的问题_jupyter没有pytorch环境-程序员宅基地

文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境

国内安装scoop的保姆教程_scoop-cn-程序员宅基地

文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn

Element ui colorpicker在Vue中的使用_vue el-color-picker-程序员宅基地

文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker

迅为iTOP-4412精英版之烧写内核移植后的镜像_exynos 4412 刷机-程序员宅基地

文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机

Linux系统配置jdk_linux配置jdk-程序员宅基地

文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk

随便推点

matlab(4):特殊符号的输入_matlab微米怎么输入-程序员宅基地

文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入

C语言程序设计-文件(打开与关闭、顺序、二进制读写)-程序员宅基地

文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。‍ Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。

Touchdesigner自学笔记之三_touchdesigner怎么让一个模型跟着鼠标移动-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动

【附源码】基于java的校园停车场管理系统的设计与实现61m0e9计算机毕设SSM_基于java技术的停车场管理系统实现与设计-程序员宅基地

文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计

Android系统播放器MediaPlayer源码分析_android多媒体播放源码分析 时序图-程序员宅基地

文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;amp;gt;Jni-&amp;amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图

java 数据结构与算法 ——快速排序法-程序员宅基地

文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法