nonebot-plugin-osubot 6.23.1__py3-none-any.whl → 6.24.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of nonebot-plugin-osubot might be problematic. Click here for more details.
- nonebot_plugin_osubot/api.py +7 -5
- nonebot_plugin_osubot/draw/bmap.py +19 -21
- nonebot_plugin_osubot/draw/bp.py +1 -1
- nonebot_plugin_osubot/draw/echarts.py +8 -2
- nonebot_plugin_osubot/draw/info.py +2 -0
- nonebot_plugin_osubot/draw/map.py +5 -2
- nonebot_plugin_osubot/draw/osu_preview.py +64 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/css/style.css +258 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/gif.js/README.md +109 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/gif.js/gif.js +3 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/gif.js/gif.js.map +1 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/gif.js/gif.worker.js +3 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/gif.js/gif.worker.js.map +1 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/index.html +437 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/beatmap/beatmap.js +211 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/beatmap/hitobject.js +29 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/beatmap/point.js +55 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/beatmap/scroll.js +45 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/beatmap/timingpoint.js +35 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/catch/LegacyRandom.js +81 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/catch/PalpableCatchHitObject.js +53 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/catch/bananashower.js +33 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/catch/catch.js +211 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/catch/fruit.js +21 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/catch/juicestream.js +176 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/mania/hitnote.js +21 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/mania/holdnote.js +37 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/mania/mania.js +164 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/preview.js +61 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/bezier2.js +33 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/catmullcurve.js +34 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/centripetalcatmullrom.js +30 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/circumstancedcircle.js +47 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/curve.js +25 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/curvetype.js +17 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/equaldistancemulticurve.js +70 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/linearbezier.js +40 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/hitcircle.js +85 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/slider.js +120 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/spinner.js +56 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/standard.js +170 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/taiko/donkat.js +40 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/taiko/drumroll.js +34 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/taiko/shaker.js +58 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/taiko/taiko.js +120 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/util.js +61 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/pic.html +115 -0
- nonebot_plugin_osubot/draw/score.py +4 -4
- nonebot_plugin_osubot/file.py +1 -12
- nonebot_plugin_osubot/mania/__init__.py +9 -10
- nonebot_plugin_osubot/matcher/bp_analyze.py +9 -9
- nonebot_plugin_osubot/matcher/guess.py +3 -3
- nonebot_plugin_osubot/matcher/map_convert.py +12 -7
- nonebot_plugin_osubot/matcher/preview.py +10 -3
- nonebot_plugin_osubot/matcher/recommend.py +7 -12
- nonebot_plugin_osubot/osufile/mods/AP.png +0 -0
- nonebot_plugin_osubot/osufile/mods/CL.png +0 -0
- nonebot_plugin_osubot/osufile/mods/DT.png +0 -0
- nonebot_plugin_osubot/osufile/mods/EZ.png +0 -0
- nonebot_plugin_osubot/osufile/mods/FI.png +0 -0
- nonebot_plugin_osubot/osufile/mods/FL.png +0 -0
- nonebot_plugin_osubot/osufile/mods/HD.png +0 -0
- nonebot_plugin_osubot/osufile/mods/HR.png +0 -0
- nonebot_plugin_osubot/osufile/mods/HT.png +0 -0
- nonebot_plugin_osubot/osufile/mods/MR.png +0 -0
- nonebot_plugin_osubot/osufile/mods/NC.png +0 -0
- nonebot_plugin_osubot/osufile/mods/NF.png +0 -0
- nonebot_plugin_osubot/osufile/mods/PF.png +0 -0
- nonebot_plugin_osubot/osufile/mods/RX.png +0 -0
- nonebot_plugin_osubot/osufile/mods/SD.png +0 -0
- nonebot_plugin_osubot/osufile/mods/SO.png +0 -0
- nonebot_plugin_osubot/osufile/mods/TD.png +0 -0
- nonebot_plugin_osubot/osufile/mods/V2.png +0 -0
- nonebot_plugin_osubot/pp.py +7 -0
- nonebot_plugin_osubot/schema/__init__.py +0 -2
- nonebot_plugin_osubot/schema/beatmapsets.py +42 -0
- nonebot_plugin_osubot/schema/score.py +1 -0
- {nonebot_plugin_osubot-6.23.1.dist-info → nonebot_plugin_osubot-6.24.1.dist-info}/METADATA +2 -2
- {nonebot_plugin_osubot-6.23.1.dist-info → nonebot_plugin_osubot-6.24.1.dist-info}/RECORD +80 -39
- nonebot_plugin_osubot/schema/sayo_beatmap.py +0 -59
- {nonebot_plugin_osubot-6.23.1.dist-info → nonebot_plugin_osubot-6.24.1.dist-info}/WHEEL +0 -0
nonebot_plugin_osubot/api.py
CHANGED
|
@@ -11,19 +11,19 @@ from nonebot import get_plugin_config
|
|
|
11
11
|
from httpx import Response
|
|
12
12
|
|
|
13
13
|
from .network.manager import network_manager
|
|
14
|
+
from .schema.beatmapsets import BeatmapSets
|
|
14
15
|
from .utils import FGM
|
|
15
16
|
from .config import Config
|
|
16
17
|
from .mods import get_mods
|
|
17
18
|
from .network import auto_retry
|
|
18
19
|
from .exceptions import NetworkError
|
|
19
20
|
from .network.first_response import get_first_response
|
|
20
|
-
from .schema import User, NewScore,
|
|
21
|
+
from .schema import User, NewScore, RecommendData
|
|
21
22
|
from .schema.score import UnifiedScore, NewStatistics, UnifiedBeatmap
|
|
22
23
|
from .schema.ppysb import InfoResponse, ScoresResponse, V2ScoresResponse
|
|
23
24
|
from .schema.user import Level, GradeCounts, UnifiedUser, UserStatistics
|
|
24
25
|
|
|
25
26
|
api = "https://osu.ppy.sh/api/v2"
|
|
26
|
-
sayoapi = "https://api.sayobot.cn"
|
|
27
27
|
cache = ExpiringDict(max_len=1, max_age_seconds=86400)
|
|
28
28
|
plugin_config = get_plugin_config(Config)
|
|
29
29
|
|
|
@@ -122,6 +122,7 @@ async def fetch_score_batch(
|
|
|
122
122
|
hp=i.beatmap.drain,
|
|
123
123
|
od=i.beatmap.accuracy,
|
|
124
124
|
stars=i.beatmap.difficulty_rating,
|
|
125
|
+
convert=i.beatmap.convert,
|
|
125
126
|
),
|
|
126
127
|
beatmapset=i.beatmapset,
|
|
127
128
|
)
|
|
@@ -413,9 +414,10 @@ async def get_random_bg() -> Optional[bytes]:
|
|
|
413
414
|
return res.content
|
|
414
415
|
|
|
415
416
|
|
|
416
|
-
async def
|
|
417
|
-
|
|
418
|
-
|
|
417
|
+
async def get_beatmapsets_info(sid) -> BeatmapSets:
|
|
418
|
+
url = f"https://osu.ppy.sh/api/v2/beatmapsets/{sid}"
|
|
419
|
+
res = await make_request(url, await get_headers(), "未查询到该谱面集(Setid)信息")
|
|
420
|
+
return BeatmapSets(**res)
|
|
419
421
|
|
|
420
422
|
|
|
421
423
|
async def get_map_bg(mapid, sid, bg_name) -> BytesIO:
|
|
@@ -4,25 +4,20 @@ from datetime import datetime, timedelta
|
|
|
4
4
|
from PIL import ImageDraw, ImageFilter, ImageEnhance
|
|
5
5
|
|
|
6
6
|
from ..file import get_projectimg
|
|
7
|
-
from ..api import
|
|
8
|
-
from ..exceptions import NetworkError
|
|
7
|
+
from ..api import get_beatmapsets_info
|
|
9
8
|
from .utils import crop_bg, stars_diff, calc_songlen
|
|
10
9
|
from .static import Image, BarImg, IconLs, Torus_SemiBold_20, Torus_SemiBold_40, Torus_SemiBold_50, extra_30, Stars
|
|
11
10
|
|
|
12
11
|
|
|
13
12
|
async def draw_bmap_info(mapid) -> BytesIO:
|
|
14
|
-
|
|
15
|
-
if sayo_info.status == -1:
|
|
16
|
-
raise NetworkError("在sayobot未查询到该地图")
|
|
17
|
-
data = sayo_info.data
|
|
18
|
-
|
|
13
|
+
data = await get_beatmapsets_info(mapid)
|
|
19
14
|
coverurl = f"https://assets.ppy.sh/beatmaps/{mapid}/covers/cover@2x.jpg"
|
|
20
15
|
cover = await get_projectimg(coverurl)
|
|
21
16
|
# 新建
|
|
22
|
-
if len(data.
|
|
17
|
+
if len(data.beatmaps) > 20:
|
|
23
18
|
im_h = 400 + 102 * 20
|
|
24
19
|
else:
|
|
25
|
-
im_h = 400 + 102 * (len(data.
|
|
20
|
+
im_h = 400 + 102 * (len(data.beatmaps) - 1)
|
|
26
21
|
im = Image.new("RGBA", (1200, im_h), (31, 41, 46, 255))
|
|
27
22
|
draw = ImageDraw.Draw(im)
|
|
28
23
|
# 背景
|
|
@@ -37,35 +32,36 @@ async def draw_bmap_info(mapid) -> BytesIO:
|
|
|
37
32
|
# mapper
|
|
38
33
|
draw.text((25, 105), f"谱面作者: {data.creator}", font=Torus_SemiBold_20, anchor="lt")
|
|
39
34
|
# rank时间
|
|
40
|
-
if data.
|
|
35
|
+
if not data.ranked_date:
|
|
41
36
|
approved_date = "谱面状态可能非ranked"
|
|
42
37
|
else:
|
|
43
|
-
datearray = datetime.
|
|
38
|
+
datearray = datetime.fromisoformat(data.ranked_date.replace("Z", ""))
|
|
44
39
|
approved_date = (datearray + timedelta(hours=8)).strftime("%Y-%m-%d %H:%M:%S")
|
|
45
40
|
draw.text((25, 140), f"上架时间: {approved_date}", font=Torus_SemiBold_20, anchor="lt")
|
|
46
41
|
# 来源
|
|
47
|
-
|
|
42
|
+
if data.source:
|
|
43
|
+
draw.text((25, 175), f"Source: {data.source}", font=Torus_SemiBold_20, anchor="lt")
|
|
48
44
|
# bpm
|
|
49
45
|
draw.text((1150, 105), f"BPM: {data.bpm}", font=Torus_SemiBold_20, anchor="rt")
|
|
50
46
|
# 曲长
|
|
51
|
-
music_len = calc_songlen(data.
|
|
47
|
+
music_len = calc_songlen(data.beatmaps[0].total_length)
|
|
52
48
|
draw.text((1150, 140), f"length: {music_len}", font=Torus_SemiBold_20, anchor="rt")
|
|
53
49
|
# Setid
|
|
54
50
|
draw.text((1150, 35), f"Setid: {mapid}", font=Torus_SemiBold_20, anchor="rt")
|
|
55
|
-
gmap = sorted(data.
|
|
51
|
+
gmap = sorted(data.beatmaps, key=lambda k: k.difficulty_rating, reverse=False)
|
|
56
52
|
for num, cmap in enumerate(gmap):
|
|
57
53
|
if num < 20:
|
|
58
54
|
h_num = 102 * num
|
|
59
55
|
# 难度
|
|
60
|
-
draw.text((20, 320 + h_num), IconLs[cmap.
|
|
56
|
+
draw.text((20, 320 + h_num), IconLs[cmap.mode_int], font=extra_30, anchor="lt")
|
|
61
57
|
# 星星
|
|
62
|
-
stars_bg = stars_diff(cmap.
|
|
58
|
+
stars_bg = stars_diff(cmap.difficulty_rating, Stars)
|
|
63
59
|
stars_img = stars_bg.resize((80, 30))
|
|
64
60
|
im.alpha_composite(stars_img, (60, 320 + h_num))
|
|
65
61
|
# diff
|
|
66
62
|
im.alpha_composite(BarImg, (10, 365 + h_num))
|
|
67
63
|
gc = ["CS", "HP", "OD", "AR"]
|
|
68
|
-
for index, i in enumerate((cmap.
|
|
64
|
+
for index, i in enumerate((cmap.cs, cmap.drain, cmap.accuracy, cmap.ar)):
|
|
69
65
|
diff_len = int(200 * i / 10) if i <= 10 else 200
|
|
70
66
|
diff_bg = Image.new("RGBA", (diff_len, 12), (255, 255, 255, 255))
|
|
71
67
|
im.alpha_composite(diff_bg, (50 + 300 * index, 365 + h_num))
|
|
@@ -90,11 +86,13 @@ async def draw_bmap_info(mapid) -> BytesIO:
|
|
|
90
86
|
anchor="lm",
|
|
91
87
|
)
|
|
92
88
|
# 难度
|
|
93
|
-
if cmap.
|
|
89
|
+
if cmap.difficulty_rating < 6.5:
|
|
94
90
|
color = (0, 0, 0, 255)
|
|
95
91
|
else:
|
|
96
92
|
color = (255, 217, 102, 255)
|
|
97
|
-
draw.text(
|
|
93
|
+
draw.text(
|
|
94
|
+
(65, 335 + h_num), f"★{cmap.difficulty_rating:.2f}", font=Torus_SemiBold_20, anchor="lm", fill=color
|
|
95
|
+
)
|
|
98
96
|
# version
|
|
99
97
|
draw.text(
|
|
100
98
|
(150, 335 + h_num),
|
|
@@ -105,14 +103,14 @@ async def draw_bmap_info(mapid) -> BytesIO:
|
|
|
105
103
|
# mapid
|
|
106
104
|
draw.text(
|
|
107
105
|
(1150, 328 + h_num),
|
|
108
|
-
f"Mapid: {cmap.
|
|
106
|
+
f"Mapid: {cmap.id}",
|
|
109
107
|
font=Torus_SemiBold_20,
|
|
110
108
|
anchor="rm",
|
|
111
109
|
)
|
|
112
110
|
# maxcb
|
|
113
111
|
draw.text(
|
|
114
112
|
(700, 328 + h_num),
|
|
115
|
-
f"Max Combo: {cmap.
|
|
113
|
+
f"Max Combo: {cmap.max_combo or 0}",
|
|
116
114
|
font=Torus_SemiBold_20,
|
|
117
115
|
anchor="lm",
|
|
118
116
|
)
|
nonebot_plugin_osubot/draw/bp.py
CHANGED
|
@@ -48,7 +48,7 @@ async def draw_bp(
|
|
|
48
48
|
# 判断是否开启lazer模式
|
|
49
49
|
if is_lazer:
|
|
50
50
|
score_info.legacy_total_score = score_info.total_score
|
|
51
|
-
if score_info.ruleset_id == 3 and not is_lazer:
|
|
51
|
+
if score_info.ruleset_id == 3 and not is_lazer and source != "ppysb":
|
|
52
52
|
score_info.accuracy = cal_legacy_acc(score_info.statistics)
|
|
53
53
|
if not is_lazer:
|
|
54
54
|
is_hidden = any(i in score_info.mods for i in (Mod(acronym="HD"), Mod(acronym="FL"), Mod(acronym="FI")))
|
|
@@ -20,8 +20,14 @@ async def draw_bpa_plot(name, pp_ls, length_ls, mod_pp_ls, mapper_pp_ls) -> byte
|
|
|
20
20
|
pic = await template_to_pic(
|
|
21
21
|
template_path,
|
|
22
22
|
template_name,
|
|
23
|
-
{
|
|
24
|
-
|
|
23
|
+
{
|
|
24
|
+
"name": name,
|
|
25
|
+
"pp_ls": pp_ls,
|
|
26
|
+
"length_ls": length_ls,
|
|
27
|
+
"mod_pp_ls": mod_pp_ls,
|
|
28
|
+
"mapper_pp_ls": mapper_pp_ls,
|
|
29
|
+
"length": len(pp_ls),
|
|
30
|
+
},
|
|
25
31
|
)
|
|
26
32
|
return pic
|
|
27
33
|
|
|
@@ -221,7 +221,9 @@ async def draw_info(uid: Union[int, str], mode: str, day: int, source: str) -> B
|
|
|
221
221
|
# 总命中
|
|
222
222
|
op, value = info_calc(statistics.total_hits, n_count)
|
|
223
223
|
t_count = f"{statistics.total_hits:,}({op}{value:,})" if value != 0 else f"{statistics.total_hits:,}"
|
|
224
|
+
avg_hit = 0 if statistics.play_count == 0 else statistics.total_hits // statistics.play_count
|
|
224
225
|
draw.text((935, 1175), t_count, font=Torus_Regular_40, anchor="rt")
|
|
226
|
+
draw.text((250, 945), f"(avg.{avg_hit:,})", font=Torus_Regular_25, anchor="lt")
|
|
225
227
|
# 游玩时间
|
|
226
228
|
sec = timedelta(seconds=statistics.play_time)
|
|
227
229
|
d_time = datetime(1, 1, 1) + sec
|
|
@@ -156,8 +156,11 @@ async def draw_map_info(mapid: int, mods: list[str], is_lazer) -> BytesIO:
|
|
|
156
156
|
if mods:
|
|
157
157
|
for mods_num, s_mods in enumerate(mods):
|
|
158
158
|
mods_bg = osufile / "mods" / f"{s_mods.acronym}.png"
|
|
159
|
-
|
|
160
|
-
|
|
159
|
+
try:
|
|
160
|
+
mods_img = Image.open(mods_bg).convert("RGBA")
|
|
161
|
+
im.alpha_composite(mods_img, (700 + 50 * mods_num, 295))
|
|
162
|
+
except FileNotFoundError:
|
|
163
|
+
pass
|
|
161
164
|
# mapper
|
|
162
165
|
icon_url = f"https://a.ppy.sh/{mapinfo.user_id}"
|
|
163
166
|
user_icon = await get_projectimg(icon_url)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
import jinja2
|
|
5
|
+
from nonebot_plugin_htmlrender import get_new_page
|
|
6
|
+
|
|
7
|
+
from ..file import map_path, download_osu
|
|
8
|
+
|
|
9
|
+
template_path = str(Path(__file__).parent / "osu_preview_templates")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
async def draw_osu_preview(beatmap_id, beatmapset_id) -> bytes:
|
|
13
|
+
path = map_path / str(beatmapset_id)
|
|
14
|
+
if not path.exists():
|
|
15
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
16
|
+
osu = path / f"{beatmap_id}.osu"
|
|
17
|
+
if not osu.exists():
|
|
18
|
+
await download_osu(beatmapset_id, beatmap_id)
|
|
19
|
+
with open(osu, encoding="utf-8-sig") as f:
|
|
20
|
+
osu_file = f.read()
|
|
21
|
+
template_name = "pic.html"
|
|
22
|
+
template_env = jinja2.Environment( # noqa: S701
|
|
23
|
+
loader=jinja2.FileSystemLoader(template_path),
|
|
24
|
+
enable_async=True,
|
|
25
|
+
)
|
|
26
|
+
template = template_env.get_template(template_name)
|
|
27
|
+
img_selector = "img"
|
|
28
|
+
base_url = Path(template_path).as_uri() + "/"
|
|
29
|
+
worker_script_path = Path(template_path) / "gif.js" / "gif.worker.js"
|
|
30
|
+
|
|
31
|
+
# 读取 worker 脚本内容
|
|
32
|
+
with open(worker_script_path, encoding="utf-8") as f:
|
|
33
|
+
worker_script_content = f.read()
|
|
34
|
+
worker_base64 = base64.b64encode(worker_script_content.encode("utf-8")).decode("utf-8")
|
|
35
|
+
worker_data_uri = f"data:application/javascript;base64,{worker_base64}"
|
|
36
|
+
async with get_new_page(2) as page:
|
|
37
|
+
await page.goto(f"file://{template_path}")
|
|
38
|
+
await page.set_content(
|
|
39
|
+
await template.render_async(osu_file=osu_file, base_url=base_url, worker_data_uri=worker_data_uri),
|
|
40
|
+
wait_until="networkidle",
|
|
41
|
+
)
|
|
42
|
+
await page.wait_for_function(
|
|
43
|
+
f"() => document.querySelector('{img_selector}') &&"
|
|
44
|
+
f" document.querySelector('{img_selector}').src.startsWith('blob:')",
|
|
45
|
+
timeout=60000,
|
|
46
|
+
)
|
|
47
|
+
blob_url = await page.locator(img_selector).get_attribute("src")
|
|
48
|
+
base64_data = await page.evaluate(
|
|
49
|
+
"""async (url) => {
|
|
50
|
+
const response = await fetch(url);
|
|
51
|
+
const blob = await response.blob();
|
|
52
|
+
|
|
53
|
+
return new Promise((resolve) => {
|
|
54
|
+
const reader = new FileReader();
|
|
55
|
+
reader.onloadend = () => {
|
|
56
|
+
resolve(reader.result.split(',')[1]);
|
|
57
|
+
};
|
|
58
|
+
reader.readAsDataURL(blob);
|
|
59
|
+
});
|
|
60
|
+
}""",
|
|
61
|
+
blob_url,
|
|
62
|
+
)
|
|
63
|
+
gif_bytes = base64.b64decode(base64_data)
|
|
64
|
+
return gif_bytes
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
html,
|
|
2
|
+
body {
|
|
3
|
+
height: 100%;
|
|
4
|
+
overflow: hidden;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
body {
|
|
8
|
+
margin: 0;
|
|
9
|
+
background: #000;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
button {
|
|
13
|
+
margin: 0;
|
|
14
|
+
padding: 0;
|
|
15
|
+
border: none;
|
|
16
|
+
outline: 0;
|
|
17
|
+
background: none;
|
|
18
|
+
color: #fff;
|
|
19
|
+
cursor: pointer;
|
|
20
|
+
width: 40px;
|
|
21
|
+
height: 40px;
|
|
22
|
+
font: 14px sans-serif;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
#control button::-moz-focus-inner {
|
|
26
|
+
padding: 0;
|
|
27
|
+
border: 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
body>* {
|
|
31
|
+
position: fixed;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
#speed,
|
|
35
|
+
#control,
|
|
36
|
+
#settingsPanel,
|
|
37
|
+
#title,
|
|
38
|
+
#mania {
|
|
39
|
+
background: rgba(0, 0, 0, .6);
|
|
40
|
+
display: none;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
body.h #speed,
|
|
44
|
+
body.h #control,
|
|
45
|
+
body.h #settingsPanel,
|
|
46
|
+
body.h #title,
|
|
47
|
+
body.h #mania.e {
|
|
48
|
+
display: block;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
#container {
|
|
52
|
+
top: 50%;
|
|
53
|
+
left: 50%;
|
|
54
|
+
transform: translate(-50%, -50%);
|
|
55
|
+
background-size: cover;
|
|
56
|
+
background-repeat: no-repeat;
|
|
57
|
+
background-position: center;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
#play {
|
|
61
|
+
top: 0;
|
|
62
|
+
left: 0;
|
|
63
|
+
width: 100%;
|
|
64
|
+
height: 100%;
|
|
65
|
+
font-size: 50vmin;
|
|
66
|
+
text-shadow: 0 0 .05em #000;
|
|
67
|
+
opacity: 0;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
#play.e {
|
|
71
|
+
opacity: .6;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
#speed {
|
|
75
|
+
top: 50%;
|
|
76
|
+
right: 0;
|
|
77
|
+
transform: translateY(-50%);
|
|
78
|
+
width: 40px;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
#speed button:not(.e) {
|
|
82
|
+
color: #666;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
#mania {
|
|
86
|
+
top: 50%;
|
|
87
|
+
left: 0;
|
|
88
|
+
transform: translateY(-50%);
|
|
89
|
+
width: 40px;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
#settingsPanel {
|
|
93
|
+
right: 10px;
|
|
94
|
+
bottom: 50px;
|
|
95
|
+
width: 150px;
|
|
96
|
+
border: 1px solid #aaa;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
#settingsPanel button {
|
|
101
|
+
margin: 2px;
|
|
102
|
+
padding: 0;
|
|
103
|
+
border: none;
|
|
104
|
+
outline: 0;
|
|
105
|
+
background: none;
|
|
106
|
+
color: #fff;
|
|
107
|
+
cursor: pointer;
|
|
108
|
+
width: 146px;
|
|
109
|
+
height: 36px;
|
|
110
|
+
font: 14px sans-serif;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
#openPanel {
|
|
114
|
+
top: 50%;
|
|
115
|
+
left: 30%;
|
|
116
|
+
transform: translateY(-50%);
|
|
117
|
+
width: 40%;
|
|
118
|
+
height: 50%;
|
|
119
|
+
border: 1px solid #aaa;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
#openTitle {
|
|
123
|
+
color: #fff;
|
|
124
|
+
font: 16px sans-serif;
|
|
125
|
+
border-bottom: solid 1px #fff;
|
|
126
|
+
white-space: nowrap;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
#openContent {
|
|
130
|
+
display: flex;
|
|
131
|
+
align-items: center;
|
|
132
|
+
justify-content: center;
|
|
133
|
+
flex-wrap: nowrap;
|
|
134
|
+
overflow-y: auto;
|
|
135
|
+
height: calc(100% - 30px);
|
|
136
|
+
align-content: center;
|
|
137
|
+
flex-direction: column;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
#openContent button{
|
|
141
|
+
margin: 2px;
|
|
142
|
+
padding: 0;
|
|
143
|
+
border: 1px solid #aaa;
|
|
144
|
+
background: none;
|
|
145
|
+
color: #fff;
|
|
146
|
+
cursor: pointer;
|
|
147
|
+
width: calc(100% - 4px);
|
|
148
|
+
height: 36px;
|
|
149
|
+
font: 16px sans-serif;
|
|
150
|
+
display: flex;
|
|
151
|
+
align-items: center;
|
|
152
|
+
justify-content: center;
|
|
153
|
+
white-space: nowrap;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
#fileInput {
|
|
157
|
+
display: none;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
#folderInput {
|
|
161
|
+
display: none;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
#settingsPanel .settingsbtn:hover, #settingsPanel .settingsbtn:active {
|
|
165
|
+
border: 1px solid #aaa;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
#control {
|
|
169
|
+
bottom: 0;
|
|
170
|
+
left: 0;
|
|
171
|
+
width: 100%;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
input {
|
|
175
|
+
margin: 4px;
|
|
176
|
+
padding: 0;
|
|
177
|
+
height: 32px;
|
|
178
|
+
box-sizing: border-box;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
#playtime {
|
|
182
|
+
margin: 4px;
|
|
183
|
+
vertical-align: 10px;
|
|
184
|
+
padding-left: 10px;
|
|
185
|
+
box-sizing: border-box;
|
|
186
|
+
color: white;
|
|
187
|
+
font-size: 12px;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
#progress {
|
|
191
|
+
width: calc(100% - 226px);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
#volume {
|
|
195
|
+
width: 80px;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
#title {
|
|
199
|
+
top: 0;
|
|
200
|
+
left: 0;
|
|
201
|
+
width: 100%;
|
|
202
|
+
white-space: nowrap;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
img {
|
|
206
|
+
vertical-align: middle;
|
|
207
|
+
position: relative;
|
|
208
|
+
border: 0;
|
|
209
|
+
top: -1px;
|
|
210
|
+
padding: 0 10px;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
a {
|
|
214
|
+
font: 14px/40px sans-serif;
|
|
215
|
+
border-bottom: 1px dashed transparent;
|
|
216
|
+
color: #fff;
|
|
217
|
+
text-decoration: none;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
a:hover {
|
|
221
|
+
border-bottom-color: #ddd;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
#share {
|
|
225
|
+
position: absolute;
|
|
226
|
+
top: 0;
|
|
227
|
+
right: 0;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
#sharePrompt {
|
|
231
|
+
top: 50%;
|
|
232
|
+
left: 50%;
|
|
233
|
+
transform: translate(-50%, -50%);
|
|
234
|
+
background: rgba(255, 255, 255, .6);
|
|
235
|
+
display: none;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
#sharePrompt button {
|
|
239
|
+
float: right;
|
|
240
|
+
background: #49f;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
#sharePrompt input {
|
|
244
|
+
width: 100%;
|
|
245
|
+
margin: 0;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
#fullscreen {
|
|
249
|
+
position: absolute;
|
|
250
|
+
top: 0;
|
|
251
|
+
right: 0;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
#settings {
|
|
255
|
+
position: absolute;
|
|
256
|
+
top: 0;
|
|
257
|
+
right: 40;
|
|
258
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
|
|
2
|
+
# gif.js
|
|
3
|
+
|
|
4
|
+
JavaScript GIF encoder that runs in your browser.
|
|
5
|
+
|
|
6
|
+
Uses typed arrays and web workers to render each frame in the background, it's really fast!
|
|
7
|
+
|
|
8
|
+
**Demo** - http://jnordberg.github.io/gif.js/
|
|
9
|
+
|
|
10
|
+
Works in browsers supporting: [Web Workers](http://www.w3.org/TR/workers/), [File API](http://www.w3.org/TR/FileAPI/) and [Typed Arrays](https://www.khronos.org/registry/typedarray/specs/latest/)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
Include `gif.js` found in `dist/` in your page. Also make sure to have `gif.worker.js` in the same location.
|
|
16
|
+
|
|
17
|
+
```javascript
|
|
18
|
+
var gif = new GIF({
|
|
19
|
+
workers: 2,
|
|
20
|
+
quality: 10
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// add an image element
|
|
24
|
+
gif.addFrame(imageElement);
|
|
25
|
+
|
|
26
|
+
// or a canvas element
|
|
27
|
+
gif.addFrame(canvasElement, {delay: 200});
|
|
28
|
+
|
|
29
|
+
// or copy the pixels from a canvas context
|
|
30
|
+
gif.addFrame(ctx, {copy: true});
|
|
31
|
+
|
|
32
|
+
gif.on('finished', function(blob) {
|
|
33
|
+
window.open(URL.createObjectURL(blob));
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
gif.render();
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Options
|
|
41
|
+
|
|
42
|
+
Options can be passed to the constructor or using the `setOptions` method.
|
|
43
|
+
|
|
44
|
+
| Name | Default | Description |
|
|
45
|
+
| -------------|-----------------|----------------------------------------------------|
|
|
46
|
+
| repeat | `0` | repeat count, `-1` = no repeat, `0` = forever |
|
|
47
|
+
| quality | `10` | pixel sample interval, lower is better |
|
|
48
|
+
| workers | `2` | number of web workers to spawn |
|
|
49
|
+
| workerScript | `gif.worker.js` | url to load worker script from |
|
|
50
|
+
| background | `#fff` | background color where source image is transparent |
|
|
51
|
+
| width | `null` | output image width |
|
|
52
|
+
| height | `null` | output image height |
|
|
53
|
+
| transparent | `null` | transparent hex color, `0x00FF00` = green |
|
|
54
|
+
| dither | `false` | dithering method, e.g. `FloydSteinberg-serpentine` |
|
|
55
|
+
| debug | `false` | whether to print debug information to console |
|
|
56
|
+
|
|
57
|
+
If width or height is `null` image size will be deteremined by first frame added.
|
|
58
|
+
|
|
59
|
+
Available dithering methods are:
|
|
60
|
+
|
|
61
|
+
* `FloydSteinberg`
|
|
62
|
+
* `FalseFloydSteinberg`
|
|
63
|
+
* `Stucki`
|
|
64
|
+
* `Atkinson`
|
|
65
|
+
|
|
66
|
+
You can add `-serpentine` to use serpentine scanning, e.g. `Stucki-serpentine`.
|
|
67
|
+
|
|
68
|
+
### addFrame options
|
|
69
|
+
|
|
70
|
+
| Name | Default | Description |
|
|
71
|
+
| -------------|-----------------|----------------------------------------------------|
|
|
72
|
+
| delay | `500` | frame delay |
|
|
73
|
+
| copy | `false` | copy the pixel data |
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
## Acknowledgements
|
|
77
|
+
|
|
78
|
+
gif.js is based on:
|
|
79
|
+
|
|
80
|
+
* [Kevin Weiner's Animated gif encoder classes](http://www.fmsware.com/stuff/gif.html)
|
|
81
|
+
* [Neural-Net color quantization algorithm by Anthony Dekker](http://members.ozemail.com.au/~dekker/NEUQUANT.HTML)
|
|
82
|
+
* [Thibault Imbert's as3gif](https://code.google.com/p/as3gif/)
|
|
83
|
+
|
|
84
|
+
Dithering code contributed by @PAEz and @panrafal
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
## License
|
|
88
|
+
|
|
89
|
+
The MIT License (MIT)
|
|
90
|
+
|
|
91
|
+
Copyright (c) 2013 Johan Nordberg
|
|
92
|
+
|
|
93
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
94
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
95
|
+
in the Software without restriction, including without limitation the rights
|
|
96
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
97
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
98
|
+
furnished to do so, subject to the following conditions:
|
|
99
|
+
|
|
100
|
+
The above copyright notice and this permission notice shall be included in
|
|
101
|
+
all copies or substantial portions of the Software.
|
|
102
|
+
|
|
103
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
104
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
105
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
106
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
107
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
108
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
109
|
+
THE SOFTWARE.
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// gif.js 0.2.0 - https://github.com/jnordberg/gif.js
|
|
2
|
+
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.GIF=f()}})(function(){var define,module,exports;return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s}({1:[function(require,module,exports){function EventEmitter(){this._events=this._events||{};this._maxListeners=this._maxListeners||undefined}module.exports=EventEmitter;EventEmitter.EventEmitter=EventEmitter;EventEmitter.prototype._events=undefined;EventEmitter.prototype._maxListeners=undefined;EventEmitter.defaultMaxListeners=10;EventEmitter.prototype.setMaxListeners=function(n){if(!isNumber(n)||n<0||isNaN(n))throw TypeError("n must be a positive number");this._maxListeners=n;return this};EventEmitter.prototype.emit=function(type){var er,handler,len,args,i,listeners;if(!this._events)this._events={};if(type==="error"){if(!this._events.error||isObject(this._events.error)&&!this._events.error.length){er=arguments[1];if(er instanceof Error){throw er}else{var err=new Error('Uncaught, unspecified "error" event. ('+er+")");err.context=er;throw err}}}handler=this._events[type];if(isUndefined(handler))return false;if(isFunction(handler)){switch(arguments.length){case 1:handler.call(this);break;case 2:handler.call(this,arguments[1]);break;case 3:handler.call(this,arguments[1],arguments[2]);break;default:args=Array.prototype.slice.call(arguments,1);handler.apply(this,args)}}else if(isObject(handler)){args=Array.prototype.slice.call(arguments,1);listeners=handler.slice();len=listeners.length;for(i=0;i<len;i++)listeners[i].apply(this,args)}return true};EventEmitter.prototype.addListener=function(type,listener){var m;if(!isFunction(listener))throw TypeError("listener must be a function");if(!this._events)this._events={};if(this._events.newListener)this.emit("newListener",type,isFunction(listener.listener)?listener.listener:listener);if(!this._events[type])this._events[type]=listener;else if(isObject(this._events[type]))this._events[type].push(listener);else this._events[type]=[this._events[type],listener];if(isObject(this._events[type])&&!this._events[type].warned){if(!isUndefined(this._maxListeners)){m=this._maxListeners}else{m=EventEmitter.defaultMaxListeners}if(m&&m>0&&this._events[type].length>m){this._events[type].warned=true;console.error("(node) warning: possible EventEmitter memory "+"leak detected. %d listeners added. "+"Use emitter.setMaxListeners() to increase limit.",this._events[type].length);if(typeof console.trace==="function"){console.trace()}}}return this};EventEmitter.prototype.on=EventEmitter.prototype.addListener;EventEmitter.prototype.once=function(type,listener){if(!isFunction(listener))throw TypeError("listener must be a function");var fired=false;function g(){this.removeListener(type,g);if(!fired){fired=true;listener.apply(this,arguments)}}g.listener=listener;this.on(type,g);return this};EventEmitter.prototype.removeListener=function(type,listener){var list,position,length,i;if(!isFunction(listener))throw TypeError("listener must be a function");if(!this._events||!this._events[type])return this;list=this._events[type];length=list.length;position=-1;if(list===listener||isFunction(list.listener)&&list.listener===listener){delete this._events[type];if(this._events.removeListener)this.emit("removeListener",type,listener)}else if(isObject(list)){for(i=length;i-- >0;){if(list[i]===listener||list[i].listener&&list[i].listener===listener){position=i;break}}if(position<0)return this;if(list.length===1){list.length=0;delete this._events[type]}else{list.splice(position,1)}if(this._events.removeListener)this.emit("removeListener",type,listener)}return this};EventEmitter.prototype.removeAllListeners=function(type){var key,listeners;if(!this._events)return this;if(!this._events.removeListener){if(arguments.length===0)this._events={};else if(this._events[type])delete this._events[type];return this}if(arguments.length===0){for(key in this._events){if(key==="removeListener")continue;this.removeAllListeners(key)}this.removeAllListeners("removeListener");this._events={};return this}listeners=this._events[type];if(isFunction(listeners)){this.removeListener(type,listeners)}else if(listeners){while(listeners.length)this.removeListener(type,listeners[listeners.length-1])}delete this._events[type];return this};EventEmitter.prototype.listeners=function(type){var ret;if(!this._events||!this._events[type])ret=[];else if(isFunction(this._events[type]))ret=[this._events[type]];else ret=this._events[type].slice();return ret};EventEmitter.prototype.listenerCount=function(type){if(this._events){var evlistener=this._events[type];if(isFunction(evlistener))return 1;else if(evlistener)return evlistener.length}return 0};EventEmitter.listenerCount=function(emitter,type){return emitter.listenerCount(type)};function isFunction(arg){return typeof arg==="function"}function isNumber(arg){return typeof arg==="number"}function isObject(arg){return typeof arg==="object"&&arg!==null}function isUndefined(arg){return arg===void 0}},{}],2:[function(require,module,exports){var UA,browser,mode,platform,ua;ua=navigator.userAgent.toLowerCase();platform=navigator.platform.toLowerCase();UA=ua.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/)||[null,"unknown",0];mode=UA[1]==="ie"&&document.documentMode;browser={name:UA[1]==="version"?UA[3]:UA[1],version:mode||parseFloat(UA[1]==="opera"&&UA[4]?UA[4]:UA[2]),platform:{name:ua.match(/ip(?:ad|od|hone)/)?"ios":(ua.match(/(?:webos|android)/)||platform.match(/mac|win|linux/)||["other"])[0]}};browser[browser.name]=true;browser[browser.name+parseInt(browser.version,10)]=true;browser.platform[browser.platform.name]=true;module.exports=browser},{}],3:[function(require,module,exports){var EventEmitter,GIF,browser,extend=function(child,parent){for(var key in parent){if(hasProp.call(parent,key))child[key]=parent[key]}function ctor(){this.constructor=child}ctor.prototype=parent.prototype;child.prototype=new ctor;child.__super__=parent.prototype;return child},hasProp={}.hasOwnProperty,indexOf=[].indexOf||function(item){for(var i=0,l=this.length;i<l;i++){if(i in this&&this[i]===item)return i}return-1},slice=[].slice;EventEmitter=require("events").EventEmitter;browser=require("./browser.coffee");GIF=function(superClass){var defaults,frameDefaults;extend(GIF,superClass);defaults={workerScript:"gif.worker.js",workers:2,repeat:0,background:"#fff",quality:10,width:null,height:null,transparent:null,debug:false,dither:false};frameDefaults={delay:500,copy:false};function GIF(options){var base,key,value;this.running=false;this.options={};this.frames=[];this.freeWorkers=[];this.activeWorkers=[];this.setOptions(options);for(key in defaults){value=defaults[key];if((base=this.options)[key]==null){base[key]=value}}}GIF.prototype.setOption=function(key,value){this.options[key]=value;if(this._canvas!=null&&(key==="width"||key==="height")){return this._canvas[key]=value}};GIF.prototype.setOptions=function(options){var key,results,value;results=[];for(key in options){if(!hasProp.call(options,key))continue;value=options[key];results.push(this.setOption(key,value))}return results};GIF.prototype.addFrame=function(image,options){var frame,key;if(options==null){options={}}frame={};frame.transparent=this.options.transparent;for(key in frameDefaults){frame[key]=options[key]||frameDefaults[key]}if(this.options.width==null){this.setOption("width",image.width)}if(this.options.height==null){this.setOption("height",image.height)}if(typeof ImageData!=="undefined"&&ImageData!==null&&image instanceof ImageData){frame.data=image.data}else if(typeof CanvasRenderingContext2D!=="undefined"&&CanvasRenderingContext2D!==null&&image instanceof CanvasRenderingContext2D||typeof WebGLRenderingContext!=="undefined"&&WebGLRenderingContext!==null&&image instanceof WebGLRenderingContext){if(options.copy){frame.data=this.getContextData(image)}else{frame.context=image}}else if(image.childNodes!=null){if(options.copy){frame.data=this.getImageData(image)}else{frame.image=image}}else{throw new Error("Invalid image")}return this.frames.push(frame)};GIF.prototype.render=function(){var i,j,numWorkers,ref;if(this.running){throw new Error("Already running")}if(this.options.width==null||this.options.height==null){throw new Error("Width and height must be set prior to rendering")}this.running=true;this.nextFrame=0;this.finishedFrames=0;this.imageParts=function(){var j,ref,results;results=[];for(i=j=0,ref=this.frames.length;0<=ref?j<ref:j>ref;i=0<=ref?++j:--j){results.push(null)}return results}.call(this);numWorkers=this.spawnWorkers();if(this.options.globalPalette===true){this.renderNextFrame()}else{for(i=j=0,ref=numWorkers;0<=ref?j<ref:j>ref;i=0<=ref?++j:--j){this.renderNextFrame()}}this.emit("start");return this.emit("progress",0)};GIF.prototype.abort=function(){var worker;while(true){worker=this.activeWorkers.shift();if(worker==null){break}this.log("killing active worker");worker.terminate()}this.running=false;return this.emit("abort")};GIF.prototype.spawnWorkers=function(){var j,numWorkers,ref,results;numWorkers=Math.min(this.options.workers,this.frames.length);(function(){results=[];for(var j=ref=this.freeWorkers.length;ref<=numWorkers?j<numWorkers:j>numWorkers;ref<=numWorkers?j++:j--){results.push(j)}return results}).apply(this).forEach(function(_this){return function(i){var worker;_this.log("spawning worker "+i);worker=new Worker(_this.options.workerScript);worker.onmessage=function(event){_this.activeWorkers.splice(_this.activeWorkers.indexOf(worker),1);_this.freeWorkers.push(worker);return _this.frameFinished(event.data)};return _this.freeWorkers.push(worker)}}(this));return numWorkers};GIF.prototype.frameFinished=function(frame){var i,j,ref;this.log("frame "+frame.index+" finished - "+this.activeWorkers.length+" active");this.finishedFrames++;this.emit("progress",this.finishedFrames/this.frames.length);this.imageParts[frame.index]=frame;if(this.options.globalPalette===true){this.options.globalPalette=frame.globalPalette;this.log("global palette analyzed");if(this.frames.length>2){for(i=j=1,ref=this.freeWorkers.length;1<=ref?j<ref:j>ref;i=1<=ref?++j:--j){this.renderNextFrame()}}}if(indexOf.call(this.imageParts,null)>=0){return this.renderNextFrame()}else{return this.finishRendering()}};GIF.prototype.finishRendering=function(){var data,frame,i,image,j,k,l,len,len1,len2,len3,offset,page,ref,ref1,ref2;len=0;ref=this.imageParts;for(j=0,len1=ref.length;j<len1;j++){frame=ref[j];len+=(frame.data.length-1)*frame.pageSize+frame.cursor}len+=frame.pageSize-frame.cursor;this.log("rendering finished - filesize "+Math.round(len/1e3)+"kb");data=new Uint8Array(len);offset=0;ref1=this.imageParts;for(k=0,len2=ref1.length;k<len2;k++){frame=ref1[k];ref2=frame.data;for(i=l=0,len3=ref2.length;l<len3;i=++l){page=ref2[i];data.set(page,offset);if(i===frame.data.length-1){offset+=frame.cursor}else{offset+=frame.pageSize}}}image=new Blob([data],{type:"image/gif"});return this.emit("finished",image,data)};GIF.prototype.renderNextFrame=function(){var frame,task,worker;if(this.freeWorkers.length===0){throw new Error("No free workers")}if(this.nextFrame>=this.frames.length){return}frame=this.frames[this.nextFrame++];worker=this.freeWorkers.shift();task=this.getTask(frame);this.log("starting frame "+(task.index+1)+" of "+this.frames.length);this.activeWorkers.push(worker);return worker.postMessage(task)};GIF.prototype.getContextData=function(ctx){return ctx.getImageData(0,0,this.options.width,this.options.height).data};GIF.prototype.getImageData=function(image){var ctx;if(this._canvas==null){this._canvas=document.createElement("canvas");this._canvas.width=this.options.width;this._canvas.height=this.options.height}ctx=this._canvas.getContext("2d");ctx.setFill=this.options.background;ctx.fillRect(0,0,this.options.width,this.options.height);ctx.drawImage(image,0,0);return this.getContextData(ctx)};GIF.prototype.getTask=function(frame){var index,task;index=this.frames.indexOf(frame);task={index:index,last:index===this.frames.length-1,delay:frame.delay,transparent:frame.transparent,width:this.options.width,height:this.options.height,quality:this.options.quality,dither:this.options.dither,globalPalette:this.options.globalPalette,repeat:this.options.repeat,canTransfer:browser.name==="chrome"};if(frame.data!=null){task.data=frame.data}else if(frame.context!=null){task.data=this.getContextData(frame.context)}else if(frame.image!=null){task.data=this.getImageData(frame.image)}else{throw new Error("Invalid frame")}return task};GIF.prototype.log=function(){var args;args=1<=arguments.length?slice.call(arguments,0):[];if(!this.options.debug){return}return console.log.apply(console,args)};return GIF}(EventEmitter);module.exports=GIF},{"./browser.coffee":2,events:1}]},{},[3])(3)});
|
|
3
|
+
//# sourceMappingURL=gif.js.map
|