缩小位图字体的算法

发布于 2024-10-02 06:00:40 字数 466 浏览 0 评论 0原文

这是此问题的后续问题。

我正在开发一个低级 C 应用程序,我必须在其中绘制文本。我决定将我想要使用的字体存储为数组(黑色和白色,每个字符 128x256,也许),然后我用某种算法将其缩小到我需要的大小(作为灰度,所以我可以有一些粗略的)字体平滑)。

注意:这是一个玩具项目,请忽略诸如是否在运行时进行计算之类的内容。

问题是,哪种算法?

我查了2xSaI,但它相当复杂。我想要一些我可以阅读描述并自己编写代码的东西(我是初学者,并且已经用 C/C++ 编码了不到一年)。

有建议吗?

感谢您抽出时间!

编辑:请注意,输入是黑白的,输出应该是平滑的灰度

This is a follow-up to this question.

I am working on a low level C app where I have to draw text. I have decided to store the font I want to use as an array (black and white, each char 128x256, perhaps), then I'd downscale it to the sizes I need with some algorithm (as grayscale, so I can have some crude font smoothing).

Note: this is a toy project, please disregard stuff like doing calculations at runtime or not.

Question is, which algorithm?

I looked up 2xSaI, but it's rather complicated. I'd like something I can read the description for and work out the code myself (I am a beginner and have been coding in C/C++ for just under a year).

Suggestions, anyone?

Thanks for your time!

Edit: Please note, the input is B&W, the output should be smoothed grayscale

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

小巷里的女流氓 2024-10-09 06:00:40

找出源图像中与目标像素对应的矩形。例如,如果源图像为 50x100,目标为 20x40,则目标中的左上角像素对应于源图像中从 (0,0) 到 (2.2,2.2) 的矩形。现在,对这些像素进行面积平均:

  • 面积为 2.2 * 2.2 = 4.84。您会将结果缩放 1/4.84。
  • (0,0)、(0,1)、(1,0) 和 (1,1) 处的像素各占 1 个单位。
  • (0,2)、(1,2)、(2,0) 和 (2,1) 处的像素各占 0.2 个单位(因为矩形仅覆盖其中的 20%)。
  • (2,2) 处的像素权重为 0.04(因为矩形只覆盖了它的 4%)。
  • 总重量当然是4*1 + 4*0.2 + 0.04 = 4.84。

这很容易,因为您从源像素和目标像素开始,在图像边缘均匀排列。一般来说,滑动矩形的所有 4 个边/4 个角都会被部分覆盖。

除了用于缩小尺寸的面积平均之外,不要费心使用其他算法。其中大多数都是明显错误的(它们会导致可怕的混叠,至少系数小于 1/2),而那些并非完全错误的方案实施起来可能会比较困难,而且可能不会给你更好的结果。

Figure out the rectangle in the source image that will correspond to a destination pixel. For example if your source image is 50x100 and your destination is 20x40, the upper left pixel in the destination corresponds to the rectangle from (0,0) to (2.2,2.2) in the source image. Now, do an area-average over those pixels:

  • Area is 2.2 * 2.2 = 4.84. You'll scale the result by 1/4.84.
  • Pixels at (0,0), (0,1), (1,0), and (1,1) each weigh in at 1 unit.
  • Pixels at (0,2), (1,2), (2,0), and (2,1) each weigh in at 0.2 unit (because the rectangle only covers 20% of them).
  • The pixel at (2,2) weighs in at 0.04 (because the rectangle only covers 4% of it).
  • The total weight is of course 4*1 + 4*0.2 + 0.04 = 4.84.

This one was easy because you started with source and destination pixels lined up evenly at the edge of the image. In general, you'll have partial coverage at all 4 sides/4 corners of the sliding rectangle.

Don't bother with algorithms other than area-averaging for downscaling. Most of them are plain wrong (they result in horrible aliasing, at least with a factor smaller than 1/2) and the ones that aren't plain wrong are a good bit more painful to implement and probably won't give you better results.

莫相离 2024-10-09 06:00:40

假设您的图像是 N*M 黑白位图。为简单起见,当允许值为 01 时,我们将其视为 char Letter[N][M]。现在考虑您要将其缩小为 unsigned char letter[n][m]。这意味着 letter 中的每个灰度像素将被计算为大位图中白色像素的数量:

char Letter[N][M];
unsigned char letter[n][m];
int rect_sz_X = N / n; // the size of rectangle that will map to a single pixel
int rect_sz_Y = M / m; // in the downscaled image
int i, j, x, y;
for (i = 0; i < n; i++) for (j = 0; j < m; j++){
    int sum = 0;
    for (x = 0; x < rect_sz_X; x++) for (y = 0; y < rect_sz_Y; y++)
        sum += Letter[i*rect_sz_X + x][j*rect_sz_Y + y];
    letter[n][m] = ( sum * 255) / (rect_sz_X * rect_sz_Y);
};

请注意,创建像素的矩形可能会重叠(如果大小不可整除)。原始位图越大越好。

Consider that your image is a N*M BW bitmap. For simplicity we'll consider it char Letter[N][M], when allowable values are 0 and 1. Now consider that you want to downscale it to the unsigned char letter[n][m]. This will mean that each greyscale pixel from letter will be computed as number of white pixels in the big bitmap:

char Letter[N][M];
unsigned char letter[n][m];
int rect_sz_X = N / n; // the size of rectangle that will map to a single pixel
int rect_sz_Y = M / m; // in the downscaled image
int i, j, x, y;
for (i = 0; i < n; i++) for (j = 0; j < m; j++){
    int sum = 0;
    for (x = 0; x < rect_sz_X; x++) for (y = 0; y < rect_sz_Y; y++)
        sum += Letter[i*rect_sz_X + x][j*rect_sz_Y + y];
    letter[n][m] = ( sum * 255) / (rect_sz_X * rect_sz_Y);
};

Note that the rectangles that creates pixels could overlap (in case when sizes aren't divisible). The larger is your original bitmap, the better.

幼儿园老大 2024-10-09 06:00:40

缩放位图字体与缩放任何其他位图具有相同的问题。您所追求的一般算法类别是插值。有很多方法可以做到这一点 - 一般来说,结果在视觉上越准确,算法就越复杂。您可以首先查看(按复杂性递增的顺序):

Scaling a bitmapped font is the same problem as scaling any other bitmap. The general class of algorithm that you're after is interpolation. There's quite a few ways to do this - in general, the more visually accurate the result, the more complicated the algorithm. You could start by looking at (in increasing order of complexity):

薄荷梦 2024-10-09 06:00:40

这很简单。如果您拥有的只是位图字体而不是轮廓字体,那么您在选择抗锯齿像素颜色时的选择非常有限。例如,如果位图字体点大小恰好是所需显示点大小的四倍,那么您只能获得 16 个不同的选择。 4x4 映射矩形中“点亮”像素的数量。

处理分数映射是一项编程练习,但不能提高质量。

It's pretty simple. If all you've got is a bitmapped font instead of an outline font then you have very limited choices in picking an anti-aliasing pixel color. For example, if the bitmapped font point size is exactly four times as large as the desired display point size then you can only ever get 16 distinct choices. The number of 'lit' pixels in the 4x4 mapping rectangle.

Having to deal with fractional mapping is a programming exercise but not one that improves the quality.

乖不如嘢 2024-10-09 06:00:40

如果将缩小尺寸限制为 2 的倍数(50%、25%、12.5% 等)是可以接受的,那么一个非常简单且相当好的算法是将每个缩小尺寸的像素创建为所有源像素的多数投票。例如,在 50% 时,由四个像素组成的正方形形成一个缩小的像素:如果其中零个或其中一个打开,则输出关闭;如果三个或四个打开,则输出打开。艺术案例(两个像素打开),要么始终选择打开或关闭,要么查看其他周围的像素进行平局。

If it is acceptable to constrain the downscaling to multiples of 2 (50%, 25%, 12.5%, etc.), then a very simple and fairly good algorithm is to create each downscaled pixel as the majority vote of all the source pixels. For example, at 50%, a square of four pixels are forming the one downscaled pixel: if zero or one of them is on, then the output is off; if three or four are on, then the output is on. The artistic case (for two pixels on), either always choose on or off, or look at other surrounding pixels for tiebreaking.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文