Greasy Fork is available in English.

Resize Image Downloader

Download resized version of single-image pages

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey, το Greasemonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

You will need to install an extension such as Tampermonkey to install this script.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Userscripts για να εγκαταστήσετε αυτόν τον κώδικα.

You will need to install an extension such as Tampermonkey to install this script.

Θα χρειαστεί να εγκαταστήσετε μια επέκταση διαχείρισης κώδικα χρήστη για να εγκαταστήσετε αυτόν τον κώδικα.

(Έχω ήδη έναν διαχειριστή κώδικα χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Έχω ήδη έναν διαχειριστή στυλ χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

// ==UserScript==
// @name         Resize Image Downloader
// @version      2.0
// @author       SleepingGiant
// @description  Download resized version of single-image pages
// @namespace    https://greasyfork.org/users/1395131
// @match        *://*/*.jpg
// @match        *://*/*.jpeg
// @match        *://*/*.png
// @match        *://*/*.webp
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    let cropLines = {};
    let cropOverlay = null;
    let infoBox = null;

    const createUI = () => {
        const container = document.createElement('div');
        container.style.position = 'fixed';
        container.style.top = '20px';
        container.style.right = '20px';
        container.style.backgroundColor = '#222';
        container.style.color = 'white';
        container.style.padding = '10px';
        container.style.borderRadius = '10px';
        container.style.zIndex = '9999';
        container.style.display = 'flex';
        container.style.flexDirection = 'column';
        container.style.gap = '6px';
        container.style.fontSize = '13px';

        const createLabeledInput = (labelText, defaultValue) => {
            const wrapper = document.createElement('div');
            wrapper.style.display = 'flex';
            wrapper.style.alignItems = 'center';
            wrapper.style.gap = '4px';

            const label = document.createElement('label');
            label.textContent = labelText;
            const input = document.createElement('input');
            input.type = 'number';
            input.value = defaultValue;
            input.style.width = '60px';
            input.style.padding = '4px';
            input.style.borderRadius = '4px';
            input.style.border = 'none';

            wrapper.appendChild(label);
            wrapper.appendChild(input);
            container.appendChild(wrapper);

            return input;
        };

        const widthInput = createLabeledInput('Width:', 1200);
        const heightInput = createLabeledInput('Height:', 1200);

        // Crop toggle checkbox
        const cropToggle = document.createElement('label');
        cropToggle.style.display = 'flex';
        cropToggle.style.alignItems = 'center';
        cropToggle.style.gap = '6px';
        const cropCheckbox = document.createElement('input');
        cropCheckbox.type = 'checkbox';
        cropCheckbox.checked = false;
        cropCheckbox.onchange = () => {
            if (cropCheckbox.checked) {
                const img = document.querySelector('img');
                if (img) createCropOverlay(img);
            } else {
                removeCropOverlay();
            }
        };
        cropToggle.appendChild(cropCheckbox);
        cropToggle.appendChild(document.createTextNode('Enable Crop'));
        container.appendChild(cropToggle);

        // Scaling toggle checkbox
        const scaleToggle = document.createElement('label');
        scaleToggle.style.display = 'flex';
        scaleToggle.style.alignItems = 'center';
        scaleToggle.style.gap = '6px';
        const scaleCheckbox = document.createElement('input');
        scaleCheckbox.type = 'checkbox';
        scaleCheckbox.checked = true;
        scaleToggle.appendChild(scaleCheckbox);
        scaleToggle.appendChild(document.createTextNode('Enable Scaling'));
        container.appendChild(scaleToggle);


        // Download button
        const downloadBtn = document.createElement('button');
        downloadBtn.textContent = '⬇️ Download';
        styleButton(downloadBtn);
        downloadBtn.onclick = () =>
            downloadCroppedAndResized(
                widthInput.value,
                heightInput.value,
                cropCheckbox.checked,
                scaleCheckbox.checked
            );


        container.appendChild(downloadBtn);
        document.body.appendChild(container);
    };

    const styleButton = (btn) => {
        btn.style.backgroundColor = '#007acc';
        btn.style.color = 'white';
        btn.style.border = 'none';
        btn.style.padding = '6px 10px';
        btn.style.borderRadius = '6px';
        btn.style.cursor = 'pointer';
        btn.style.fontSize = '13px';
    };

    const createCropOverlay = (img) => {
        const rect = img.getBoundingClientRect();

        cropOverlay = document.createElement('div');
        cropOverlay.style.position = 'absolute';
        cropOverlay.style.left = `${rect.left + window.scrollX}px`;
        cropOverlay.style.top = `${rect.top + window.scrollY}px`;
        cropOverlay.style.width = `${rect.width}px`;
        cropOverlay.style.height = `${rect.height}px`;
        cropOverlay.style.zIndex = '9998';
        cropOverlay.style.pointerEvents = 'none';

        document.body.appendChild(cropOverlay);

        const directions = ['left', 'right', 'top', 'bottom'];
        directions.forEach(dir => {
            const line = document.createElement('div');
            line.className = `crop-line ${dir}`;
            Object.assign(line.style, {
                position: 'absolute',
                backgroundColor: 'red',
                pointerEvents: 'auto',
                zIndex: '10000',
                cursor: dir === 'left' || dir === 'right' ? 'ew-resize' : 'ns-resize',
            });

            if (dir === 'left' || dir === 'right') {
                line.style.top = '0';
                line.style.width = '2px';
                line.style.height = '100%';
                line.style.left = dir === 'left' ? '10px' : `${rect.width - 10}px`;
            } else {
                line.style.left = '0';
                line.style.height = '2px';
                line.style.width = '100%';
                line.style.top = dir === 'top' ? '10px' : `${rect.height - 10}px`;
            }

            makeDraggable(line, dir, img, rect);
            cropOverlay.appendChild(line);
            cropLines[dir] = line;
        });

        // Info box
        infoBox = document.createElement('div');
        infoBox.style.position = 'fixed';
        infoBox.style.bottom = '20px';
        infoBox.style.left = '20px';
        infoBox.style.background = '#000a';
        infoBox.style.color = 'white';
        infoBox.style.padding = '6px 10px';
        infoBox.style.borderRadius = '8px';
        infoBox.style.fontSize = '13px';
        infoBox.style.zIndex = '9999';
        document.body.appendChild(infoBox);

        updateInfoBox(img, rect);
    };

    const removeCropOverlay = () => {
        if (cropOverlay) cropOverlay.remove();
        if (infoBox) infoBox.remove();
        cropOverlay = null;
        infoBox = null;
        cropLines = {};
    };

    const makeDraggable = (element, direction, img, imgRect) => {
        let isDragging = false;

        element.addEventListener('mousedown', (e) => {
            e.preventDefault();
            isDragging = true;

            const onMouseMove = (moveEvent) => {
                if (!isDragging) return;

                const delta = direction === 'left' || direction === 'right'
                    ? moveEvent.clientX - imgRect.left
                    : moveEvent.clientY - imgRect.top;

                if (direction === 'left' || direction === 'right') {
                    const clamped = Math.max(0, Math.min(delta, imgRect.width));
                    element.style.left = `${clamped}px`;
                } else {
                    const clamped = Math.max(0, Math.min(delta, imgRect.height));
                    element.style.top = `${clamped}px`;
                }

                updateInfoBox(img, imgRect);
            };

            const onMouseUp = () => {
                isDragging = false;
                document.removeEventListener('mousemove', onMouseMove);
                document.removeEventListener('mouseup', onMouseUp);
            };

            document.addEventListener('mousemove', onMouseMove);
            document.addEventListener('mouseup', onMouseUp);
        });
    };

    const getCropValues = (imgRect) => {
        const left = parseInt(cropLines.left?.style.left || '0');
        const right = parseInt(cropLines.right?.style.left || `${imgRect.width}`);
        const top = parseInt(cropLines.top?.style.top || '0');
        const bottom = parseInt(cropLines.bottom?.style.top || `${imgRect.height}`);

        const cropX = Math.min(left, right);
        const cropY = Math.min(top, bottom);
        const cropW = Math.abs(right - left);
        const cropH = Math.abs(bottom - top);

        return { cropX, cropY, cropW, cropH };
    };

    const updateInfoBox = (img, imgRect) => {
        const { cropX, cropY, cropW, cropH } = getCropValues(imgRect);
        const removedLeft = cropX;
        const removedTop = cropY;
        const removedRight = img.naturalWidth - (cropX + cropW);
        const removedBottom = img.naturalHeight - (cropY + cropH);

        infoBox.innerHTML = `
            <b>Crop</b><br/>
            Removed: Left ${removedLeft}px, Right ${removedRight}px<br/>
            Removed: Top ${removedTop}px, Bottom ${removedBottom}px<br/>
            Final: ${cropW} x ${cropH}px
        `;
    };

    const downloadCroppedAndResized = (newWidth, newHeight, cropEnabled, scaleEnabled) => {
        const img = document.querySelector('img');
        const rect = img.getBoundingClientRect();

        let cropX = 0, cropY = 0, cropW = img.naturalWidth, cropH = img.naturalHeight;

        if (cropEnabled && cropOverlay) {
            const values = getCropValues(rect);
            cropX = values.cropX * img.naturalWidth / rect.width;
            cropY = values.cropY * img.naturalHeight / rect.height;
            cropW = values.cropW * img.naturalWidth / rect.width;
            cropH = values.cropH * img.naturalHeight / rect.height;
        }

        const finalW = scaleEnabled ? parseInt(newWidth) : cropW;
        const finalH = scaleEnabled ? parseInt(newHeight) : cropH;

        const canvas = document.createElement('canvas');
        canvas.width = finalW;
        canvas.height = finalH;
        const ctx = canvas.getContext('2d');

        ctx.drawImage(img, cropX, cropY, cropW, cropH, 0, 0, finalW, finalH);

        canvas.toBlob(blob => {
            const link = document.createElement('a');
            link.href = URL.createObjectURL(blob);
            link.download = `cropped_scaled_${canvas.width}x${canvas.height}.jpg`;
            link.click();
        }, 'image/jpeg', 0.9);
    };


    const interval = setInterval(() => {
        const img = document.querySelector('img');
        if (img && document.body) {
            createUI();
            clearInterval(interval);
        }
    }, 200);
})();