Greasy Fork

Greasy Fork is available in English.

动漫之家漫画页转长图

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

当前为 2024-06-21 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==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.icu/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)
    })
})();