「脑洞」图片转HTML(支持动画)
也许是受到很久以前看到的这玩意儿的原因:The Shapes of CSS
现在开脑洞写了个自动转换,顺便支持了动画……嗯,纯 CSS (:з」∠)
主要步骤就是用 Python 读图片,然后把像素全转写成 CSS 的 box-shadow
,最后构建一个完整的 HTML 文件输出。
然后用浏览器打开生成的 HTML 文件,就直接看到图片了,如果输入是一个文件夹的话,就以文件夹里面的图片为帧生成一个带动画的 HTML。
最新的版本就在这儿了: img2html
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- ## @package img2html
- # Usage : img2html.py file1|dir1 [file2|dir2 ...]
- # Description : generate html uses box-shadow to show picture
- # or a html to show your image sequence in a folder as css animation
- # Dependencies : Python Image Library, Python 3
- # Note : Take care of the Super-High-Energy output ( >﹏<。)
- # Date : 2014-12-19
- # Author : frantic1048
- import sys
- import os
- from PIL import Image
- from string import Template
- class UnknownColorMode(Exception): pass
- ## @var tHTML template for constructing entire html document
- tHTML = Template('''
- <!doctype html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>~ ${name} ~</title>
- </head>
- <body>
- <style type="text/css">${css}</style>
- <div id="image_kun"></div>
- </body>
- </html>''')
- ## @var tCSSStatic template for constructing static image's css code
- tCSSStatic = Template('''
- @charset "utf-8";
- body{
- display:flex;
- justify-content:center;
- align-items:center;
- }
- #image_kun{
- height: ${height}px;
- width: ${width}px;
- position:relative;
- }
- #image_kun::after{
- position:absolute;
- height:1px;
- width:1px;
- background:${firstPixel};
- margin:0;
- padding:0;
- content:"\\200B";/*ZWS*/
- box-shadow:
- ${boxshadow};
- }
- ''')
- ## @var tCSSAnimation template for constructing image sequence's css animation code
- tCSSAnimation = Template('''
- @charset "utf-8";
- body{
- display:flex;
- justify-content:center;
- align-items:center;
- }
- #image_kun{
- height: ${height}px;
- width: ${width}px;
- position:relative;
- }
- #image_kun::after{
- position:absolute;
- height:1px;
- width:1px;
- background:transparent;
- margin:0;
- padding:0;
- content:"\\200B";/*ZWS*/
- animation:ayaya ${animationLength} step-end infinite alternate;
- }
- ${animationKeyFrames}
- ''')
- ## @var tCSSKeyframes template entire CSS keyframes rule
- tCSSKeyframes = Template('@keyframes ayaya {${keyframes}}')
- ## @var tCSSKeyframe template for a single CSS keyframe
- tCSSKeyframe = Template('${percentage}% {${keyframeRule}}\n')
- ## @var tCSSKeyframeRule template for a single CSS keyframe inner rule
- tCSSKeyframeRule = Template('background:${firstPixel};box-shadow:${boxshadow};')
- ## ensure no trailiing slash in directory name
- def toRegularDirName(dirName):
- if (os.path.split(dirName)[-1] == ''):
- return os.path.split(dirName)[0]
- else:
- return dirName
- ## write str to a file,named as <exportFileName>.html
- def toFile (str,exportFileName):
- with open (exportFileName,'w') as html:
- html.write(str)
- ## construct HEX Color value for a pixel
- # @param pixel a RGB mode pixel object to be converted
- # @return CSS hex format color value
- def toHexColor (pixel):
- return '#{0:02x}{1:02x}{2:02x}'.format(*pixel[:])
- ## construct RGBA Color value for a pixel
- # @param pixel a RGBA mode pixle object to be comverted
- # @return CSS rgba format color value
- def toRGBAColor (pixel):
- return 'rgba({0},{1},{2},{3})'.format(*pixel[:])
- def toCSSColor (pixel, mode):
- if (mode == 'RGB'):
- return toHexColor(pixel)
- elif (mode == 'RGBA'):
- return toRGBAColor(pixel)
- else:
- raise UnknownColorMode
- ## construct single box-shadow param
- # @param color valid CSS color
- def toBoxShadowParam (x, y, color):
- return format('%spx %spx 0 %s'%(x, y, color))
- ## process single image file to html
- # @param fileName input file's name
- # @param export output callback(doc, exportFileName):
- # doc : generated html string
- # exportFileName : output filename
- def mipaStatic(fileName,export=''):
- with Image.open(fileName) as im:
- ## what called magic
- boxshadow = ''
- ## file name as sysname
- exportFileName = fileName+'.html'
- title = os.path.split(fileName)[-1]
- ## image size
- width, height = im.size[0], im.size[1]
- #ensure RGB(A) mode
- if (im.mode != 'RGBA' or im.mode != 'RGB'):
- im.convert('RGB')
- firstPixel = toCSSColor(im.getpixel((0,0)), im.mode)
- for y in range(0, height):
- for x in range(0, width):
- color = toCSSColor(im.getpixel((x, y)), im.mode)
- #link magic
- boxshadow += toBoxShadowParam(x, y, color)
- #add a spliter if not the end
- if (not (y == height-1 and x == width-1)):
- #keep a '\n' for text editor ˊ_>ˋ
- boxshadow += ',' + '\n'
- doc = tHTML.substitute(name = title, css = tCSSStatic.substitute(width = width, height = height, boxshadow = boxshadow, firstPixel=firstPixel))
- if (export==''):
- print(doc)
- else:
- export(doc, exportFileName)
- ## process a image folder
- # files in folder will processed to an animated html
- # process order is filename asend
- # @param dirName input file's name
- # @param export output callback, call with generated html as a string argument
- def mipaAnimation(dirName,export=''):
- dirName = toRegularDirName(dirName)
- title = os.path.basename(dirName)
- exportFileName = title + '.html'
- files = os.listdir(dirName)
- files.sort()
- FPS = 24
- mode = ''
- width, height = 0, 0
- frameCount = 0
- keyframeRules = []
- keyframe = ''
- for f in files:
- try:
- with Image.open(os.path.join(dirName, f)) as im:
- if (export!=''):print('processing file --> ' + f)
- frameCount+=1
- #ensure RGB(A) mode
- if (im.mode != 'RGBA' or im.mode != 'RGB'):
- im.convert('RGB');
- #collect animation info
- if (width == 0) : width, height = im.size[0], im.size[1]
- if (mode == '') : mode = im.mode
- firstPixel = toCSSColor(im.getpixel((0,0)), mode)
- boxshadow = ''
- for y in range(0, height):
- for x in range(0, width):
- color = toCSSColor(im.getpixel((x, y)), mode)
- #link magic
- boxshadow += toBoxShadowParam(x, y, color)
- #add a spliter if not the end
- if (not (y == height-1 and x == width-1)):
- #keep a '\n' for text editor ˊ_>ˋ
- boxshadow += ',' + '\n'
- keyframeRules.append(tCSSKeyframeRule.substitute(firstPixel=firstPixel,boxshadow=boxshadow))
- except:
- pass
- percentUnit= 100/frameCount
- for i in range(0,frameCount):
- if (i == frameCount - 1):
- pc = ''
- elif (i == 0):
- pc = ''
- else:
- pc = str(percentUnit * i)
- keyframe += tCSSKeyframe.substitute(percentage = pc, keyframeRule = keyframeRules[i])
- if (export!=''):print('generating document...')
- doc = tHTML.substitute(name = title, css = tCSSAnimation.substitute(animationLength = str((1000 / FPS) * frameCount) + 'ms',
- animationKeyFrames = tCSSKeyframes.substitute(keyframes = keyframe),
- height = height,
- width = width))
- #output
- if (export==''):
- print(doc)
- else:
- print('Start exporting...')
- export(doc, exportFileName)
- print('Finished exporting !\nenjoy with your magical ' + exportFileName + ' _(:з」∠)_')
- for path in sys.argv[1:]:
- if os.path.isfile(path):
- ##export to stdout
- #mipaStatic(path)
- ##export to autonamed file
- mipaStatic(path,toFile)
- elif os.path.isdir(path):
- #mipaAnimation(path)
- mipaAnimation(path,toFile)
「脑洞」图片转HTML(支持动画)的更多相关文章
- 《Offer一箩筐》一份高质量「简历」撰写指南,望打扰!!
「MoreThanJava」 宣扬的是 「学习,不止 CODE」. 如果觉得 「不错」 的朋友,欢迎 「关注 + 留言 + 分享」,文末有完整的获取链接,您的支持是我前进的最大的动力! Hi~ 这里是 ...
- SpringBoot图文教程10—模板导出|百万数据Excel导出|图片导出「easypoi」
有天上飞的概念,就要有落地的实现 概念十遍不如代码一遍,朋友,希望你把文中所有的代码案例都敲一遍 先赞后看,养成习惯 SpringBoot 图文教程系列文章目录 SpringBoot图文教程1「概念+ ...
- iOS图案锁,支持动画、图片、绘图
最近忙着搭建一个聊天用的框架,过几天应该会整理写出来吧,原理不难,但是实现后会省很多事.好久没写博客,周末心血来潮写了个图案锁,这东西没什么技术含量,网上一堆,这次这个图案锁顺便联系了怎么打包使用.a ...
- loj #2037. 「SHOI2015」脑洞治疗仪
#2037. 「SHOI2015」脑洞治疗仪 题目描述 曾经发明了自动刷题机的发明家 SHTSC 又公开了他的新发明:脑洞治疗仪——一种可以治疗他因为发明而日益增大的脑洞的神秘装置. 为了简单起见 ...
- 「MoreThanJava」Java发展史及起航新世界
「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...
- 一个「学渣」从零开始的Web前端自学之路
从 13 年专科毕业开始,一路跌跌撞撞走了很多弯路,做过餐厅服务员,进过工厂干过流水线,做过客服,干过电话销售可以说经历相当的“丰富”. 最后的机缘巧合下,走上了前端开发之路,作为一个非计算机专业且低 ...
- Android逆向之旅---静态方式分析破解视频编辑应用「Vue」水印问题
一.故事背景 现在很多人都喜欢玩文艺,特别是我身边的UI们,拍照一分钟修图半小时.就是为了能够在朋友圈显得逼格高,不过的确是挺好看的,修图的软件太多了就不多说了,而且一般都没有水印啥的.相比较短视频有 ...
- 零元学Expression Blend 4 - Chapter 18 用实例了解互动控制项「CheckBox」II
原文:零元学Expression Blend 4 - Chapter 18 用实例了解互动控制项「CheckBox」II 延续上一章的CheckBox教学,本章将以实作继续延伸更灵活的运用CheckB ...
- 零元学Expression Blend 4 - Chapter 17 用实例了解互动控制项「CheckBox」I
原文:零元学Expression Blend 4 - Chapter 17 用实例了解互动控制项「CheckBox」I 本章将教大家如何运用CheckBox做实作上的变化:教你如何把CheckBox变 ...
随机推荐
- 数据库的NULL值讨论
有许多关于数据库设计中NULL的讨论,我个人的设计习惯是,不使用NULL值. 我所设计所有表都是Not Null的字段的,尤其是我主要做数据仓库的表设计.刚开始使用数据库时,就栽了一次.一个Group ...
- java ppt课后作业
1 .仔细阅读示例: EnumTest.java,运行它,分析运行结果? 枚举类型是引用类型,枚举不属于原始数据类型,它的每个具体值都引用一个特定的对象.相同的值则引用同一个对象.可以使用“==”和e ...
- JS,复习
按钮,倒数五秒操作练习 <input type="button" id="btn1" value="按钮(5)" disable=&q ...
- 44、NLP的其他分词功能测试
1. 命名实体识别功能测试 @Test public void testNer(){ if (NER.create("ltp_data/ner.model")<0) { Sy ...
- 36、重新复习html和css之二
(1)由于公司是意大利的网段, (2)而且公司的电脑是保密的, (3)文件发不出去, (4)U盘插不进去. (5)而且我们组的项目整体上已经开发完毕,客户暂时没有什么大的需求, 所以如果我不把这些技术 ...
- css响应有media,js响应有这种
比如,我不想在移动端执行某js特效可以参考(function(doc, win) { var screenWidth = 0, size = 'M', root = doc.documentEleme ...
- 【java基础学习二】 数组相互转换,转成用逗号隔开的字符串等
/** * int[],Integer[],List,List<Integer>,HashSet<Integer>相互转换,转成用逗号隔开的字符串 */ public stat ...
- mobx源码解读2
我们将上节用到的几个类的构造器列举一下吧: function Reaction(name, onInvalidate) { if (name === void 0) { name = "Re ...
- 利用Sql实现将指定表数据导入到另一个数据库示例
因为工作中经常需要将数据从一个数据库导入到另一个数据库中,所以将这个功能写成一个存储过程,以方便调用.现在粘贴出来供大家参考: 注意:1,以下示例中用到了syscolumns,sysobjects等系 ...
- 创建 Web 前端开发环境
Web 前端开发涉及多种工具,这里将常用工具的安装和配置进行说明,提供了详细的说明,为后继的开发创建一个坚实的基础. 本文介绍的工具有:NodeJS, NPM, Bower, Git 和 Grunt. ...