其实到上一篇为止关于操作系统的开发就已经基本完成了。为了使操作系统更为丰富,本篇内容继续开发了一些应用程序,并改进了IPL启动区。

1. 应用程序开发——图片阅览器
作者在这里开发了命令行计算器、文本阅览器、MML播放器与图片阅览器等4个应用程序。有了这些程序的运行,这个操作系统已经很是像模像样了,可以实现看图,阅读文档,听音乐等基本功能,可谓麻雀虽小,五脏俱全。但这些应用程序的程序代码内容较多,涉及到的知识也很多,已经脱离了操作系统开发的主题,暂时先不在这里进行记录了。后面或许会深入研究,每一个应用程序,单独写一篇笔记进行记录。
这里主要记录代码内容较少的图片阅览器应用程序的开发。
#include "apilib.h"
struct DLL_STRPICENV { /* 64KB */
int work[64 * 1024 / 4];
};
struct RGB {
unsigned char b, g, r, t;
};
/* bmp.nasm */
int info_BMP(struct DLL_STRPICENV *env, int *info, int size, char *fp);
int decode0_BMP(struct DLL_STRPICENV *env, int size, char *fp, int b_type, char *buf, int skip);
/* jpeg.c */
int info_JPEG(struct DLL_STRPICENV *env, int *info, int size, char *fp);
int decode0_JPEG(struct DLL_STRPICENV *env, int size, char *fp, int b_type, char *buf, int skip);
unsigned char rgb2pal(int r, int g, int b, int x, int y);
void error(char *s);
void HariMain(void)
{
struct DLL_STRPICENV env;
char filebuf[512 * 1024], winbuf[1040 * 805];
char s[32], *p;
int win, i, j, fsize, xsize, info[8];
struct RGB picbuf[1024 * 768], *q;
/* 命令行解析 */
api_cmdline(s, 30);
for (p = s; *p > ' '; p++) { } /* 一直读取到空格为止 */
for (; *p == ' '; p++) { } /* 跳过空格 */
/* 读入文件 */
i = api_fopen(p);
if (i == 0)
{
error("file not found.\n");
}
fsize = api_fsize(i, 0);
if (fsize > 512 * 1024)
{
error("file too large.\n");
}
api_fread(filebuf, fsize, i);
api_fclose(i);
/* 检查文件类型 */
if (info_BMP(&env, info, fsize, filebuf) == 0) {
/* 非BMP格式*/
if (info_JPEG(&env, info, fsize, filebuf) == 0) {
/* 非JPEG */
api_putstr0("file type unknown.\n");
api_end();
}
}
/* 上面其中一个info函数如果调用成功,info函数中含有以下信息: */
/* info[0] : 文件类型 (1:BMP, 2:JPEG) */
/* info[1] : 颜色信息 */
/* info[2] : xsize */
/* info[3] : ysize */
if (info[2] > 1024 || info[3] > 768) {
error("picture too large.\n");
}
/* 准备窗口 */
xsize = info[2] + 16;
if (xsize < 136) {
xsize = 136;
}
win = api_openwin(winbuf, xsize, info[3] + 37, -1, "gview");
/* 将文件内容转换为图像数据 */
if (info[0] == 1) {
i = decode0_BMP (&env, fsize, filebuf, 4, (char *) picbuf, 0);
} else {
i = decode0_JPEG(&env, fsize, filebuf, 4, (char *) picbuf, 0);
}
/* b_type = 4 表示 struct RGB格式 */
/* skip设置为0既可 */
if (i != 0) {
error("decode error.\n");
}
/* 显示 */
for (i = 0; i < info[3]; i++) {
p = winbuf + (i + 29) * xsize + (xsize - info[2]) / 2;
q = picbuf + i * info[2];
for (j = 0; j < info[2]; j++) {
p[j] = rgb2pal(q[j].r, q[j].g, q[j].b, j, i);
}
}
api_refreshwin(win, (xsize - info[2]) / 2, 29, (xsize - info[2]) / 2 + info[2], 29 + info[3]);
/* 等待结束 */
for (;;) {
i = api_getkey(1);
if (i == 'Q' || i == 'q') {
api_end();
}
}
}
unsigned char rgb2pal(int r, int g, int b, int x, int y)
{
static int table[4] = { 3, 1, 0, 2 };
int i;
x &= 1; /* 判断是奇数还是偶数 */
y &= 1;
i = table[x + y * 2]; /* 用于生成中间色的常量 */
r = (r * 21) / 256; /* 结果为0-20 */
g = (g * 21) / 256;
b = (b * 21) / 256;
r = (r + i) / 4; /* 结果为0-5 */
g = (g + i) / 4;
b = (b + i) / 4;
return 16 + r + g * 6 + b * 36;
}
void error(char *s)
{
api_putstr0(s);
api_end();
}
前面命令行解析的部分,根据读入的命令行内容跳过空格,获取图片的文件名。
接下来使用api_fopen函数打开文件,并判断文件大小。如果文件大小在范围内,则通过api_fread函数将文件内容读入filebuf中,并通过api_fclose函数关闭文件。
将文件读入到filebuf中,还需要判断文件的格式。这个图片浏览器支持BMP与JPEG两种格式,因此接下来是文件格式的判断。文件格式为BMP或JPEG时,可以获取到图片信息。信息中包括图片的长宽,如果图片的长宽超出屏幕显示范围的也返回错误。
图片满足条件可以显示,接下来准备进行显示。对BMP格式与JPEG格式文件进行转换的关键函数为decode0_BMP与decode0_JPEG。这两个函数的源代码涉及到BMP格式与JPEG格式的相关知识,这里作者也从略了。对于decode0_JPEG,给出了源代码,对于decode0_BMP还给出了编译后的obj文件,可以直接进行调用。
这样图片阅览器程序就可以用来显示图片了,这里显示的是作者准备的图片:


2. IPL改进
为了加快启动速度,接下来对IPL再进行一些修改。
在前面我们实现了文件的压缩,启动区需要加载的内容减小到了9个柱面,可以重新改写ipl09.nas。同时还将一个一个扇区读取的方式优化为同时读取多个扇区(见【读书笔记-《30天自制操作系统》-2】Day3),理论上这样是可以加快启动速度的。不过根据实际使用设备的不同,启动速度加快的感受可能因人而异。
3. 通过光盘启动
之前作者的叙述一直是基于软盘的启动,实际上软盘在国内已经很难见到了。可以通过工具将之前生成的haribote.img文件生成ISO文件,再刻录到光盘中制成引导光盘,这样本操作系统就可以通过光盘启动了。
到此《30天自制操作系统》这本书的开发内容就基本讲完了。

1675

被折叠的 条评论
为什么被折叠?



