![如何从特定文本组成图像?](https://linux22.com/image/292073/%E5%A6%82%E4%BD%95%E4%BB%8E%E7%89%B9%E5%AE%9A%E6%96%87%E6%9C%AC%E7%BB%84%E6%88%90%E5%9B%BE%E5%83%8F%EF%BC%9F.png)
我喜欢玩 ASCII 艺术,正如你所知,有一些工具可以从图像生成 ASCII 艺术,其中 ASCII 由那些可以产生最佳图像的字符组成,如第一张图片所示:
通过眼睛,您需要具有大量白色的 ASCII 字符(例如点、逗号、连字符)来生成较亮的区域,以及具有大量黑色的字符(例如 M、$)来生成较暗的区域。
现在,我想要实现的是能够控制组成图像的人物。下图就是一个示例,其中的故事形成了一只乌鸦的形状。
但是这只乌鸦只是平的,没有眼睛那样的深度。我想把眼睛和乌鸦的例子结合起来。
是否可以通过对每个字符使用不同的灰色阴影或不同的大小来实现相同的效果?因此,对于较亮的区域,请使用浅灰色或小黑色字符,对于较暗的区域,请使用黑色和大字符。
这有意义吗?
是否可以使用 LaTeX 以自动化的方式实现?
答案1
这个答案需要 lualatex 和图像魔法或类似程序。您必须将彩色图片转换为,.ppm
将灰度图片转换为.pgm
,这非常容易处理。您可以使用以下命令保持纵横比:
convert -compress none -resize ___OutputWidth___ ___InputFile___ ___output___.ppm
convert -compress none -resize ___OutputWidth___ ___InputFile___ ___output___.pgm
警告:这是一个漫长的过程,处理较大的图像会花费大量时间。
代码如下:
文本文件
\documentclass{article}
\usepackage{luacode}
\usepackage{xcolor}
\usepackage{graphicx}
\directlua {require "asciiart"}
\newcommand\bwascii[1]{\directlua{bwascii("#1")}}
\newcommand\colorascii[1]{\directlua{colorascii("#1")}}
\newcommand\bwframe[1]{\vspace*{\fill}\bwascii{#1}\vspace*{\fill}\newpage}
\newcommand\colorframe[1]{\vspace*{\fill}\colorascii{#1}\vspace*{\fill}\newpage}
\begin{document}
\ttfamily\frenchspacing
\newlength{\correctem}\settowidth{\correctem}{M}%to set the size of the minipage
\newlength{\correctex}\settowidth{\correctex}{x}%to set the line height
\pagestyle{empty}\centering
\colorframe{lenna_128x128.ppm}
\colorframe{lisa_150x224.ppm}
\colorframe{knuth_192x227.ppm}
\bwframe{einstein_150x206.pgm}
\end{document}
asciiart.lua
colorascii = function ( picture )
-- read a picture in .ppm format
local file = io.open(picture, "r")
if file==nil then
tex.sprint("file not found")
return
end
local arr = {}
for line in file:lines() do
if line:sub(1,1)~="#" then--if line starts with # don't insert it
table.insert(arr,line);
end
end
file:close()
if arr[1]~="P3" then
tex.sprint("i don't like this file")
--TODO: implement moar ways to detect if the file is corrupt
return
end
local sizes = {}
for i in string.gmatch(arr[2],"%d+") do
table.insert(sizes,i)
end
local xsize = tonumber(sizes[1])
local ysize = tonumber(sizes[2])
table.remove(arr,1)--remove "P3"
table.remove(arr,1)--remove sizes
table.remove(arr,1)--remove maxval and assume no value is bigger than 255
colors = ""
for k,v in pairs(arr) do
colors = colors..v.." "
end
colors = string.gsub(colors, " +", " ")
--now all our picture is in a single string
rgb = {}
for i in string.gmatch(colors,"%d+ %d+ %d+") do
temp = {}
for j in string.gmatch(i, "%d+") do
table.insert(temp,j)
end
table.insert(rgb, temp)
end
tex.sprint("\\noindent\\resizebox{\\textwidth}{!}{")
tex.sprint("\\noindent\\begin{minipage}{"..xsize.."\\correctem}\\setlength\\baselineskip{1\\correctex}\\setlength\\lineskip{0pt}\\setlength\\prevdepth{0pt}")
for i = 1,#rgb do
tex.sprint("\\definecolor{mycolor}{RGB}{"..rgb[i][1]..","..rgb[i][2]..","..rgb[i][3].."}\\textcolor{mycolor}x\\hspace{0pt}")
end
tex.sprint("\\end{minipage}}")
end
valchar = function (val)--takes an integer from 0 to 255 and returns a character
val = tonumber(val)
valuetable = {"\\$","B","Q","Y","v","~","."," "}--return darker characters for darker values
return valuetable[math.floor(val/32)+1]
end
bwascii = function ( picture )
local file = io.open(picture, "r")
if file==nil then
tex.sprint("file not found")
return
end
local arr = {}
for line in file:lines() do
if line:sub(1,1)~="#" then
table.insert(arr,line);
end
end
file:close()
if arr[1]~="P2" then
tex.sprint("i don't like this file")
return
end
local sizes = {}
for i in string.gmatch(arr[2],"%d+") do
table.insert(sizes,i)
end
local xsize = tonumber(sizes[1])
local ysize = tonumber(sizes[2])
table.remove(arr,1)
table.remove(arr,1)
table.remove(arr,1)
greys = ""
for k,v in pairs(arr) do
greys = greys..v.." "
end
greys = string.gsub(greys, " +", " ")
value = {}
for i in string.gmatch(greys,"%d+") do
table.insert(value, i)
end
tex.sprint("\\noindent\\resizebox{\\textwidth}{!}{")
tex.sprint("\\noindent\\begin{minipage}{"..xsize.."\\correctem}\\setlength\\baselineskip{1\\correctex}\\setlength\\lineskip{0pt}\\setlength\\prevdepth{0pt}\\leavevmode")
for i = 1,#value do
tex.sprint("\\smash{"..valchar(value[i]).."}\\hspace{0pt}")
end
tex.sprint("\\end{minipage}}")
end
示例输出(下载pdf放大):
警告:对于较大的图像,可能需要比您预期更长的时间。
如果您不想安装 imagemagick,请转换为 .ppm/.pgm:莱娜,丽莎,克努特,爱因斯坦。
虽然这可能不是确切地你想要的(乌鸦,改变字体大小和粗细……),这是一个开始。据我所知,没有其他方法可以用 latex 生成 ascii 艺术。