动漫之家漫画页转长图

打开某一话后点击标题右侧按钮生成长图(仅为用于熟人间分享),需要与网络请求修改类浏览器扩展配合

질문, 리뷰하거나, 이 스크립트를 신고하세요.
// ==UserScript==
// @name         动漫之家漫画页转长图
// @namespace    https://unlucky.ninja/
// @version      2024.06.18.2
// @description  打开某一话后点击标题右侧按钮生成长图(仅为用于熟人间分享),需要与网络请求修改类浏览器扩展配合
// @author       UnluckyNinja
// @license      MIT
// @match        https://manhua.idmzj.com/*
// @match        https://manhua.dmzj.com/*
// @require      https://code.jquery.com/jquery-3.7.1.slim.min.js
// @require      https://update.greasyfork.org/scripts/498113/1395364/waitForKeyElements_mirror.js
// @icon         https://www.google.com/s2/favicons?sz=64&domain=idmzj.com
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // consts
    const CANVAS_WIDTH = 800
    const JPG_QUALITY = 0.5

    // return tarB in tarA/tarB=srcA/srcB
    function toRatioValue(srcA, srcB, tarA){
        return tarA/srcA * srcB
    }

    function getTotalHeight(images, width = 800){
        let totalH = 0
        for (let image of images){
            const w = image.naturalWidth
            const h = image.naturalHeight
            totalH += Math.ceil(toRatioValue(w, h, width))
        }
        return totalH
    }

    async function genLongImageBlob(){
        const images = [...document.querySelectorAll(".comic_wraCon img").values()]
        const canvas = document.createElement('canvas')
        const totalHeight = getTotalHeight(images, CANVAS_WIDTH)
        let targetWidth = CANVAS_WIDTH
        if (totalHeight > 32767) {
            let optimalWidth = Math.floor(32767 / totalHeight * CANVAS_WIDTH)
            const conti = confirm(`高度超出生成上限: ${totalHeight} / 32767, 若继续生成,则图片宽度将只有:${optimalWidth.toFixed(0)}px,是否继续生成?`)
            if (!conti) throw new Error('高度过大无法绘制')
            targetWidth = optimalWidth
        }
        canvas.width = targetWidth
        canvas.height = getTotalHeight(images, targetWidth)
        const context = canvas.getContext('2d')
        let curH = 0
        const promises = images.map(it=>it.decode())
        await Promise.all(promises)
        for (let image of images){
            const w = image.naturalWidth
            const h = image.naturalHeight
            const newH = Math.ceil(toRatioValue(w, h, targetWidth))
            console.log(canvas.width)
            console.log(canvas.height)
            context.drawImage(image, 0, curH, targetWidth, newH)
            curH += newH
        }
        return new Promise((resolve)=>{
            canvas.toBlob((blob)=>{
                resolve(blob)
            }, 'image/jpeg', JPG_QUALITY)
        })
    }
    let downloadButton
    let previewButton

    async function openImage(){
        previewButton.innerText = '生成中...'
        previewButton.disabled = true
        try {
            const blob = await genLongImageBlob()
            const url = URL.createObjectURL(blob)
            window.open(url, '_blank')
            setTimeout(()=>{
                URL.revokeObjectURL(url)
            }, 10000)
        } finally {
            previewButton.innerText = '预览长图'
            previewButton.disabled = false
        }
    }
    async function downloadImage(){
        downloadButton.innerText = '生成中...'
        downloadButton.disabled = true
        try {
            const blob = await genLongImageBlob()
            const url = URL.createObjectURL(blob)
            const a = document.createElement('a')
            a.href = url
            const name = document.querySelector('.comic_wraCon h1').textContent
            const chapter = document.querySelector('.comic_wraCon h1 ~ span').textContent
            a.download = `${name}_${chapter}.jpg`
            a.click()
            setTimeout(()=>{
                URL.revokeObjectURL(url)
            }, 0)
        } finally {
            downloadButton.innerText = '下载长图'
            downloadButton.disabled = false
        }
    }

    function addButton(node){
        const wrapper = document.createElement('span')
        wrapper.style.position = 'relative'
        const div = document.createElement('div')
        div.style.display = 'flex'
        div.style.position = 'absolute'
        div.style.width = 'max-content'
        div.style.height = '100%'
        div.style.left = '100%'
        div.style.top = '0'

        previewButton = document.createElement('button')
        previewButton.innerText = '预览长图'
        previewButton.style.margin = '0 0.5rem'
        previewButton.addEventListener('click', openImage)
        div.append(previewButton)

        downloadButton = document.createElement('button')
        downloadButton.innerText = '下载长图'
        //downloadButton.style.margin = '0 0.5rem'
        downloadButton.addEventListener('click', downloadImage)
        div.append(downloadButton)

        wrapper.append(div)
        node[0].parentElement.append(wrapper)
    }

    waitForKeyElements('.comic_wraCon img', (images)=>{
        if (!window.location.href.match(/https?:\/\/manhua.i?dmzj.com\/.*\/.*.shtml.*/)) return
        images[0].crossOrigin = 'anonymous'
    })
    waitForKeyElements('.comic_wraCon h1', (nodes)=>{
        if (!window.location.href.match(/https?:\/\/manhua.i?dmzj.com\/.*\/.*.shtml.*/)) return
        addButton(nodes)
    })
})();