当前位置: 首页 > news >正文

精灵图(雪碧图)的生成和使用

前言

一些短视频播放器在快进的时候经常能看到下方进度条展示的一个小的的单帧图片,亚马逊的转码服务(AWS MediaConvert)通过配置单帧缩略图来生成多个单帧图片。前端处理的时候需要按照时间每10秒去请求一次图片。
配置方式:
在这里插入图片描述

优化

由于是缩略图,没有必要多次请求,因此考虑使用lambda拼接成一张精灵图,前端根据坐标读取即可。

后端生成精灵图:

package req;import lombok.Data;
import pers.cz.swiss.JsonUtils;import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;/*** @version 1.0* 精灵图的核心逻辑是将多个图片合成为一个大图片,同时记录每一张图片在拼合后的大图中的位置* @description: 精灵图测试* @author: ChengZhi 0336* @create: 2025-10-09 16:47**/
public class SpriteImg {public static void main(String[] args) throws IOException {// 读取图片String dir = "C:\\Users\\chengzhi\\Desktop\\视频封面";File dirFile = new File(dir);File[] files = dirFile.listFiles();// 创建新图片File newFile = new File("C:\\Users\\chengzhi\\Desktop\\视频封面\\new.png");BufferedImage bufferedImage = ImageUtils.mergeImages(files, true);ImageIO.write(bufferedImage, "png", newFile);}}@Data
class Location {private int x;private int y;private int width;private int height;private String name;}class ImageUtils {/*** 合并图片, 支持横向或竖向合并* @param images* @param isHorizontal* @return* @throws IOException*/public static BufferedImage mergeImages(File[] images, boolean isHorizontal) throws IOException {int imagesCount = images.length;System.out.println("待合并总数:" + imagesCount);int maxWidth = 0;int maxHeight = 0;Map<String, BufferedImage> bufferedImages = new HashMap<>(imagesCount);for (File image : images) {BufferedImage bufferedImage = ImageIO.read(image);if (bufferedImage == null) {continue;}int width = bufferedImage.getWidth();int height = bufferedImage.getHeight();if (isHorizontal) {maxHeight = Math.max(maxHeight, height);maxWidth += width;} else {maxWidth = Math.max(maxWidth, width);maxHeight += height;}bufferedImages.put(image.getName(), bufferedImage);}BufferedImage finalBufferedImage = new BufferedImage(maxWidth, maxHeight, BufferedImage.TYPE_INT_ARGB);int startX = 0;int startY = 0;Map<String, Location> map = new HashMap<>();for (Map.Entry<String, BufferedImage> entry : bufferedImages.entrySet()) {BufferedImage bufImage = entry.getValue();int width = bufImage.getWidth();int height = bufImage.getHeight();int[] ImageArray = new int[width * height];;int[] rgb = bufImage.getRGB(0, 0, width, height, ImageArray, 0, width);Location location = new Location();location.setWidth(width);location.setHeight(height);location.setX(startX);location.setY(startY);if (isHorizontal) {finalBufferedImage.setRGB(startX, startY, width, height, rgb, 0, width);startX += width;} else {finalBufferedImage.setRGB(startX, startY, width, height, rgb, 0, width);startY += height;}map.put(entry.getKey(), location);}System.out.println("合并完成!");System.out.println("图片位置:" + JsonUtils.toJson(map));return finalBufferedImage;}}

前端展示demo:

<script setup>
import {ref, computed} from "vue";
import sprite from "@/views/drama/new.png"
import axios from "axios";const image = ref(sprite)// 精灵图元数据
const sprites = {"穿条纹睡衣的男孩.jpg":{"x":0,"y":0,"width":540,"height":796},"蝴蝶效应.jpg":{"x":540,"y":0,"width":540,"height":799},"天空之城.jpg":{"x":1080,"y":0,"width":540,"height":756},"天书奇谭.jpg":{"x":1620,"y":0,"width":540,"height":763},"千与千寻.jpg":{"x":2160,"y":0,"width":540,"height":780},"九品芝麻官.jpg":{"x":2700,"y":0,"width":540,"height":867},"龙猫.jpg":{"x":3240,"y":0,"width":540,"height":795},"傲慢与偏见.jpg":{"x":3780,"y":0,"width":540,"height":801},"功夫.jpg":{"x":4320,"y":0,"width":540,"height":754},"指环王2:双塔奇兵.jpg":{"x":4860,"y":0,"width":540,"height":754},"绿皮书.jpg":{"x":5400,"y":0,"width":540,"height":855},"完美的世界.jpg":{"x":5940,"y":0,"width":540,"height":810},"还有明天.jpg":{"x":6480,"y":0,"width":540,"height":768},"泰坦尼克号.jpg":{"x":7020,"y":0,"width":540,"height":803},"花样年华.jpg":{"x":7560,"y":0,"width":540,"height":769},"疯狂动物城.jpg":{"x":8100,"y":0,"width":540,"height":824},"低俗小说.jpg":{"x":8640,"y":0,"width":514,"height":755},"天堂电影院.jpg":{"x":9154,"y":0,"width":540,"height":787},"未麻的部屋.jpg":{"x":9694,"y":0,"width":443,"height":625},"无间道.jpg":{"x":10137,"y":0,"width":540,"height":819},"摩登时代.jpg":{"x":10677,"y":0,"width":540,"height":839},"海上钢琴师.jpg":{"x":11217,"y":0,"width":540,"height":763},"末代皇帝.jpg":{"x":11757,"y":0,"width":540,"height":816},"狮子王.jpg":{"x":12297,"y":0,"width":540,"height":804},"美国往事.jpg":{"x":12837,"y":0,"width":540,"height":799},"触不可及.jpg":{"x":13377,"y":0,"width":540,"height":772},"阳光灿烂的日子.jpg":{"x":13917,"y":0,"width":540,"height":777},"倩女幽魂.jpg":{"x":14457,"y":0,"width":540,"height":756},"教父3.jpg":{"x":14997,"y":0,"width":540,"height":810},"飞越疯人院.jpg":{"x":15537,"y":0,"width":540,"height":802},"死亡诗社.jpg":{"x":16077,"y":0,"width":540,"height":797},"辩护人.jpg":{"x":16617,"y":0,"width":540,"height":773},"爱在黎明破晓前.jpg":{"x":17157,"y":0,"width":540,"height":800},"一个叫欧维的男人决定去死.jpg":{"x":17697,"y":0,"width":540,"height":769},"美丽心灵.jpg":{"x":18237,"y":0,"width":540,"height":801},"神偷奶爸.jpg":{"x":18777,"y":0,"width":540,"height":799},"哪吒闹海.jpg":{"x":19317,"y":0,"width":540,"height":730},"我不是药神.jpg":{"x":19857,"y":0,"width":540,"height":756},"消失的爱人.jpg":{"x":20397,"y":0,"width":540,"height":810},"饮食男女.jpg":{"x":20937,"y":0,"width":404,"height":584},"拯救大兵瑞恩.jpg":{"x":21341,"y":0,"width":540,"height":765},"心灵捕手.jpg":{"x":21881,"y":0,"width":540,"height":796},"美丽人生.jpg":{"x":22421,"y":0,"width":540,"height":756},"时空恋旅人.jpg":{"x":22961,"y":0,"width":540,"height":800},"春光乍泄.jpg":{"x":23501,"y":0,"width":487,"height":711},"让子弹飞.jpg":{"x":23988,"y":0,"width":540,"height":792},"辛德勒的名单.jpg":{"x":24528,"y":0,"width":540,"height":796},"萤火之森.jpg":{"x":25068,"y":0,"width":540,"height":762},"驯龙高手.jpg":{"x":25608,"y":0,"width":540,"height":803},"钢琴家.jpg":{"x":26148,"y":0,"width":540,"height":745},"借东西的小人阿莉埃蒂.jpg":{"x":26688,"y":0,"width":540,"height":762},"哈利·波特与魔法石.jpg":{"x":27228,"y":0,"width":540,"height":799},"大话西游之大圣娶亲.jpg":{"x":27768,"y":0,"width":540,"height":756},"玩具总动员3.jpg":{"x":28308,"y":0,"width":540,"height":799},"乱世佳人.jpg":{"x":28848,"y":0,"width":400,"height":571},"寄生虫.jpg":{"x":29248,"y":0,"width":540,"height":769},"杀人回忆.jpg":{"x":29788,"y":0,"width":540,"height":775},"加勒比海盗.jpg":{"x":30328,"y":0,"width":540,"height":802},"爱在日落黄昏时.jpg":{"x":30868,"y":0,"width":540,"height":797},"怦然心动.jpg":{"x":31408,"y":0,"width":540,"height":802},"阿甘正传.jpg":{"x":31948,"y":0,"width":540,"height":734},"指环王3:王者无敌.jpg":{"x":32488,"y":0,"width":540,"height":754},"蝙蝠侠:黑暗骑士崛起.jpg":{"x":33028,"y":0,"width":540,"height":800},"茶馆.jpg":{"x":33568,"y":0,"width":540,"height":767},"楚门的世界.jpg":{"x":34108,"y":0,"width":540,"height":812},"重庆森林.jpg":{"x":34648,"y":0,"width":540,"height":768},"幸福终点站.jpg":{"x":35188,"y":0,"width":540,"height":770},"菊次郎的夏天.jpg":{"x":35728,"y":0,"width":540,"height":766},"飞屋环游记.jpg":{"x":36268,"y":0,"width":540,"height":800},"控方证人.jpg":{"x":36808,"y":0,"width":450,"height":675},"被嫌弃的松子的一生.jpg":{"x":37258,"y":0,"width":516,"height":728},"机器人总动员.jpg":{"x":37774,"y":0,"width":540,"height":800},"釜山行.jpg":{"x":38314,"y":0,"width":540,"height":772},"看不见的客人.jpg":{"x":38854,"y":0,"width":540,"height":770},"西西里的美丽传说.jpg":{"x":39394,"y":0,"width":540,"height":720},"三傻大闹宝莱坞.jpg":{"x":39934,"y":0,"width":540,"height":777},"寻梦环游记.jpg":{"x":40474,"y":0,"width":540,"height":771},"禁闭岛.jpg":{"x":41014,"y":0,"width":540,"height":800},"教父2.jpg":{"x":41554,"y":0,"width":540,"height":765},"少年派的奇幻漂流.jpg":{"x":42094,"y":0,"width":540,"height":800},"色,戒.jpg":{"x":42634,"y":0,"width":540,"height":770},"哈利·波特与死亡圣器(下).jpg":{"x":43174,"y":0,"width":540,"height":800},"星际穿越.jpg":{"x":43714,"y":0,"width":540,"height":786},"唐伯虎点秋香.jpg":{"x":44254,"y":0,"width":540,"height":757},"喜剧之王.jpg":{"x":44794,"y":0,"width":540,"height":767},"黑客帝国.jpg":{"x":45334,"y":0,"width":540,"height":772},"7号房的礼物.jpg":{"x":45874,"y":0,"width":540,"height":769},"放牛班的春天.jpg":{"x":46414,"y":0,"width":540,"height":756},"哈利·波特与密室.jpg":{"x":46954,"y":0,"width":540,"height":799},"忠犬八公的故事.jpg":{"x":47494,"y":0,"width":540,"height":762},"这个杀手不太冷.jpg":{"x":48034,"y":0,"width":540,"height":765},"活着.jpg":{"x":48574,"y":0,"width":540,"height":797},"致命ID.jpg":{"x":49114,"y":0,"width":540,"height":810},"怪兽电力公司.jpg":{"x":49654,"y":0,"width":540,"height":802},"教父.jpg":{"x":50194,"y":0,"width":540,"height":764},"素媛.jpg":{"x":50734,"y":0,"width":540,"height":769},"新世界.jpg":{"x":51274,"y":0,"width":540,"height":772},"大话西游之月光宝盒.jpg":{"x":51814,"y":0,"width":540,"height":772},"致命魔术.jpg":{"x":52354,"y":0,"width":540,"height":800},"蝙蝠侠:黑暗骑士.jpg":{"x":52894,"y":0,"width":540,"height":800},"本杰明·巴顿奇事.jpg":{"x":53434,"y":0,"width":540,"height":834},"一一.jpg":{"x":53974,"y":0,"width":540,"height":760},"大闹天宫.jpg":{"x":54514,"y":0,"width":540,"height":738},"当幸福来敲门.jpg":{"x":55054,"y":0,"width":540,"height":802},"哈利·波特与阿兹卡班的囚徒.jpg":{"x":55594,"y":0,"width":540,"height":800},"幽灵公主.jpg":{"x":56134,"y":0,"width":540,"height":756},"窃听风暴.jpg":{"x":56674,"y":0,"width":540,"height":810},"猫鼠游戏.jpg":{"x":57214,"y":0,"width":540,"height":799},"甜蜜蜜.jpg":{"x":57754,"y":0,"width":540,"height":756},"闻香识女人.jpg":{"x":58294,"y":0,"width":540,"height":787},"摔跤吧!爸爸.jpg":{"x":58834,"y":0,"width":540,"height":782},"罗马假日.jpg":{"x":59374,"y":0,"width":540,"height":810},"指环王1:护戒使者.jpg":{"x":59914,"y":0,"width":498,"height":778},"入殓师.jpg":{"x":60412,"y":0,"width":540,"height":755},"两杆大烟枪.jpg":{"x":60952,"y":0,"width":540,"height":810},"何以为家.jpg":{"x":61492,"y":0,"width":540,"height":795},"哈利·波特与火焰杯.jpg":{"x":62032,"y":0,"width":540,"height":800},"哈尔的移动城堡.jpg":{"x":62572,"y":0,"width":540,"height":756},"海蒂和爷爷.jpg":{"x":63112,"y":0,"width":540,"height":757},"盗梦空间.jpg":{"x":63652,"y":0,"width":540,"height":799},"超脱.jpg":{"x":64192,"y":0,"width":540,"height":800},"鬼子来了.jpg":{"x":64732,"y":0,"width":540,"height":758},"红辣椒.jpg":{"x":65272,"y":0,"width":540,"height":768},"布达佩斯大饭店.jpg":{"x":65812,"y":0,"width":540,"height":810},"超能陆战队.jpg":{"x":66352,"y":0,"width":540,"height":771},"海豚湾.jpg":{"x":66892,"y":0,"width":540,"height":720},"阿凡达.jpg":{"x":67432,"y":0,"width":400,"height":592},"音乐之声.jpg":{"x":67832,"y":0,"width":540,"height":744},"七宗罪.jpg":{"x":68372,"y":0,"width":540,"height":842},"天使爱美丽.jpg":{"x":68912,"y":0,"width":540,"height":810},"剪刀手爱德华.jpg":{"x":69452,"y":0,"width":498,"height":755},"小森林 夏秋篇.jpg":{"x":69950,"y":0,"width":540,"height":762},"情书.jpg":{"x":70490,"y":0,"width":540,"height":771},"霸王别姬.jpg":{"x":71030,"y":0,"width":540,"height":800},"熔炉.jpg":{"x":71570,"y":0,"width":540,"height":771},"勇敢的心.jpg":{"x":72110,"y":0,"width":540,"height":800},"小鞋子.jpg":{"x":72650,"y":0,"width":407,"height":600}}const selectedSprite = ref('')// 计算当前选中图片的样式
const currentSpriteStyle = computed(() => {if (!selectedSprite.value || !sprites[selectedSprite.value]) {return {}}const sprite = sprites[selectedSprite.value]return {width: `${sprite.width}px`,height: `${sprite.height}px`,backgroundImage: `url(${image.value})`,backgroundPosition: `-${sprite.x}px -${sprite.y}px`,backgroundRepeat: 'no-repeat',backgroundSize: 'auto'}
})const onSpriteChange = () => {console.log('选择了图片:', selectedSprite.value)
}</script><template><div class="sprite-container"><h2>精灵图显示</h2><select v-model="selectedSprite" @change="onSpriteChange"><option value="">请选择图片</option><option v-for="(sprite, name) in sprites" :key="name" :value="name">{{ name }}</option></select><div v-if="selectedSprite" class="sprite-display"><divclass="sprite-image":style="currentSpriteStyle"></div></div></div>
</template><style scoped>
.sprite-container {padding: 20px;text-align: center;
}select {padding: 10px;font-size: 16px;border: 1px solid #ddd;border-radius: 4px;margin: 20px 0;
}.sprite-display {margin: 20px 0;
}.sprite-image {border: 2px solid #007bff;border-radius: 8px;margin: 10px auto;display: inline-block;
}</style>

效果:

在这里插入图片描述
在这里插入图片描述

http://www.dtcms.com/a/469475.html

相关文章:

  • Web 开发 27
  • 网站制作主要公司学校网站开发系统的背景
  • Linux小课堂: 目录操作命令深度解析(LS 与 CD 命令)
  • 面向财经新闻的文本挖掘系统设计与实现(论文)
  • 【Redis-cli操作数据类型】Redis八大数据类型详解:从redis-cli操作到场景落地
  • linux安装海量数据库和操作
  • Redis分片+Sentinel熔断设计TP99控制在15ms内
  • 山海关城乡建设局网站佛山网络科技公司有哪些
  • 我的算法模板1(快速幂、逆元、组合数)
  • 八股-2025.10.11
  • 图片上传网站变形的处理旅游网站建设的概念
  • 集团培训网站建设注册公司需要什么条件和手续
  • Spark RDD详解 —— RDD特性、lineage、缓存、checkpoint、依赖关系
  • 玩转Docker系列专栏大纲
  • 网络攻防技术:信息收集技术
  • spark on hive 还是 hive on spark?
  • 搞懂数据通信不用愁!网络基础 + 参考模型 + VRP 配置,一篇全搞定
  • 解决MacOS上CLion调试的时候容器的值显示为0的问题
  • Docker快速入门——第一章Docker入门
  • 建站助手官网淘宝seo具体优化方法
  • 邯郸网站建设哪儿好网站建设参考文献英文书籍
  • STM32 串口收发数据-中断的方式
  • k8s ingress-nginx 学习
  • 【含文档+PPT+源码】基于springboot的旅游路线推荐系统的设计与实现
  • 嘉兴seo网站优化竞价托管的注意事项
  • K8S 概念、安装与核心工作机制详解
  • 做网站需要公司有哪些网站最新点击量排名
  • VUE 开发实例 一则
  • jmeter使用之--MD5加密
  • ESim电工仿真APP使用说明书