javascript - 从任意字符串生成图像

标签 javascript image-processing dynamic-image-generation

我见过很多图像到 ascii 艺术转换器,但我需要的是稍微复杂一些。我需要能够使用一组任意长度的预定义字符串作为我的马赛克图 block ,而不是从 ascii 字符创建的马赛克图像。

我已经进行了大量的谷歌搜索,但我什至不确定如何构建我的查询?有这样的东西存在吗?如果它不会在其图像生成中使用重复项,还有奖励。

最佳答案

不太适合 Stack Overflow,但仍然是一个有趣的项目。所以我试了一下,想找点乐子,看看我能走多远。

我认为归结为:

  1. 计算一组ASCII字符的灰度值;
  2. 计算每个字符串的“最佳匹配”;
  3. 重复 2. 直到完成。

我不认为“没有重复”是可行的,除非你有非常小的图像和大量的候选字符串。这是我想出的,使用我的头像和我当前的徽章作为字符串列表。 (我排除了我的“c”徽章;不知何故我的程序决定它是大补丁的“最适合”,这不是很有吸引力。注意:不要包含 1 个字符的字符串。)

QuorumQuorumAutobiographerQuorumQuorumQuorumJongwareQuorumQuorumQuorumQuorumQuor
umQuorumQuorumAutobiographerQuorumQuorumSupporterQuorumQuorumProofreaderQuorumQu
orumQuorumAutobiographerQuorumQuorumQuorumQuorumQuorumQuorumAutobiographerQuorum
QuorumQuorumAutobiographerQuorumQuorumQuorumQuorumQuorumQuorumAutobiographerQuor
umQuorumQuorumAutobiographerQuorumQuorumQuorumAutobiographerQuorumMortarboardQuo
rumQuorumAutobiographerQuorumQuorumQuorumQuorumAutobiographerQuorumMortarboardQu
orumQuorumAutobiographerQuorumQuorumQuorumQuorumJongwareQuorumQuorumCommentatorQ
uorumQuorumAutobiographerQuorumQuorumQuorumQuorumQuorumQuorumQuorumAutobiographe
rQuorumQuorumAutobiographerQuorumQuorumProofreaderJongwareQuorumQuorumQuorumQuor
umQuorumQuorumMortarboardJongwareQuorumProofreaderCommentatorSuffrageQuorumQuoru
mQuorumQuorumJongwareQuorumAutobiographerSuffrageCommentatorCaucusCriticCleanupQ
uorumQuorumMortarboardAutobiographerCommentatorQuorumConstituentCriticCriticQuor
umQuorumQuorumQuorumAutobiographerJongwareCleanupSupporterInvestorCriticCleanupQ
uorumQuorumQuorumQuorumAutobiographerFanaticCleanupFanaticInvestorCriticCleanupQ
uorumQuorumQuorumQuorumAutobiographerCriticInformedSupporterCriticCriticInformed
QuorumQuorumQuorumQuorumAutobiographerCriticQuorumSupporterInvestorFanaticQuorum
QuorumQuorumQuorumQuorumAutobiographerCriticCleanupCommentatorQuorumDeputyQuorum
QuorumQuorumQuorumQuorumAutobiographerCriticInvestorCaucusInformedDeputyQuorumQu
orumQuorumQuorumQuorumQuorumCommentatorCriticCriticCitizen PatrolQuorumQuorumQuo
rumQuorumQuorumQuorumQuorumAutobiographerCriticCriticCitizen PatrolQuorumQuorumQ
uorumQuorumQuorumQuorumQuorumAutobiographerCriticCriticCitizen PatrolStewardQuor
umQuorumQuorumQuorumQuorumAutobiographerConstituentCitizen PatrolCaucusQuorumQuo
rumQuorumQuorumQuorumQuorumAutobiographerInvestorCriticConstituentQuorumQuorumQu
orumQuorumQuorumQuorumQuorumCommentatorConstituentCleanupCaucusCleanupQuorumQuor
umQuorumQuorumQuorumQuorumAutobiographerInvestorCleanupSupporterInformedQuorumQu
orumQuorumQuorumAutobiographerCommentatorCriticInformedJongwareJongwareQuorumQuo
rumQuorumQuorumAutobiographerCommentatorCriticInvestorJongwareJongwareQuorumQuor
umQuorumQuorumAutobiographerFanaticInvestorCriticInformedCleanupQuorumQuorumQuor
umQuorumQuorumQuorumDeputySupporterInvestorConstituentCaucusQuorumQuorumQuorumQu
orumQuorumQuorumAutobiographerCriticInvestorCriticSupporterQuorumQuorumQuorumQuo
rumQuorumQuorumQuorumAutobiographerInvestorInvestorCleanupQuorumQuorumQuorumQuor
umQuorumQuorumQuorumQuorumCommentatorInvestorInvestorQuorumQuorumQuorumQuorumQuo
rumQuorumQuorumQuorumQuorumCommentatorInvestorInvestorQuorumQuorumQuorumQuorumQu
orumQuorumQuorumQuorumQuorumCommentatorInvestorCleanupStewardQuorumQuorumQuorumQ
uorumQuorumQuorumQuorumQuorumCommentatorInvestorJongwareQuorumQuorumQuorumQuorum
QuorumQuorumQuorumQuorumQuorumAutobiographerCleanupQuorumQuorumQuorumQuorumQuoru
mQuorumQuorumQuorumQuorumQuorumAutobiographerSuffrageQuorumQuorumQuorumQuorumQuo
rumQuorumQuorumQuorumQuorumQuorumAutobiographerDeputyQuorumQuorumQuorumQuorumQuo
rumQuorumQuorumQuorumQuorumQuorumQuorumAutobiographerQuorumQuorumQuorumQuorumQuo
rumQuorumQuorumQuorumQuorumQuorumQuorumQuorumQuorumQuorumQuorumQuorumQuorumQuoru

你得眯着眼睛看;小尺寸时它看起来像这样:

textvatar(tm)

这是我创建它的方式。

第 1 步:找到合适的图像;

第二步:转灰度;

第 3 步:将灰色转换为极值。这一步是为了确保输入范围(灰度值)使用 0 到 255 的完整范围。

第 4 步:调整图像大小以使其最适合。我选择了 80x40,并故意将图像压缩了一半。这是因为“文本”通常高于它的宽度。不同的字体需要不同的纵横比! 80 是每行的字符数,40 是总行数。

我在上述步骤中使用了 Photoshop,只是因为我不想为其编写代码。这并不难,只要您可以访问原始图像数据,但它需要大量工作而且并不有趣。

中间步骤,放大 400%,以便您可以看到像素:

deformed grayscale image

第 5 步:找到等宽位图字体。我在网上的某个地方找到了一个不错的 8x8 的。也许更大的字体可能效果更好,但只是非常小的,因为限制因素是您的字符串,而不是字体。

第 6 步:计算每个 ASCII 字符的“灰色”值。这是黑色像素的数量除以像素总数。为了更好地传播,我将每个字符的结果除以找到的最大值,因此最低值为 0(对于空格),最高值为 1(恰好用于 M,但这取决于字体)。然后我将这些值乘以 255,因此它模拟了灰度值。最后,由于这些值与灰度图像中的值相反,我将它们替换为 255-value

在此期间,我做了很多测试以确保我最初的想法仍然正确。这是我使用简单的灰度到字符转换的测试图像转储:

0MMMMMM00000000000RDRRDDDDDDDDDDDDDDR#@RRRRR#00000RRR@RRRRR@RR@RRRRD&44&#00#0000
MMMMMM000000000000RDRDDDDDDDDDDDDDDDR0####0R&&&&&&DR@RRR@#########RRDDD4@0000000
MMM000#00000000000RDRRDDDDDDDDDDD&&&R00#000@&DR@####RR@#0000000##0#RD4PP&R@00000
M000#0000000000000RDDDDDDDDDDD&D&&D&R###0000@#0000#@@##@@@@@##000000R&2FPP4R#000
00###0000000000000RDDDDDDDDDDDDDD&&&D0000#@##@##00##@RDD&DRRRR#00000@R4FFP4PD@00
00#000000000000000RDDDDDDDDDD&D&D&&&DRRRRDR@@@##00#R&4&44DDDRRR#0000##R&FPP4PRR@
00##00#00000000000RDDDDDDDDDDD&&&&&&RDRRRRRRRR##@@RR&F4&RDDRR@@#0000000#&44&&4FD
000000000000000000DDDDDDD&&&DD&&&D&&R##@RRRRRRRRRRRRD&DRD&44DD&RR@#00000RDDRR4F4
000000000000000000RDDDDDDDRRDRDDD&DR@###@R&4&4444PP4DRRR&P22FF2FP&DRRRRRRRR@R4FD
000000000000000000RRRRRRR@00@@R&&DRRRRRR@&P2$33*33*4RRRDP23$*33$$**333*$$2D#@4DR
000000000000000000RRRRRRR@0000#DDRRRRRD&D4*$$%%ff3F&DRRR2$1%$$%11ff%ll1l;'IRDF&R
000000000000000000RRR@#0#00000R4444DRRRR&3llf33$32PDRR&3Ii(i%fIlI1Il!ii/' .FF4DR
0000000#0000000000#@@#0MM0M00#RP22*24DR4$l!!!I%*P4DDP31i===/lf1Illi((ii=;..*F4RR
000000000000000000#@@##0M00000@F*$%*2PFflilllI1f3*2PF3fIi/=(lf$fIi/======;iF&P4R
000000000000000000##@##00000000&3f$2F2*1i!ll1$2P4RD&4P*$$%!ii!I!ii/=/=;;;(*&R4FR
000000000000000000#####00000000D%I3$$fflil!l1$3%3&RD2PP*$%1ll!lI1%f$3fI="1RRRRDR
000000000000000000#####00000000Rf1f%II1IIl!l!!1%ff$*FFFF*%((lf**F4&D&PPFf2RRRRRR
00000000000000000M#####0000000003!i11II11l!!!(ilIIl1f$f%I="=1FP4&@#R&DP22&RRR@#@
0000000000000000000###0000000000#$i/iIIIl!!i=;"";===;""""";i12FFP4&4*4&*FRRRR@@R
000000000000000000M000000000000000R4FF1l!i(=;"''"""""'...';/i$3$f$$33$$$4DRRRRRR
000000000000000000000000000M00000000@21l(/ii/=;;=ilI;"'...'=;I%11f$$$ffP@@RR@R#0
000000000000000000000000000M00000000&11!=/li(i!I%%Ii;... .";"!I!!I1ff$*R0#@#0000
000000000000000000000000M0000M000000$lli=//=/i!lIi/l%I/""=//'=Iiiil%f$PR@#@00000
000000000000000000000000M0M0M00000MRl!!!/=;;/l%fl!lI%3233$ff%11II%%f*2PP@##00000
00000000000000000M000000M0MM00000003=illl!!iI%11%%f%f$32FF22$1%ff$f2DD4PR0000000
00000000000000000M00M0#RRRRRRRRRRRPi/(lllI1I(=;=iI$2222FPFFP*$fff%FRR2322&R00000
00000000000000000MM00#RRD&&&&&444*l/(i!ll!i!==/(il%$33*2FFF23$ff*4DDDF33*22&0000
0000000000000000000000@R@@@@@#&f!((/i!!!lI!i=;;/!l1f32*3$$$ff$2&RR@###@##00##000
0000000000000000#RRRR@@4F4R0R3!////(iii!!l%Ii=;"=l%f$333$ff%$4############00000#
0000000000000000000000#@@@#0Di/ii(=/(i!!!lI%%1!(iI%$**$$fffF@0000000000000000000
00000000000000000000000000000R3l((/((ii!lll!I%$3$f$$$$$3$f20M0000000000000000000
000000000000000000000000000000#2l///((!!l!!i!!1%f%f$3$f%%fR000000000000000000000
00000000000000#00000000000000000&l//(i!llllII1%%%1I1ff1I1&000000000000000000#00#
M00000000000000000000000000000000R3l!!llII111%%%%%%f$$f%2000000000000000000RR00#
0000#000000000000000000000000000000R*%1II111%%ffff$33fffR000000000000000000##00#
0####000000000000000000000000000000M0RF3ff$$$fff$$33$ff&00000000000#000000##000R
#00000000#00000000000000000000000000000R4FFFF22*****3fF00000000000000000000000@&
00###000000000000000000000000000000000000@RRDD&&&4P*34#00000000000000000000000#R
00000####000000000000000000000000000000000000##@RRDDR00000000000000M0000000000##
00000000#000000000000000000000000000000000000000000000000000000000000000000000##

这类似于您的平均图像到 ASCII 艺术转换器的输出。

第 7 步:找到要使用的字符串列表。

第 8 步:从左上角开始,测试每个字符串对图像的覆盖率。打印出最合适的,将位置增加这个字符串的长度,重复直到完成。 (如果您不想重复,此时您可以从您的池中删除该字符串。)

第 9 步:获利!


对于覆盖率测试,我对每个字符/像素使用了 (source - dest)² 的总和除以字符串的长度:lower = better——两者之间的最小差异字符串和目的地。

我在这里没有考虑漂亮的行尾。如果一个词正好填满一行,我尝试给予负奖励,但输出的差异很小。它可能仍然适用于更大的字符串集。

一个可能的改进是测试一个字符串的序列,即,而不是这里的贪婪方法,使用动态编程方法,就像 Donald Knuth 设计来决定单词换行文本中的最佳中断.

关于javascript - 从任意字符串生成图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26347985/

相关文章:

java - 红框交通标志的颜色阈值

c# - 从 XAML View 生成图像

javascript - 如何使用php和ajax强制下载图像而不显示它

javascript - 如何将 Node js 包添加到 Meteor 应用程序中?

javascript - 放大和缩小在 chrome 中不起作用

javascript - d3.js 中条形图之间的关联距离

javascript - Spring MVC中如何实现AJAX?

php - 如何使用 php 上传到静态内容服务器?

python - 如何检查点云/3d 对象上的某些坐标?