/* * This file is part of OneConfig. * OneConfig - Next Generation Config Library for Minecraft: Java Edition * Copyright (C) 2021, 2022 Polyfrost. * * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * OneConfig is licensed under the terms of version 3 of the GNU Lesser * General Public License as published by the Free Software Foundation, AND * under the Additional Terms Applicable to OneConfig, as published by Polyfrost, * either version 1.0 of the Additional Terms, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License. If not, see . You should * have also received a copy of the Additional Terms Applicable * to OneConfig, as published by Polyfrost. If not, see * */ package cc.polyfrost.oneconfig.images; import cc.polyfrost.oneconfig.utils.IOUtils; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import javax.imageio.ImageIO; import java.awt.*; import java.awt.geom.AffineTransform; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.util.Base64; import java.util.Objects; /** An Image wrapper class that is used by the OneConfig system.*/ @SuppressWarnings("unused") public class OneImage { private static final Logger LOGGER = LogManager.getLogger("OneConfig Images"); private BufferedImage image; private Graphics2D graphics = null; private final int width, height; /** * Create a new OneImage from the file. This can be as a resource location inside your JAR. * @param filePath The path to the image file. */ public OneImage(String filePath) throws IOException { image = ImageIO.read(Objects.requireNonNull(OneImage.class.getResourceAsStream(filePath))); width = image.getWidth(); height = image.getHeight(); } /** * Create a new OneImage from the file. * @param is InputStream to the image file. */ public OneImage(InputStream is) throws IOException { image = ImageIO.read(is); width = image.getWidth(); height = image.getHeight(); } /** * Create a new OneImage from the file. * @param file File to the image file. */ public OneImage(File file) throws IOException { image = ImageIO.read(Objects.requireNonNull(file)); width = image.getWidth(); height = image.getHeight(); } /** * Create a new OneImage from the BufferedImage. */ public OneImage(BufferedImage image) { this.image = image; width = image.getWidth(); height = image.getHeight(); } /** Create a new blank image with the specified width and height. */ public OneImage(int width, int height) { this.width = width; this.height = height; image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); } /** Get the image as a BufferedImage. */ public BufferedImage getImage() { return image; } protected void setImage(BufferedImage img) { image = img; } /** Get the graphics object associated with the image. */ public Graphics2D getG2D() { if (graphics == null) { graphics = image.createGraphics(); graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); } return graphics; } /** Dispose of the graphics object. */ public void dispose() { if(graphics != null) { graphics.dispose(); graphics = null; } } /** Get the width of the image. */ public int getWidth() { return width; } /** Get the height of the image. */ public int getHeight() { return height; } /** Crop the image to the specified width and height. * @param startX The x coordinate of the top-left corner of the crop. * @param startY The y coordinate of the top-left corner of the crop. * @param width The width of the crop. * @param height The height of the crop. */ public void crop(int startX, int startY, int width, int height) { image = image.getSubimage(startX, startY, width, height); } /** Get the color of a pixel in the image. */ public void getColorAtPos(int x, int y) { image.getRGB(x, y); } /** Set the color of a pixel in the image. */ public void setColorAtPos(int x, int y, int argb) { image.setRGB(x, y, argb); } /** Attempt to save the image to the specified file. */ public void save(String filePath) throws IOException { ImageIO.write(image, "png", new File(filePath)); } /** Attempt to upload the image to Imgur, returning the JSON that the server replied with. */ public JsonObject uploadToImgur() { try { // thanks stack overflow for the help with this :_) URL url = new URL("https://api.imgur.com/3/image"); HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setDoInput(true); con.setDoOutput(true); con.setRequestMethod("POST"); con.setRequestProperty("Authorization", "Client-ID " + "6cfc432a9954f4d"); con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); con.connect(); ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); ImageIO.write(image, "png", byteOut); String encoded = URLEncoder.encode("image", "UTF-8") + "=" + URLEncoder.encode(Base64.getEncoder().encodeToString(byteOut.toByteArray()), "UTF-8"); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(con.getOutputStream())); writer.write(encoded); byteOut.close(); writer.close(); if(con.getResponseCode() != 200) { LOGGER.error("Error uploading image to Imgur: " + con.getResponseCode()); return null; } BufferedReader rd = new BufferedReader(new InputStreamReader(con.getInputStream())); JsonObject object = new JsonParser().parse(rd).getAsJsonObject(); rd.close(); return object; } catch (Exception e) { e.printStackTrace(); LOGGER.error("Error uploading image to Imgur."); return null; } } /** Attempt to upload the image to Imgur, returning the URL that the image is hosted at. * @param copy weather or not to copy the URL to the clipboard as well. */ public String uploadToImgur(boolean copy) { JsonObject object = uploadToImgur(); String link = object.get("data").getAsJsonObject().get("link").getAsString(); if(copy) IOUtils.copyStringToClipboard(link); return link; } /** Copy the image to the system clipboard and delete the graphics object. */ public void copyToClipboard() { IOUtils.copyImageToClipboard(image); dispose(); } // MASK METHODS public void setBrightness(float brightness) { maskColor(new Color(0f,0f,0f,brightness)); } public void maskColor(Color color) { Graphics2D g2d = getG2D(); g2d.setColor(color); g2d.fillRect(0,0,width,height); dispose(); } public void maskPaint(Paint paint) { Graphics2D g2d = getG2D(); g2d.setPaint(paint); g2d.fillRect(0,0,width,height); dispose(); } // LINE METHODS public void drawLine(Stroke stroke, int sx, int sy, int ex, int ey) { Graphics2D g2d = getG2D(); g2d.setStroke(stroke); g2d.drawLine(sx, sy, ex, ey); dispose(); } public void drawLine(int sx, int sy, int ex, int ey, int width) { drawLine(new BasicStroke(width), sx, sy, ex, ey); } // SHAPE METHODS public void drawTexturedRect(TexturePaint paint, int x, int y, int width, int height) { Graphics2D g2d = getG2D(); g2d.setPaint(paint); g2d.fillRect(x, y, width, height); dispose(); } public void drawRect(int x, int y, int width, int height, int color) { Graphics2D g2d = getG2D(); g2d.setColor(new Color(color, true)); g2d.drawRect(x, y, width, height); dispose(); } public void drawRoundedRect(int x, int y, int width, int height, int radius, int color) { Graphics2D g2d = getG2D(); g2d.setColor(new Color(color, true)); g2d.fillRoundRect(x, y, width, height, radius, radius); dispose(); } public void drawPolygon(int x, int y, Polygon polygon, int color) { Graphics2D g2d = getG2D(); g2d.setColor(new Color(color, true)); g2d.translate(x, y); g2d.fillPolygon(polygon); dispose(); } public void drawOval(int x, int y, int width, int height, int color) { Graphics2D g2d = getG2D(); g2d.setColor(new Color(color, true)); g2d.fillOval(x, y, width, height); dispose(); } public void drawTriangle(Point p1, Point p2, Point p3, int color) { Graphics2D g2d = getG2D(); g2d.setColor(new Color(color, true)); g2d.fillPolygon(new int[] {p1.x, p2.x, p3.x}, new int[] {p1.y, p2.y, p3.y}, 3); dispose(); } public void drawCircle(int x, int y, int radius, int color) { Graphics2D g2d = getG2D(); g2d.setColor(new Color(color, true)); g2d.fillRoundRect(x, y, radius, radius, radius, radius); dispose(); } // STRING METHODS public void drawString(String text, int x, int y, Font font, int color) { Graphics2D g2d = getG2D(); g2d.setColor(new Color(color, true)); g2d.setFont(font); g2d.drawString(text, x, y); dispose(); } // IMAGE METHODS /** Scale the image by the given factor (1.0 = no change). */ public void scale(double sx, double sy) { if(sx == 1.0 && sy == 1.0) return; BufferedImage old = image; image = new BufferedImage((int) (Math.abs(sx * image.getWidth())), (int) (Math.abs(image.getHeight() * sy)), BufferedImage.TYPE_INT_ARGB); Graphics2D g2d = getG2D(); g2d.drawImage(old, new AffineTransformOp(AffineTransform.getScaleInstance(sx, sy), AffineTransformOp.TYPE_BILINEAR), 0, 0); dispose(); } /** * Scale the image to the specified width and height. */ public void setSize(int width, int height) { if(width == this.width && height == this.height) return; scale(width / (double) this.width, height / (double) this.height); } /** Rotate the image by the given angle (in degrees). */ public void rotate(double angle) { if(angle == 0 || angle == 360) return; Graphics2D g2d = getG2D(); g2d.drawImage(image, new AffineTransformOp(AffineTransform.getRotateInstance(Math.toRadians(angle)), AffineTransformOp.TYPE_BILINEAR), 0, 0); dispose(); } /** Translate the image by the given amount. */ public void translate(int moveX, int moveY) { Graphics2D g2d = getG2D(); g2d.drawImage(image, new AffineTransformOp(AffineTransform.getTranslateInstance(moveX, moveY), AffineTransformOp.TYPE_BILINEAR), 0, 0); dispose(); } /** Flip the image horizontally. */ public void flipHorizontal() { scale(-1, 1); } /** Flip the image vertically. */ public void flipVertical() { scale(1, -1); } }