<commit_before>/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.wizzardo.tools;

import com.wizzardo.tools.image.JpegEncoder;
import com.wizzardo.tools.image.Lanczos3Filter;
import com.wizzardo.tools.image.ResampleOp;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.image.*;
import java.io.*;
import java.util.concurrent.CountDownLatch;

/**
 * @author Moxa
 */
public class ImageTools {

    public static BufferedImage toGrayScale2(BufferedImage source) {
        BufferedImageOp op = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
        BufferedImage im = new BufferedImage(source.getWidth(), source.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
        op.filter(source, im);
        return im;
    }

    public static BufferedImage toGrayScale(BufferedImage source) {
        BufferedImage im = new BufferedImage(source.getWidth(), source.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
        im.getGraphics().drawImage(source, 0, 0, null);
        return im;
    }

    public static void saveJPG(BufferedImage im, String file, int quality) throws IOException {
        saveJPG(im, new FileOutputStream(file), quality);
    }

    public static void saveJPG(BufferedImage im, File file, int quality) throws IOException {
        saveJPG(im, new FileOutputStream(file), quality);
    }

    public static byte[] saveJPGtoBytes(BufferedImage im, int quality) throws IOException {
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        saveJPG(im, bytes, quality);
        return bytes.toByteArray();
    }

    public static void saveJPG(BufferedImage im, OutputStream out, int quality) throws IOException {
        JpegEncoder encoder = new JpegEncoder(im, quality, out);
        encoder.Compress();
        out.close();
    }

    public static void savePNG(BufferedImage im, String file) throws IOException {
        ImageIO.write(im, "png", new File(file));
    }

    public static void savePNG(BufferedImage im, File file) throws IOException {
        ImageIO.write(im, "png", file);
    }

    public static void savePNG(BufferedImage im, OutputStream out) throws IOException {
        ImageIO.write(im, "png", out);
    }

    public static byte[] savePNGtoBytes(BufferedImage im) throws IOException {
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        ImageIO.write(im, "png", bytes);
        return bytes.toByteArray();
    }

    public static BufferedImage crop(BufferedImage src, int x1, int y1, int x2, int y2) {
        int x = x1 > x2 ? x2 : x1;
        int y = y1 > y2 ? y2 : y1;
        return src.getSubimage(x, y, Math.abs(x2 - x1), Math.abs(y2 - y1));
    }

    public static BufferedImage read(File f) throws IOException {
        if (f.getName().toLowerCase().endsWith("jpg")) {
            try {
                return readByToolkit(f, BufferedImage.TYPE_INT_RGB);
            } catch (Exception ignored) {
            }
        }
        return ImageIO.read(f);
    }

    public static BufferedImage read(byte[] bytes) throws IOException {
        return ImageIO.read(new ByteArrayInputStream(bytes));
    }

    public static BufferedImage read(InputStream in) throws IOException {
        return ImageIO.read(in);
    }

    public static BufferedImage read(File f, int imageType) throws IOException {
        try {
            return readByToolkit(f, imageType);
        } catch (Exception ignored) {
        }
        return ImageIO.read(f);
    }

    public static BufferedImage read(String f) throws IOException {
        return read(new File(f));
    }

    public static BufferedImage read(String f, int imageType) throws IOException {
        return read(new File(f), imageType);
    }

    private static class LoadListener implements ImageObserver {
        private CountDownLatch latch = new CountDownLatch(1);

        @Override
        public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
            if (infoflags != ALLBITS)
                return true;
            latch.countDown();
            return false;
        }

        public void await() throws InterruptedException {
            latch.await();
        }
    }

    private static BufferedImage readByToolkit(File f, int imageType) throws IOException, InterruptedException {
        Image image = Toolkit.getDefaultToolkit().createImage(f.getAbsolutePath());
        LoadListener obs = new LoadListener();
        Toolkit.getDefaultToolkit().prepareImage(image, -1, -1, obs);
        obs.await();
        while (image.getWidth(null) < 0)
            try {
                Thread.sleep(1);
            } catch (InterruptedException ignored) {
            }
        BufferedImage img = new BufferedImage(image.getWidth(null), image.getHeight(null), imageType);
        Graphics g = img.getGraphics();
        g.drawImage(image, 0, 0, null);
        g.dispose();
        return img;
    }

    public static BufferedImage trim(BufferedImage src) {
        return trim(src, 0);
    }

    public static BufferedImage trim(BufferedImage src, int diff) {
        return trimHorizontal(trimVertical(src, diff), diff);
    }

    public static BufferedImage trimHorizontal(BufferedImage src) {
        return trimHorizontal(src, 0);
    }

    public static BufferedImage trimVertical(BufferedImage src) {
        return trimVertical(src, 0);
    }

    public static BufferedImage trimHorizontal(BufferedImage src, int diff) {
        int color = src.getRGB(0, 0);
        boolean clear = true;
        int x;
        for (x = 0; x < src.getWidth() && clear; x++) {
            int y = 0;
            while (clear && y < src.getHeight()) {<commit_msg>add CMYK reading support<commit_after>/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.wizzardo.tools;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageDecoder;
import com.wizzardo.tools.image.JpegEncoder;
import com.wizzardo.tools.image.Lanczos3Filter;
import com.wizzardo.tools.image.ResampleOp;
import com.wizzardo.tools.io.FileTools;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.color.ICC_ColorSpace;
import java.awt.color.ICC_Profile;
import java.awt.image.*;
import java.io.*;

/**
 * @author Moxa
 */
public class ImageTools {
    private static ICC_Profile CMYK_PROFILE;

    public static void setCmykProfile(File iccProfile) throws IOException {
        setCmykProfile(new FileInputStream(iccProfile));
    }

    public static void setCmykProfile(InputStream iccProfile) throws IOException {
        CMYK_PROFILE = ICC_Profile.getInstance(iccProfile);
    }

    public static BufferedImage toGrayScale2(BufferedImage source) {
        BufferedImageOp op = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
        BufferedImage im = new BufferedImage(source.getWidth(), source.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
        op.filter(source, im);
        return im;
    }

    public static BufferedImage toGrayScale(BufferedImage source) {
        BufferedImage im = new BufferedImage(source.getWidth(), source.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
        im.getGraphics().drawImage(source, 0, 0, null);
        return im;
    }

    public static void saveJPG(BufferedImage im, String file, int quality) throws IOException {
        saveJPG(im, new FileOutputStream(file), quality);
    }

    public static void saveJPG(BufferedImage im, File file, int quality) throws IOException {
        saveJPG(im, new FileOutputStream(file), quality);
    }

    public static byte[] saveJPGtoBytes(BufferedImage im, int quality) throws IOException {
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        saveJPG(im, bytes, quality);
        return bytes.toByteArray();
    }

    public static void saveJPG(BufferedImage im, OutputStream out, int quality) throws IOException {
        JpegEncoder encoder = new JpegEncoder(im, quality, out);
        encoder.Compress();
        out.close();
    }

    public static void savePNG(BufferedImage im, String file) throws IOException {
        ImageIO.write(im, "png", new File(file));
    }

    public static void savePNG(BufferedImage im, File file) throws IOException {
        ImageIO.write(im, "png", file);
    }

    public static void savePNG(BufferedImage im, OutputStream out) throws IOException {
        ImageIO.write(im, "png", out);
    }

    public static byte[] savePNGtoBytes(BufferedImage im) throws IOException {
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        ImageIO.write(im, "png", bytes);
        return bytes.toByteArray();
    }

    public static BufferedImage crop(BufferedImage src, int x1, int y1, int x2, int y2) {
        int x = x1 > x2 ? x2 : x1;
        int y = y1 > y2 ? y2 : y1;
        return src.getSubimage(x, y, Math.abs(x2 - x1), Math.abs(y2 - y1));
    }

    public static BufferedImage read(File f) throws IOException {
        return read(FileTools.bytes(f));
    }

    public static BufferedImage read(byte[] bytes) throws IOException {
        if (CMYK_PROFILE == null)
            return read(new ByteArrayInputStream(bytes));

        try {
            return ImageIO.read(new ByteArrayInputStream(bytes));
        } catch (javax.imageio.IIOException e) {
            return readAndConvertFromCMYK(new ByteArrayInputStream(bytes));
        }
    }

    public static BufferedImage read(InputStream in) throws IOException {
        return ImageIO.read(in);
    }

    public static BufferedImage readAndConvertFromCMYK(InputStream in) throws IOException {
        if (CMYK_PROFILE == null)
            throw new IOException("You need to setup CMYK profile first by method setCmykProfile");
        return readAndConvertFromCMYK(in, CMYK_PROFILE);
    }

    public static BufferedImage readAndConvertFromCMYK(InputStream in, ICC_Profile cmykProfile) throws IOException {
        JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(in);
        BufferedImage src = decoder.decodeAsBufferedImage();
        WritableRaster srcRaster = src.getRaster();
        //prepare result image
        BufferedImage result = new BufferedImage(srcRaster.getWidth(), srcRaster.getHeight(), BufferedImage.TYPE_INT_RGB);
        WritableRaster resultRaster = result.getRaster();
        //prepare icc profiles
        ColorSpace sRGBColorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);

        //invert k channel
        for (int x = srcRaster.getMinX(); x < srcRaster.getWidth(); x++) {
            for (int y = srcRaster.getMinY(); y < srcRaster.getHeight(); y++) {
                float[] pixel = srcRaster.getPixel(x, y, (float[]) null);
                pixel[3] = 255f - pixel[3];
                srcRaster.setPixel(x, y, pixel);
            }
        }
        //convert
        ColorConvertOp cmykToRgb = new ColorConvertOp(new ICC_ColorSpace(cmykProfile), sRGBColorSpace, null);
        cmykToRgb.filter(srcRaster, resultRaster);
        return result;
    }

    public static BufferedImage read(String f) throws IOException {
        return read(new File(f));
    }

    public static BufferedImage trim(BufferedImage src) {
        return trim(src, 0);
    }

    public static BufferedImage trim(BufferedImage src, int diff) {
        return trimHorizontal(trimVertical(src, diff), diff);
    }

    public static BufferedImage trimHorizontal(BufferedImage src) {
        return trimHorizontal(src, 0);
    }

    public static BufferedImage trimVertical(BufferedImage src) {
        return trimVertical(src, 0);
    }

    public static BufferedImage trimHorizontal(BufferedImage src, int diff) {
        int color = src.getRGB(0, 0);
        boolean clear = true;
        int x;
        for (x = 0; x < src.getWidth() && clear; x++) {
            int y = 0;
            while (clear && y < src.getHeight()) {
{'fraction_non_alphanumeric': 0.09707203460322741, 'fraction_numerical': 0.0054899351189485945, 'mean_word_length': 2.9086475942782837, 'pattern_counts': {'":': 0, '<': 10, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2542421', 'n_tokens_mistral': 3498, 'n_tokens_neox': 3409, 'n_words': 938}