「脑洞」图片转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)

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。