# 自制操作系统Antz(15)——实现启动界面

# AntzScript

🎓 The language executed in the Antz system.

> 本节不涉及OS底层内容，只是关于图片放大显示时效果处理的。

###### [Antz系统更新地址](https://www.cnblogs.com/LexMoon/category/1262287.html)

###### [Antz项目地址](https://github.com/CasterWx/AntzOS)

###### [AntzScript项目地址](https://github.com/CasterWx/AntzScript)


| 真机启动效果 |
| -------- |
| <img src="https://github.com/CasterWx/AntzOS/raw/master/screen/runShow.gif"> |

图片来源:[phodal/daily](https://github.com/phodal/daily)

(orz左上角是在处理原图时自己签的名)

为了节省镜像空间，我将图片从2000乘800左右图片压缩为108乘60的24色大小的图片，计算为RGB值之后也有近6400左右像素点。但是要将它写入显存，展现在用户眼中，效果表明是很差的，我们的分辨率为1080x768，数十倍于这张图片。

为了解决显示效果的问题，这里有两种解决方法。

 ---------

## 一. 像素点区域化

这个方法是我自己起的名字，大致意思也如标题所示，就是将一个本来应该显示在(x1,y1)位置的像素点区域化显示，将其RGB值覆盖在(x1,y1)至(x1+x,y1+y)的这片区域。这个方法实现起来非常简单，但是效果`极差`，最后显示出来的效果就好像是`我的世界`中的超大像素点效果。

图示大概如这样:

![123](https://www.cnblogs.com/images/cnblogs_com/LexMoon/1246510/o_12310.png)

附上简单实现。
```c
void to_show(){
    int i, x, y ;
    int k ; 
    k = 0  ;
    for (y = 0; y < 60; y++) {
        for (x = 0; x < 108; x++){
            // 在(x*10,y*13)至(x*10+10,y*13+13)这片区域填充RGB值bmp[k]
            print_image(x*10,y*13,x*10+10,y*13+13,bmp[k]);
            k++;
        }
    }
}
```

在虚拟机中效果如下。

![img](https://github.com/CasterWx/AntzOS/raw/master/screen/my.gif)

## 二. 双线性插值

在使用第一种粗略暴力的方式实现启动动画之后，第二天的数字图像处理课程中，听到老师讲matlab中的图片放大缩小函数的原理，了解了`双线性插值`这个算法，于是想到用这个方法来重新实现启动界面。

双线性插值的基本原理是，假设源图像大小为MxN，目标图像为AxB。那么两幅图像的边长比分别为：M/A和N/B。这两个比例值一般是浮点数。目标图像的第（i,j）个像素点（i行j列）可以通过边长比对应回源图像。其对应坐标为（i*m/a,j*n/b）。显然，这个对应坐标一般来说不是整数，而非整数的坐标是无法在图像这种离散数据上使用的。双线性插值通过寻找距离这个对应坐标最近的四个像素点，来计算该点的值（灰度值或者RGB值）。

其实可以理解为通过其周围的四个点，`中和`出这片区域中的其他点。

![2123](https://www.cnblogs.com/images/cnblogs_com/LexMoon/1246510/o_213123.png)

![s](../sreen/1.png)

我们想得到一张放大的图片，现在有`原图像`和`目标图像`。那么，有一个最基本的问题摆在我们面前：是遍历`原图像`呢，还是遍历`目标图像`呢？

在实践的过程中，通常都是遍历`目标图像`的。因为这样可以确保`目标图像`的每一个像素都是有值的。

就拿上图的例子来说，右图`目标图像`中的 [0,0] 点很顺利的找到了左图`原图像`中与自己对应的 [0,0] 点。然后 [0,1] 点就懵逼了，它应该找 [0,0.33]点吗？没有这个点啊。

插值这个方法，就是为了解决这个问题的。
