也许是受到很久以前看到的这玩意儿的原因: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(支持动画)的更多相关文章

  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. 【转】Java关键字final、static使用总结

    转自:http://lavasoft.blog.51cto.com/62575/18771/   Java关键字final.static使用总结   一.final        根据程序上下文环境, ...

  2. linux 关于用户与组的操作

    1.添加用户: useradd  handongyu 2.查看所有用户 cat  /etc/passwd   查看某一用户用 cat /etc/passwd |grep root 3.查看所有组 ca ...

  3. CMake比较实用的命令小记

    最近将项目迁移到CMake进行管理,对CMake进行了一些研究,觉得有一些命令非常实用但很少有资料提到,在这里做一个总结,至于太普通常用的命令就不提了. OPTION(OPTION_VAR " ...

  4. rabbitMQ学习(二)

    一端发送,多端消费 发送端: import java.io.IOException; import com.rabbitmq.client.ConnectionFactory; import com. ...

  5. js面向对象笔记

    JavaScript 私有成员实现 到此为止,如果您任然对 JavaScript 面向对象持怀疑态度,那么这个怀疑一定是,JavaScript 没有实现面向对象中的信息隐藏,即私有和公有.与其他类式面 ...

  6. Redis_DataType

    Redis_DataType.html :first-child{margin-top:0!important}img.plugin{box-shadow:0 1px 3px rgba(0,0,0,. ...

  7. 去掉IE下input的叉号

    IE10下的Input Text和谷歌下面的 input search 一旦输入内容,会在最右端出现一个叉号,点击后,内容就会自动清空,看似方便,其实有些场景并不需要,需要写代码清除掉. 代码如下: ...

  8. Tomcat安装及配置教程

    工具/原料 Tomcat7.0 eclipse 百度经验:jingyan.baidu.com java环境的配置 1 java环境的配置应该都学过吧,这里简单的讲一下. 下载安装java JDK,注意 ...

  9. myeclicps开发web时候复制一个工程改名字后执行出现404错误

    当部署的时候会出现如下的警告,此时请按照如下的方法解决: 1.选择要运行的工程,右击-->properties-->在上边的搜索框中搜索web,选中web,将Web Context-roo ...

  10. VFP正则表达式判断是否是手机号码/电子邮件

    正则表达式,可以理解为字符匹配或搜索技术 ,重要的是Pattern属性的写法. *--判断是否是手机号码Function isMobiPhoneLparameters cStroRegExp=Newo ...