diff --git a/README.md b/README.md index 69be1ac..514c7dc 100644 --- a/README.md +++ b/README.md @@ -5,30 +5,34 @@ One Last Image 卢浮宫生成器 是一个 将 **赛璐珞风格** **动画截图** 或 **插画**,转换成 One Last Kiss 封面风格的在线生成器 ## 地址 -https://lab.magiconch.com/one-last-image/ + ## 功能 + 在转换时,可以自定义 - - 线条处理方案 - - 开关 One Last Kiss 风格(仅将图片转换为线稿) - - 给画面暗部排铅笔调子 - - 叠加类似 One Last Kiss 光碟封面水印 - - 初回限定盘面效果选项 - - 线迹轻重 - - 调子数量 - - 叠加歌词 (未完成) + +- 线条处理方案 +- 开关 One Last Kiss 风格(仅将图片转换为线稿) +- 给画面暗部排铅笔调子 +- 叠加类似 One Last Kiss 光碟封面水印 +- 初回限定盘面效果选项 +- 线迹轻重 +- 调子数量 +- 叠加歌词 (未完成) 点按图片可以和原图对比生成效果,也可以直接输出对比图 手机端请使用自带浏览器进行保存 - ## GitHub -https://github.com/itorr/one-last-image + + ## 微博 -https://weibo.com/1197780522/M19X18EGP + + ## 使用了 -ITC Avant Garde Gothic Bold [#3](https://github.com/itorr/one-last-image/issues/3) \ No newline at end of file + +ITC Avant Garde Gothic Bold [#3](https://github.com/itorr/one-last-image/issues/3) diff --git a/html/document.css b/html/document.css new file mode 100644 index 0000000..55047b5 --- /dev/null +++ b/html/document.css @@ -0,0 +1,379 @@ +:root { + --background-color: #c3c3c3; + --background-color-transparent-half: rgba(195, 195, 195, 0.5); + --background-color-transparent: rgba(195, 195, 195, 0); + --color-font: #111; +} +html { + background: var(--background-color); + text-align: center; + font: 14px sans-serif; +} +html[data-loading="true"] { + overflow: hidden; +} +html[data-output="true"] { + overflow: hidden; +} +body { + margin: 0; +} +button { + cursor: pointer; +} +a { + color: #666; + text-decoration: none; + cursor: pointer; +} +hr { + border: 0; + border-top: 1px solid rgba(0, 0, 0, 0.08); + margin: 10px auto; + max-width: 100px; + display: block; +} +header { + padding: 40px 0 30px; +} +header p { + opacity: 0.5; +} +.loading-box { + position: fixed; + top: 0; + right: 0; + left: 0; + bottom: 0; + z-index: 1; + background: #FFF; + animation: loadingBoxopacityIn 4s ease; +} +.loading-box h2 { + line-height: 100px; + width: 100%; +} +.loading-box svg { + width: 320px; + height: 40px; + margin: auto; + position: absolute; + top: 0; + right: 0; + left: 0; + bottom: 0; + opacity: 0; + animation: opacityIn 3s ease 1s; +} +@keyframes loadingBoxopacityIn { + 0%, + 90% { + opacity: 1; + } + 100% { + opacity: 0; + } +} +@keyframes opacityIn { + 0%, + 80%, + 100% { + opacity: 0; + } + 40%, + 60% { + opacity: 1; + } +} +h1 { + margin: 0 auto; + width: 300px; + height: 52px; + font-size: 39px; + line-height: 52px; + word-spacing: -1px; + white-space: nowrap; + overflow: hidden; + color: transparent; + background: url(one-last-image-sans.svg) no-repeat; + background-size: contain; +} +@media (min-width: 800px) { + h1 { + width: 400px; + height: 68px; + font-size: 52px; + line-height: 68px; + } +} +h2 { + margin: 0; +} +.app { + max-width: 800px; + margin: 0 auto; +} +[v-clock] { + visibility: hidden; +} +.main-box .ctrl-box { + padding: 40px 0; +} +.preview-box { + position: relative; + cursor: pointer; + --cover-width: 480px; +} +.preview-box img, +.preview-box canvas { + display: block; + max-width: 100%; + margin: 0 auto; +} +.preview-box img { + position: absolute; + left: 0; + right: 0; + opacity: 0; + pointer-events: none; + transition: opacity 0.1s ease; +} +.preview-box[data-diff] img { + opacity: 1; +} +.preview-box[data-runing] img { + opacity: 1; +} +.preview-box[data-cover="true"] { + width: var(--cover-width); + height: var(--cover-width); + margin: 0 auto; +} +.preview-box[data-cover="true"] img, +.preview-box[data-cover="true"] canvas { + width: var(--cover-width); + height: var(--cover-width); + object-fit: cover; +} +@media (max-width: 480px) { + .preview-box { + --cover-width: 100vw; + } +} +.generator-btn:before { + content: '生成'; +} +.app[data-runing="true"] .generator-btn { + pointer-events: none; +} +.app[data-runing="true"] .generator-btn:before { + content: '生成中...'; +} +.config-box { + padding: 40px 0; +} +.tips-box { + padding: 14px; +} +.tips-box p { + margin: 0; + padding: 4px 0; +} +.range-box { + padding: 4px 0; + width: 320px; + max-width: 100%; + margin: 0 auto; + font-size: 12px; +} +.range-box .head { + overflow: hidden; +} +.range-box .head b { + float: left; +} +.range-box .head span { + float: right; +} +input[type="range"] { + display: block; + margin: 0 auto; + width: 100%; +} +/* .app[data-cover="true"] canvas{ + width:480px; + height:480px; +} */ +.ui-shadow { + position: fixed; + top: 0; + right: 0; + left: 0; + bottom: 0; + z-index: 1; + background: rgba(0, 0, 0, 0.5); + overflow: auto; + overflow-y: scroll; + overscroll-behavior: contain; +} +.output-box { + background: #FFF; + width: 800px; + max-width: 100%; + margin: 40px auto; + padding: 20px; + box-sizing: border-box; + box-shadow: 0 0 40px rgba(0, 10, 40, 0.4); +} +.output-box h2 { + padding-bottom: 10px; +} +.output-box img { + display: block; + width: 800px; + max-width: 100%; + box-shadow: 0 0 20px rgba(40, 80, 200, 0.2); + margin: 10px 0 40px; +} +.output-box .ctrl-box { + padding: 10px 0; +} +footer { + padding: 40px 0 80px; + line-height: 3; +} +footer a { + display: inline-block; + padding: 0 0.5em; +} +[data-text]:before { + content: attr(data-text); +} +.ui-tabs-box { + display: inline-block; + overflow: hidden; + text-align: center; +} +.ui-tabs-box a { + color: currentColor; + float: left; + cursor: pointer; + line-height: 1; + padding: 6px; + border-radius: 3px; + transition: color 0.3s ease, background-color 0.3s ease; +} +.ui-tabs-box a[data-checked="true"] { + background: currentColor; +} +.ui-tabs-box a[data-checked="true"]:before { + color: #FFF; +} +.ui-switch-box { + cursor: pointer; + margin: 0.2em; + display: inline-block; + vertical-align: middle; + text-align: left; + transition: opacity 0.3s ease; +} +.ui-switch-box .switch { + display: inline-block; + vertical-align: middle; + margin-top: -0.3em; + width: 2.4em; + height: 1.4em; + border-radius: 9em; + background: rgba(0, 0, 0, 0.2); + background: #999; + transition: background-color 0.3s ease; +} +.ui-switch-box .switch .slider { + display: inline-block; + vertical-align: top; + width: 1em; + height: 1em; + border-radius: 9em; + background: #FFF; + margin: 0.2em; + position: relative; + transition: transform 0.3s ease; +} +.ui-switch-box[data-checked] .switch { + background: #000; +} +.ui-switch-box[data-checked] .switch .slider { + transform: translateX(1em); +} +.ui-switch-box[data-disabled="true"] { + opacity: 0.5; + pointer-events: none; +} +.btn { + display: inline-block; + border: 0; + margin: 4px; + font-size: 15px; + line-height: 1.4; + padding: 10px 16px; + border-radius: 3px; + background: #666; + color: #DDD; + transition: background-color 0.3s ease, color 0.3s ease; +} +.btn.current { + background: #000; + color: #EEE; +} +.btn[disabled] { + background: #999; + pointer-events: none; +} +.lyric-box { + --lyric-padding: 100px; + height: 48px; + overflow: hidden; + margin: 20px 0 140px; + padding: var(--lyric-padding) 0; + position: relative; + z-index: 0; +} +.lyric-box:before, +.lyric-box:after { + content: ''; + display: block; + height: var(--lyric-padding); + position: absolute; + left: 0; + right: 0; + z-index: 1; +} +.lyric-box:before { + top: 0; + background-image: linear-gradient(180deg, var(--background-color), var(--background-color-transparent-half), var(--background-color-transparent)); +} +.lyric-box:after { + bottom: 0; + background-image: linear-gradient(0deg, var(--background-color), var(--background-color-transparent-half), var(--background-color-transparent)); +} +.lyric-box .list { + transition: transform 0.3s ease; +} +.lyric-box .item { + box-sizing: border-box; + height: 48px; + line-height: 20px; + padding: 14px 0; + transition: opacity 0.3s ease; + opacity: 0.3; +} +.lyric-box .item[data-have-cn="true"] { + padding: 4px 0; +} +.lyric-box .item .cn { + opacity: 0.4; + font-size: 12px; +} +.lyric-box .item[data-current="true"] { + opacity: 1; +} diff --git a/html/index.html b/html/index.html index 8974b92..2fb19c3 100644 --- a/html/index.html +++ b/html/index.html @@ -274,5 +274,28 @@

生成好啦

+ \ No newline at end of file diff --git a/html/louvre.js b/html/louvre.js index 8a47f98..03086bc 100644 --- a/html/louvre.js +++ b/html/louvre.js @@ -21,13 +21,13 @@ let scale = width / height; let lastConfigString = null; const canvas = document.createElement('canvas'); -const ctx = canvas.getContext('2d'); +const ctx = canvas.getContext('2d', { willReadFrequently: true }); const canvasShade = document.createElement('canvas'); const canvasShadeMin = document.createElement('canvas'); const canvasMin = document.createElement('canvas'); const pencilTextureCanvas = document.createElement('canvas'); -const louvre = async ({img, outputCanvas, config, callback}) => { +const louvre = async ({img, outputCanvas, config}) => { if (!img || !config) return; const configString = [ @@ -149,7 +149,7 @@ const louvre = async ({img, outputCanvas, config, callback}) => { // 载入纹理 pencilTextureCanvas.width = _width; pencilTextureCanvas.height = _height; - const pencilTextureCtx = pencilTextureCanvas.getContext('2d'); + const pencilTextureCtx = pencilTextureCanvas.getContext('2d', { willReadFrequently: true }); const pencilSetWidthHeight = Math.max(_width,_height); pencilTextureCtx.drawImage( pencilTextureEl, @@ -180,7 +180,7 @@ const louvre = async ({img, outputCanvas, config, callback}) => { // /* // document.body.appendChild(canvasShade) - const ctxShade = canvasShade.getContext('2d'); + const ctxShade = canvasShade.getContext('2d', { willReadFrequently: true }); const ctxShadeMin = canvasShadeMin.getContext('2d'); canvasShade.width = _width; diff --git a/html/manifest.json b/html/manifest.json index 111cc51..0c1e613 100644 --- a/html/manifest.json +++ b/html/manifest.json @@ -2,14 +2,15 @@ "name": "One Last Image", "short_name": "One Last Image", "description": "卢浮宫生成器 - One Last Kiss 封面风格生成器", - "background_color": "#c3c3c3", - "display": "browser", + "background_color": "#C3C3C3", + "theme_color": "#FFFFFF", + "start_url": "index.html", + "display": "standalone", "icons": [ { - "src": "icon.jpg", - "sizes": "602x602", - "type": "image/jpeg" + "src": "icon.jpg", + "sizes": "602x602", + "type": "image/jpeg" } - ], - "start_url": "/pwa-examples/a2hs/index.html" + ] } \ No newline at end of file diff --git a/html/sw.js b/html/sw.js new file mode 100644 index 0000000..7c73e34 --- /dev/null +++ b/html/sw.js @@ -0,0 +1,43 @@ +'use strict'; + +const LOUVER_CACHE = 'louver-pwa' + +const ASSETS = [ + '/', + '/index.html', + '/bezier-easing.js', + '/color.js', + '/document.css', + '/document.js', + '/icon.jpg', + '/images/asuka-11.jpg', + '/images/asuka-8.jpg', + '/images/asuka.jpg', + '/logo-loading.svg', + '/louvre.js', + '/lyric.js', + '/manifest.json', + '/one-last-image-logo2.png', + '/one-last-image-sans.svg', + '/one-last-kiss.lrc', + '/pencil-texture.jpg', + '/ui-switch.vue.js', + '/ui-tabs.vue.js', + '/vue.2.6.11.min.js' +] + +self.addEventListener('install', (installEvent /** @type {ExtendableEvent} */) => { + installEvent.waitUntil( + caches.open(LOUVER_CACHE).then(cache => { + cache.addAll(ASSETS) + }) + ) +}) + +self.addEventListener('fetch', (fetchEvent /** @type {FetchEvent} */) => { + fetchEvent.respondWith( + caches.match(fetchEvent.request).then(res => { + return res || fetch(fetchEvent.request) + }) + ) +}) \ No newline at end of file diff --git a/html/ui-tabs.vue.js b/html/ui-tabs.vue.js index e8f8b97..dc1741b 100644 --- a/html/ui-tabs.vue.js +++ b/html/ui-tabs.vue.js @@ -1,22 +1,22 @@ -Vue.component('ui-tabs',{ +Vue.component('ui-tabs', { template: ` `, - props:{ - value: [String,Number], + props: { + value: [String, Number], options: Array }, computed: { - _options(){ - const {options} = this; - if(options.constructor === Object){ - return Object.entries(options).map(option=>({ + _options() { + const { options } = this; + if (options.constructor === Object) { + return Object.entries(options).map(option => ({ value: option[0], text: option[1], })) } - return options.map(option=>{ - if(option.constructor === String){ + return options.map(option => { + if (option.constructor === String) { return { value: option, text: option @@ -27,9 +27,9 @@ Vue.component('ui-tabs',{ }) } }, - methods:{ - set(v){ - this.$emit('input',v); + methods: { + set(v) { + this.$emit('input', v); } } }) \ No newline at end of file