也许是受到很久以前看到的这玩意儿的原因:The Shapes of CSS

现在开脑洞写了个自动转换,顺便支持了动画……嗯,纯 CSS (:з」∠)

主要步骤就是用 Python 读图片,然后把像素全转写成 CSS 的 box-shadow ,最后构建一个完整的 HTML 文件输出。

然后用浏览器打开生成的 HTML 文件,就直接看到图片了,如果输入是一个文件夹的话,就以文件夹里面的图片为帧生成一个带动画的 HTML。

最新的版本就在这儿了: img2html

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3.  
  4. ## @package img2html
  5. # Usage : img2html.py file1|dir1 [file2|dir2 ...]
  6. # Description : generate html uses box-shadow to show picture
  7. # or a html to show your image sequence in a folder as css animation
  8. # Dependencies : Python Image Library, Python 3
  9. # Note : Take care of the Super-High-Energy output ( >﹏<。)
  10. # Date : 2014-12-19
  11. # Author : frantic1048
  12.  
  13. import sys
  14. import os
  15. from PIL import Image
  16. from string import Template
  17.  
  18. class UnknownColorMode(Exception): pass
  19.  
  20. ## @var tHTML template for constructing entire html document
  21. tHTML = Template('''
  22. <!doctype html>
  23. <html lang="en">
  24. <head>
  25. <meta charset="UTF-8">
  26. <title>~ ${name} ~</title>
  27. </head>
  28. <body>
  29. <style type="text/css">${css}</style>
  30. <div id="image_kun"></div>
  31. </body>
  32. </html>''')
  33.  
  34. ## @var tCSSStatic template for constructing static image's css code
  35. tCSSStatic = Template('''
  36. @charset "utf-8";
  37. body{
  38. display:flex;
  39. justify-content:center;
  40. align-items:center;
  41. }
  42. #image_kun{
  43. height: ${height}px;
  44. width: ${width}px;
  45. position:relative;
  46. }
  47. #image_kun::after{
  48. position:absolute;
  49. height:1px;
  50. width:1px;
  51. background:${firstPixel};
  52. margin:0;
  53. padding:0;
  54. content:"\\200B";/*ZWS*/
  55. box-shadow:
  56. ${boxshadow};
  57. }
  58. ''')
  59.  
  60. ## @var tCSSAnimation template for constructing image sequence's css animation code
  61. tCSSAnimation = Template('''
  62. @charset "utf-8";
  63. body{
  64. display:flex;
  65. justify-content:center;
  66. align-items:center;
  67. }
  68. #image_kun{
  69. height: ${height}px;
  70. width: ${width}px;
  71. position:relative;
  72. }
  73. #image_kun::after{
  74. position:absolute;
  75. height:1px;
  76. width:1px;
  77. background:transparent;
  78. margin:0;
  79. padding:0;
  80. content:"\\200B";/*ZWS*/
  81. animation:ayaya ${animationLength} step-end infinite alternate;
  82. }
  83. ${animationKeyFrames}
  84. ''')
  85.  
  86. ## @var tCSSKeyframes template entire CSS keyframes rule
  87. tCSSKeyframes = Template('@keyframes ayaya {${keyframes}}')
  88.  
  89. ## @var tCSSKeyframe template for a single CSS keyframe
  90. tCSSKeyframe = Template('${percentage}% {${keyframeRule}}\n')
  91.  
  92. ## @var tCSSKeyframeRule template for a single CSS keyframe inner rule
  93. tCSSKeyframeRule = Template('background:${firstPixel};box-shadow:${boxshadow};')
  94.  
  95. ## ensure no trailiing slash in directory name
  96. def toRegularDirName(dirName):
  97. if (os.path.split(dirName)[-1] == ''):
  98. return os.path.split(dirName)[0]
  99. else:
  100. return dirName
  101.  
  102. ## write str to a file,named as <exportFileName>.html
  103. def toFile (str,exportFileName):
  104. with open (exportFileName,'w') as html:
  105. html.write(str)
  106.  
  107. ## construct HEX Color value for a pixel
  108. # @param pixel a RGB mode pixel object to be converted
  109. # @return CSS hex format color value
  110. def toHexColor (pixel):
  111. return '#{0:02x}{1:02x}{2:02x}'.format(*pixel[:])
  112.  
  113. ## construct RGBA Color value for a pixel
  114. # @param pixel a RGBA mode pixle object to be comverted
  115. # @return CSS rgba format color value
  116. def toRGBAColor (pixel):
  117. return 'rgba({0},{1},{2},{3})'.format(*pixel[:])
  118.  
  119. def toCSSColor (pixel, mode):
  120. if (mode == 'RGB'):
  121. return toHexColor(pixel)
  122. elif (mode == 'RGBA'):
  123. return toRGBAColor(pixel)
  124. else:
  125. raise UnknownColorMode
  126.  
  127. ## construct single box-shadow param
  128. # @param color valid CSS color
  129. def toBoxShadowParam (x, y, color):
  130. return format('%spx %spx 0 %s'%(x, y, color))
  131.  
  132. ## process single image file to html
  133. # @param fileName input file's name
  134. # @param export output callback(doc, exportFileName):
  135. # doc : generated html string
  136. # exportFileName : output filename
  137. def mipaStatic(fileName,export=''):
  138. with Image.open(fileName) as im:
  139. ## what called magic
  140. boxshadow = ''
  141.  
  142. ## file name as sysname
  143. exportFileName = fileName+'.html'
  144. title = os.path.split(fileName)[-1]
  145.  
  146. ## image size
  147. width, height = im.size[0], im.size[1]
  148.  
  149. #ensure RGB(A) mode
  150. if (im.mode != 'RGBA' or im.mode != 'RGB'):
  151. im.convert('RGB')
  152.  
  153. firstPixel = toCSSColor(im.getpixel((0,0)), im.mode)
  154. for y in range(0, height):
  155. for x in range(0, width):
  156. color = toCSSColor(im.getpixel((x, y)), im.mode)
  157. #link magic
  158. boxshadow += toBoxShadowParam(x, y, color)
  159.  
  160. #add a spliter if not the end
  161. if (not (y == height-1 and x == width-1)):
  162. #keep a '\n' for text editor ˊ_>ˋ
  163. boxshadow += ',' + '\n'
  164.  
  165. doc = tHTML.substitute(name = title, css = tCSSStatic.substitute(width = width, height = height, boxshadow = boxshadow, firstPixel=firstPixel))
  166. if (export==''):
  167. print(doc)
  168. else:
  169. export(doc, exportFileName)
  170.  
  171. ## process a image folder
  172. # files in folder will processed to an animated html
  173. # process order is filename asend
  174. # @param dirName input file's name
  175. # @param export output callback, call with generated html as a string argument
  176. def mipaAnimation(dirName,export=''):
  177. dirName = toRegularDirName(dirName)
  178. title = os.path.basename(dirName)
  179. exportFileName = title + '.html'
  180.  
  181. files = os.listdir(dirName)
  182. files.sort()
  183.  
  184. FPS = 24
  185. mode = ''
  186. width, height = 0, 0
  187. frameCount = 0
  188. keyframeRules = []
  189. keyframe = ''
  190.  
  191. for f in files:
  192. try:
  193. with Image.open(os.path.join(dirName, f)) as im:
  194.  
  195. if (export!=''):print('processing file --> ' + f)
  196.  
  197. frameCount+=1
  198.  
  199. #ensure RGB(A) mode
  200. if (im.mode != 'RGBA' or im.mode != 'RGB'):
  201. im.convert('RGB');
  202.  
  203. #collect animation info
  204. if (width == 0) : width, height = im.size[0], im.size[1]
  205. if (mode == '') : mode = im.mode
  206.  
  207. firstPixel = toCSSColor(im.getpixel((0,0)), mode)
  208. boxshadow = ''
  209. for y in range(0, height):
  210. for x in range(0, width):
  211. color = toCSSColor(im.getpixel((x, y)), mode)
  212. #link magic
  213. boxshadow += toBoxShadowParam(x, y, color)
  214.  
  215. #add a spliter if not the end
  216. if (not (y == height-1 and x == width-1)):
  217. #keep a '\n' for text editor ˊ_>ˋ
  218. boxshadow += ',' + '\n'
  219. keyframeRules.append(tCSSKeyframeRule.substitute(firstPixel=firstPixel,boxshadow=boxshadow))
  220. except:
  221. pass
  222.  
  223. percentUnit= 100/frameCount
  224. for i in range(0,frameCount):
  225. if (i == frameCount - 1):
  226. pc = ''
  227. elif (i == 0):
  228. pc = ''
  229. else:
  230. pc = str(percentUnit * i)
  231. keyframe += tCSSKeyframe.substitute(percentage = pc, keyframeRule = keyframeRules[i])
  232.  
  233. if (export!=''):print('generating document...')
  234. doc = tHTML.substitute(name = title, css = tCSSAnimation.substitute(animationLength = str((1000 / FPS) * frameCount) + 'ms',
  235. animationKeyFrames = tCSSKeyframes.substitute(keyframes = keyframe),
  236. height = height,
  237. width = width))
  238. #output
  239. if (export==''):
  240. print(doc)
  241. else:
  242. print('Start exporting...')
  243. export(doc, exportFileName)
  244. print('Finished exporting !\nenjoy with your magical ' + exportFileName + ' _(:з」∠)_')
  245.  
  246. for path in sys.argv[1:]:
  247. if os.path.isfile(path):
  248. ##export to stdout
  249. #mipaStatic(path)
  250.  
  251. ##export to autonamed file
  252. mipaStatic(path,toFile)
  253. elif os.path.isdir(path):
  254. #mipaAnimation(path)
  255. mipaAnimation(path,toFile)

「脑洞」图片转HTML(支持动画)的更多相关文章

  1. 《Offer一箩筐》一份高质量「简历」撰写指南,望打扰!!

    「MoreThanJava」 宣扬的是 「学习,不止 CODE」. 如果觉得 「不错」 的朋友,欢迎 「关注 + 留言 + 分享」,文末有完整的获取链接,您的支持是我前进的最大的动力! Hi~ 这里是 ...

  2. SpringBoot图文教程10—模板导出|百万数据Excel导出|图片导出「easypoi」

    有天上飞的概念,就要有落地的实现 概念十遍不如代码一遍,朋友,希望你把文中所有的代码案例都敲一遍 先赞后看,养成习惯 SpringBoot 图文教程系列文章目录 SpringBoot图文教程1「概念+ ...

  3. iOS图案锁,支持动画、图片、绘图

    最近忙着搭建一个聊天用的框架,过几天应该会整理写出来吧,原理不难,但是实现后会省很多事.好久没写博客,周末心血来潮写了个图案锁,这东西没什么技术含量,网上一堆,这次这个图案锁顺便联系了怎么打包使用.a ...

  4. loj #2037. 「SHOI2015」脑洞治疗仪

    #2037. 「SHOI2015」脑洞治疗仪   题目描述 曾经发明了自动刷题机的发明家 SHTSC 又公开了他的新发明:脑洞治疗仪——一种可以治疗他因为发明而日益增大的脑洞的神秘装置. 为了简单起见 ...

  5. 「MoreThanJava」Java发展史及起航新世界

    「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...

  6. 一个「学渣」从零开始的Web前端自学之路

    从 13 年专科毕业开始,一路跌跌撞撞走了很多弯路,做过餐厅服务员,进过工厂干过流水线,做过客服,干过电话销售可以说经历相当的“丰富”. 最后的机缘巧合下,走上了前端开发之路,作为一个非计算机专业且低 ...

  7. Android逆向之旅---静态方式分析破解视频编辑应用「Vue」水印问题

    一.故事背景 现在很多人都喜欢玩文艺,特别是我身边的UI们,拍照一分钟修图半小时.就是为了能够在朋友圈显得逼格高,不过的确是挺好看的,修图的软件太多了就不多说了,而且一般都没有水印啥的.相比较短视频有 ...

  8. 零元学Expression Blend 4 - Chapter 18 用实例了解互动控制项「CheckBox」II

    原文:零元学Expression Blend 4 - Chapter 18 用实例了解互动控制项「CheckBox」II 延续上一章的CheckBox教学,本章将以实作继续延伸更灵活的运用CheckB ...

  9. 零元学Expression Blend 4 - Chapter 17 用实例了解互动控制项「CheckBox」I

    原文:零元学Expression Blend 4 - Chapter 17 用实例了解互动控制项「CheckBox」I 本章将教大家如何运用CheckBox做实作上的变化:教你如何把CheckBox变 ...

随机推荐

  1. 数据库的NULL值讨论

    有许多关于数据库设计中NULL的讨论,我个人的设计习惯是,不使用NULL值. 我所设计所有表都是Not Null的字段的,尤其是我主要做数据仓库的表设计.刚开始使用数据库时,就栽了一次.一个Group ...

  2. java ppt课后作业

    1 .仔细阅读示例: EnumTest.java,运行它,分析运行结果? 枚举类型是引用类型,枚举不属于原始数据类型,它的每个具体值都引用一个特定的对象.相同的值则引用同一个对象.可以使用“==”和e ...

  3. JS,复习

    按钮,倒数五秒操作练习 <input type="button" id="btn1" value="按钮(5)" disable=&q ...

  4. 44、NLP的其他分词功能测试

    1. 命名实体识别功能测试 @Test public void testNer(){ if (NER.create("ltp_data/ner.model")<0) { Sy ...

  5. 36、重新复习html和css之二

    (1)由于公司是意大利的网段, (2)而且公司的电脑是保密的, (3)文件发不出去, (4)U盘插不进去. (5)而且我们组的项目整体上已经开发完毕,客户暂时没有什么大的需求, 所以如果我不把这些技术 ...

  6. css响应有media,js响应有这种

    比如,我不想在移动端执行某js特效可以参考(function(doc, win) { var screenWidth = 0, size = 'M', root = doc.documentEleme ...

  7. 【java基础学习二】 数组相互转换,转成用逗号隔开的字符串等

    /** * int[],Integer[],List,List<Integer>,HashSet<Integer>相互转换,转成用逗号隔开的字符串 */ public stat ...

  8. mobx源码解读2

    我们将上节用到的几个类的构造器列举一下吧: function Reaction(name, onInvalidate) { if (name === void 0) { name = "Re ...

  9. 利用Sql实现将指定表数据导入到另一个数据库示例

    因为工作中经常需要将数据从一个数据库导入到另一个数据库中,所以将这个功能写成一个存储过程,以方便调用.现在粘贴出来供大家参考: 注意:1,以下示例中用到了syscolumns,sysobjects等系 ...

  10. 创建 Web 前端开发环境

    Web 前端开发涉及多种工具,这里将常用工具的安装和配置进行说明,提供了详细的说明,为后继的开发创建一个坚实的基础. 本文介绍的工具有:NodeJS, NPM, Bower, Git 和 Grunt. ...