「脑洞」图片转HTML(支持动画)

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

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

「wxParser」小程序插件:想在小程序中快速部署富文本?这个插件让你一步搞定

上期,我们在<「微信同声传译」小程序插件:快速实现语音转文字.文本翻译.语音合成等能力>一文中介绍了「微信同声传译」小程序插件的意义.作用以及应用.而在此之前,我们还介绍过「腾讯地图」.「腾讯视频」.「医院 LBS 位置服务」插件,有兴趣了解的读者可以点击「微信极客WeGeek」公众号底部菜单「极客干货 - 小程序插件」了解. 今天我们为大家推荐的是一款富文本渲染插件「wxParser」,目前 wxParser 支持对一般的富文本内容包括标题.字体大小.对齐和列表等进行解析.同时也支持表格.代

「Optimage」多格式 Mac 图片压缩工具,还支持 PDF 压缩

相信你也有很多图片压缩的需要,假如你对 Photoshop 软件使用并不熟络,或者身边设备并未安装这类大型设计软件,你还有其他选择,那就是使用专用于图像压缩的软件.「Optimage」是一款老牌 Mac 图片压缩软件,只需将要处理的图像文件拖拽至软件界面,「Optimage」即开始处理,和之前介绍的「TinyPNG For Mac」不同,「Optimage」全程本地处理,效率能高一些. ## 「Optimage」刚刚更新了 3.0 版本,几个亮点: 1.简洁的 UI 设计,支持黑暗模式:2.支持

LOJ #2037. 「SHOI2015」脑洞治疗仪

#2037. 「SHOI2015」脑洞治疗仪 题目描述 曾经发明了自动刷题机的发明家 SHTSC 又公开了他的新发明:脑洞治疗仪——一种可以治疗他因为发明而日益增大的脑洞的神秘装置. 为了简单起见,我们将大脑视作一个 01 序列.1 代表这个位置的脑组织正常工作,0 代表这是一块脑洞. 1 0 1 0 0 0 1 1 1 0 脑洞治疗仪修补某一块脑洞的基本工作原理就是将另一块连续区域挖出,将其中正常工作的脑组织填补在这块脑洞中.(所以脑洞治疗仪是脑洞的治疗仪?) 例如,用上面第 8 号位置到第 

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

最近忙着搭建一个聊天用的框架,过几天应该会整理写出来吧,原理不难,但是实现后会省很多事.好久没写博客,周末心血来潮写了个图案锁,这东西没什么技术含量,网上一堆,这次这个图案锁顺便联系了怎么打包使用.a .bundle 注:支持动画.图片做触摸点,另外,打包成.a的资源包含了图片,比较大,想自定义的童鞋,可以使用未打包的,然后自己定义资源,使用颜色的,会按照默认样式绘图,不好意思,现在不支持改变样式,只能改变颜色,不过图片可以弥补这个缺陷. 先上超链接: 普通版:PLView.zip .a含资源版

「01」机器学习,到底在学些什么?

阅读 0 编辑文章 大家好,欢迎来到久违的机器学习系列,这是「美团」算法工程师带你入门机器学习 专栏的第一篇文章,不会太长,一半聊想法,一半聊干货.熟悉我的朋友可能知道,我以前的文章比较随意,涉及的内容极广,包括但不限于Python/Java/C/C++,网络编程,Hadoop等,但主要核心还是机器学习算法和数据科学相关的主题,这一点没变过. 最近认真总结和思考了之前的博客内容,决定将自己从入门到现在一路走来的学习经验和理解整理一番,帮助更多后来的小伙伴更好的入门,所以就有了这个系列.以前的知乎

「Unity」与iOS、Android平台的整合:3、导出的Android-Studio工程

本文属于「Unity与iOS.Android平台的整合」系列文章之一,转载请注明出处. Unity默认导出的是Android-Eclipse工程,毕竟Eclipse for Android开发在近一两年才开始没落,用户量还是非常巨大的. 个人认为AndroidStudio非常好用,能轻易解决很多Eclipse解决不了或者很难解决的问题. 所以我将Unity导出的Andoid工程分为Eclipse和AndroidStudio两部分. 不过我之后的相关内容都会使用AndroidStudio,希望依然

技术人员应对「考核」的一些思考

来这个公司实习已经半年多了,在年前经历了一次年终考核,最终对我的工作的评级是 C(及格-符合当前职位的工作),让我不禁思考自己在项目中的一些工作的问题,为什么我是C?是我做的不够好吗?或者说在哪里做的不够好? 从考核流程来看,基本上是 CTO 与 Team Leader 对团队成员的「年终总结与次年工作计划」进行Rank,个人狭义的认为「考核」的主要支持材料就是这个总结了. 他山之石 其他公司是怎么考核的呢?说实话我也不太清楚,刚入行,只能通过搜索了解,在网上了解到有以下几种:发精品博客.发论文

「Unity」与iOS、Android平台的整合:2、导出的Android-Eclipse工程

本文属于「Unity与iOS.Android平台的整合」系列文章之一,转载请注明出处. Unity默认导出的是Android-Eclipse工程,毕竟Eclipse for Android开发在近一两年才开始没落,用户量还是非常巨大的. 个人认为AndroidStudio非常好用,能轻易解决很多Eclipse解决不了或者很难解决的问题. 所以我将Unity导出的Andoid工程分为Eclipse和AndroidStudio两部分. 不过我之后的相关内容都会使用AndroidStudio,希望依然

从「集装箱」思考Docker风潮

从「集装箱」思考Docker风潮 -- Docker潮流下的赢家策略 By 高焕堂 (台灣Docker聯盟 主席) 2015/02/20 前言 在许多革命性转折里,经常出现集装箱的身影:它就像幸运草一般,总是带来许多幸福和财运.现在Docker风起云涌,再现集装箱身影,如果开放视野.大力支持它,持续发挥它的潜能和力量,则幸运草就会出现在我们身旁了. 由于Docker集装箱带来的商机,其最直接的受益者是软件管理者(或称维运者),例如软件测试工具业者.测试人员等.因此在今天,不论您是开发者或是维运者