<commit_before>/*
 * Copyright (c) www.bugull.com
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.bugull.mongo.fs;

import com.bugull.mongo.utils.StreamUtil;
import com.bugull.mongo.utils.StringUtil;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.gridfs.GridFSDBFile;
import java.awt.AlphaComposite;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import javax.imageio.ImageIO;

/**
 * Convenient class for uploading an image file to GridFS.
 * 
 * <p>Besides uploading, ImageUploader can watermark and compress an image.</p>
 * 
 * @author <NAME>(<EMAIL>)
 */
public class ImageUploader extends Uploader{
    
    public final static String DIMENSION = "dimension";
    
    public ImageUploader(File file, String originalName){
        super(file, originalName);
    }
    
    public ImageUploader(File file, String originalName, boolean rename){
        super(file, originalName, rename);
    }
    
    public ImageUploader(InputStream input, String originalName){
        super(input, originalName);
    }
    
    public ImageUploader(InputStream input, String originalName, boolean rename){
        super(input, originalName, rename);
    }
    
    public ImageUploader(byte[] data, String originalName){
        super(data, originalName);
    }
    
    public ImageUploader(byte[] data, String originalName, boolean rename){
        super(data, originalName, rename);
    }
    
    /**
     * Save the image with a watermark on it.
     * @param watermark 
     * @return the file(with watermark on it) id generated by MongoDB.
     */
    public String save(Watermark watermark){
        processFilename();
        String fid = null;
        if(!StringUtil.isEmpty(watermark.getText())){
            fid = pressText(watermark);
        }
        else if(!StringUtil.isEmpty(watermark.getImagePath())){
            fid = pressImage(watermark);
        }
        else{
            fid = saveInputStream();
        }
        return fid;
    }
    
    private String pressText(Watermark watermark){
        BufferedImage originalImage = openImage(input);
        int originalWidth = originalImage.getWidth(null);
        int originalHeight = originalImage.getHeight(null);
        BufferedImage newImage = new BufferedImage(originalWidth, originalHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = newImage.createGraphics();
        g.drawImage(originalImage, 0, 0, originalWidth, originalHeight, null);
        g.setColor(watermark.getColor());
        g.setFont(new Font(watermark.getFontName(), watermark.getFontStyle(), watermark.getFontSize())); 
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, watermark.getAlpha())); 
        String text = watermark.getText();
        int len = text.length();
        int fontSize = watermark.getFontSize();
        switch(watermark.getAlign()){
            case Watermark.CENTER:
                g.drawString(text, (originalWidth - (len * fontSize)) / 2, (originalHeight - fontSize) / 2);
                break;
            case Watermark.BOTTOM_RIGHT:
                g.drawString(text, originalWidth - (len * fontSize) - watermark.getRight(), originalHeight - fontSize - watermark.getBottom());
                break;
            case Watermark.BOTTOM_LEFT:
                g.drawString(text, watermark.getLeft(), originalHeight - fontSize - watermark.getBottom());
                break;
            default:
                break;
        }
        g.dispose();
        return saveImage(newImage);
    }
    
    private String pressImage(Watermark watermark){
        BufferedImage originalImage = openImage(input);
        BufferedImage watermarkImage = openImage(new File(watermark.getImagePath()));
        int originalWidth = originalImage.getWidth(null);
        int originalHeight = originalImage.getHeight(null);
        int watermarkWidth = watermarkImage.getWidth(null);
        int watermarkHeight = watermarkImage.getHeight(null);
        if (originalWidth < watermarkWidth || originalHeight < watermarkHeight) {
            return saveInputStream();
        }
        BufferedImage newImage = new BufferedImage(originalWidth, originalHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = newImage.createGraphics();
        g.drawImage(originalImage, 0, 0, originalWidth, originalHeight, null);
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, watermark.getAlpha())); 
        //position of the watermark
        switch(watermark.getAlign()){
            case Watermark.CENTER:
                g.drawImage(watermarkImage, (originalWidth - watermarkWidth) / 2, (originalHeight - watermarkHeight) / 2, watermarkWidth, watermarkHeight, null);
                break;
            case Watermark.BOTTOM_RIGHT:
                g.drawImage(watermarkImage, originalWidth - watermarkWidth - watermark.getRight(), originalHeight - watermarkHeight - watermark.getBottom(), watermarkWidth, watermarkHeight, null);
                break;
            case Watermark.BOTTOM_LEFT:
                g.drawImage(watermarkImage, watermark.getLeft(), originalHeight - watermarkHeight - watermark.getBottom(), watermarkWidth, watermarkHeight, null);
                break;
            default:
                break;
        }
        g.dispose();
        return saveImage(newImage);
    }
    
    /**
     * compress the image to another dimension
     * @param dimension
     * @param maxWidth
     * @param maxHeight
     * @return the compressed file id generated by MongoDB.
     */
    public String compress(String dimension, int maxWidth, int maxHeight) {
        setAttribute(DIMENSION, dimension);
        BufferedImage srcImage = openImage(getOriginalInputStream());
        int srcWidth = srcImage.getWidth(null);
        int srcHeight = srcImage.getHeight(null);
        if(srcWidth <= maxWidth && srcHeight <= maxHeight){
            return saveImage(srcImage);
        }
        double ratio = Math.min((double) maxWidth / srcWidth, (double) maxHeight / srcHeight);
        int targetWidth = (int)(srcWidth * ratio);
        int targetHeight = (int)(srcHeight * ratio);
        BufferedImage targetImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB);
        Image img = srcImage.getScaledInstance(targetWidth, targetHeight, Image.SCALE_SMOOTH);
        Graphics g = targetImage.getGraphics();
        g.drawImage(img, 0, 0, targetWidth, targetHeight, null);
        g.dispose();
        return saveImage(targetImage);
    }
    
    private InputStream getOriginalInputStream(){
        DBObject query = new BasicDBObject(BuguFS.FILENAME, filename);
        query.put(DIMENSION, null);
        BuguFS fs = BuguFSFactory.getInstance().create(connection, bucket, chunkSize);
        GridFSDBFile f = fs.findOne(query);
        return f.getInputStream();<commit_msg>support filling style when compress image<commit_after>/*
 * Copyright (c) www.bugull.com
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.bugull.mongo.fs;

import com.bugull.mongo.utils.StreamUtil;
import com.bugull.mongo.utils.StringUtil;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.gridfs.GridFSDBFile;
import java.awt.AlphaComposite;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import javax.imageio.ImageIO;

/**
 * Convenient class for uploading an image file to GridFS.
 * 
 * <p>Besides uploading, ImageUploader can watermark and compress an image.</p>
 * 
 * @author <NAME>(<EMAIL>)
 */
public class ImageUploader extends Uploader{
    
    public final static String DIMENSION = "dimension";
    
    public ImageUploader(File file, String originalName){
        super(file, originalName);
    }
    
    public ImageUploader(File file, String originalName, boolean rename){
        super(file, originalName, rename);
    }
    
    public ImageUploader(InputStream input, String originalName){
        super(input, originalName);
    }
    
    public ImageUploader(InputStream input, String originalName, boolean rename){
        super(input, originalName, rename);
    }
    
    public ImageUploader(byte[] data, String originalName){
        super(data, originalName);
    }
    
    public ImageUploader(byte[] data, String originalName, boolean rename){
        super(data, originalName, rename);
    }
    
    /**
     * Save the image with a watermark on it.
     * @param watermark 
     * @return the file(with watermark on it) id generated by MongoDB.
     */
    public String save(Watermark watermark){
        processFilename();
        String fid = null;
        if(!StringUtil.isEmpty(watermark.getText())){
            fid = pressText(watermark);
        }
        else if(!StringUtil.isEmpty(watermark.getImagePath())){
            fid = pressImage(watermark);
        }
        else{
            fid = saveInputStream();
        }
        return fid;
    }
    
    private String pressText(Watermark watermark){
        BufferedImage originalImage = openImage(input);
        int originalWidth = originalImage.getWidth(null);
        int originalHeight = originalImage.getHeight(null);
        BufferedImage newImage = new BufferedImage(originalWidth, originalHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = newImage.createGraphics();
        g.drawImage(originalImage, 0, 0, originalWidth, originalHeight, null);
        g.setColor(watermark.getColor());
        g.setFont(new Font(watermark.getFontName(), watermark.getFontStyle(), watermark.getFontSize())); 
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, watermark.getAlpha())); 
        String text = watermark.getText();
        int len = text.length();
        int fontSize = watermark.getFontSize();
        switch(watermark.getAlign()){
            case Watermark.CENTER:
                g.drawString(text, (originalWidth - (len * fontSize)) / 2, (originalHeight - fontSize) / 2);
                break;
            case Watermark.BOTTOM_RIGHT:
                g.drawString(text, originalWidth - (len * fontSize) - watermark.getRight(), originalHeight - fontSize - watermark.getBottom());
                break;
            case Watermark.BOTTOM_LEFT:
                g.drawString(text, watermark.getLeft(), originalHeight - fontSize - watermark.getBottom());
                break;
            default:
                break;
        }
        g.dispose();
        return saveImage(newImage);
    }
    
    private String pressImage(Watermark watermark){
        BufferedImage originalImage = openImage(input);
        BufferedImage watermarkImage = openImage(new File(watermark.getImagePath()));
        int originalWidth = originalImage.getWidth(null);
        int originalHeight = originalImage.getHeight(null);
        int watermarkWidth = watermarkImage.getWidth(null);
        int watermarkHeight = watermarkImage.getHeight(null);
        if (originalWidth < watermarkWidth || originalHeight < watermarkHeight) {
            return saveInputStream();
        }
        BufferedImage newImage = new BufferedImage(originalWidth, originalHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = newImage.createGraphics();
        g.drawImage(originalImage, 0, 0, originalWidth, originalHeight, null);
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, watermark.getAlpha())); 
        //position of the watermark
        switch(watermark.getAlign()){
            case Watermark.CENTER:
                g.drawImage(watermarkImage, (originalWidth - watermarkWidth) / 2, (originalHeight - watermarkHeight) / 2, watermarkWidth, watermarkHeight, null);
                break;
            case Watermark.BOTTOM_RIGHT:
                g.drawImage(watermarkImage, originalWidth - watermarkWidth - watermark.getRight(), originalHeight - watermarkHeight - watermark.getBottom(), watermarkWidth, watermarkHeight, null);
                break;
            case Watermark.BOTTOM_LEFT:
                g.drawImage(watermarkImage, watermark.getLeft(), originalHeight - watermarkHeight - watermark.getBottom(), watermarkWidth, watermarkHeight, null);
                break;
            default:
                break;
        }
        g.dispose();
        return saveImage(newImage);
    }
    
    /**
     * compress the image to another dimension, not scale to filling
     * @param dimension
     * @param maxWidth
     * @param maxHeight
     * @return the compressed file id generated by MongoDB.
     */
    public String compress(String dimension, int maxWidth, int maxHeight) {
        return compress(dimension, maxWidth, maxHeight, false);
    }
    
    /**
     * compress the image to another dimension
     * @param dimension
     * @param maxWidth
     * @param maxHeight
     * @param filling fill the entire area or not
     * @return the compressed file id generated by MongoDB.
     */
    public String compress(String dimension, int maxWidth, int maxHeight, boolean filling) {
        setAttribute(DIMENSION, dimension);
        int targetWidth = maxWidth;
        int targetHeight = maxHeight;
        BufferedImage srcImage = openImage(getOriginalInputStream());
        if(!filling){
            int srcWidth = srcImage.getWidth(null);
            int srcHeight = srcImage.getHeight(null);
            if(srcWidth <= maxWidth && srcHeight <= maxHeight){
                return saveImage(srcImage);
            }
            double ratio = Math.min((double) maxWidth / srcWidth, (double) maxHeight / srcHeight);
            targetWidth = (int)(srcWidth * ratio);
            targetHeight = (int)(srcHeight * ratio);
        }
        BufferedImage targetImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB);
        Image img = srcImage.getScaledInstance(targetWidth, targetHeight, Image.SCALE_SMOOTH);
        Graphics g = targetImage.getGraphics();
        g.drawImage(img, 0, 0, targetWidth, targetHeight, null);
        g.dispose();
        return saveImage(targetImage);
    }
    
    private InputStream getOriginalInputStream(){
        DBObject query = new BasicDBObject(BuguFS.FILENAME, filename);
        query.put(DIMENSION, null);
        BuguFS fs = BuguFSFactory.getInstance().create(connection, bucket, chunkSize);
        GridFSDBFile f = fs.findOne(query);
        return f.getInputStream();
{'fraction_non_alphanumeric': 0.09575142675967026, 'fraction_numerical': 0.002155992390615092, 'mean_word_length': 2.824199806013579, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, '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': '3522767', 'n_tokens_mistral': 4287, 'n_tokens_neox': 4229, 'n_words': 1088}