diff --git a/src/main/java/tech/nevets/vcardgen/Location.java b/src/main/java/tech/nevets/vcardgen/Location.java new file mode 100644 index 0000000..1f8e816 --- /dev/null +++ b/src/main/java/tech/nevets/vcardgen/Location.java @@ -0,0 +1,86 @@ +package tech.nevets.vcardgen; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.FileReader; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +public class Location { + public static final List LOCATIONS = new ArrayList<>(); + + private final String id; + private final String name; + private final String address; + private final String number; + private transient BufferedImage background; + + public Location(String id, String name, String address, String number) throws IOException { + this.id = id; + this.name = name; + this.address = address; + this.number = number; + background = ImageIO.read(this.getClass().getResourceAsStream("/backgrounds/" + id + ".png")); + } + + public String getId() { + return id; + } + + public String getName() { + return name; + } + + public String getAddress() { + return address; + } + + public String getNumber() { + return number; + } + + public BufferedImage getBackground() { + return background; + } + + public void loadBackground() throws IOException { + URL backgroundURL = this.getClass().getResource("/backgrounds/" + id + ".png"); + if (backgroundURL == null) backgroundURL = this.getClass().getResource("/backgrounds/default.png"); + background = ImageIO.read(backgroundURL); + } + + public static void loadLocations () { + try { + Gson gson = new Gson(); + JsonArray jsonFile = gson.fromJson(new FileReader("./locations.json"), JsonArray.class); + for (JsonElement element : jsonFile.asList()) { + Location location = gson.fromJson(element, Location.class); + location.loadBackground(); + LOCATIONS.add(location); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static Location getLocation (String locationId){ + for (Location loc : LOCATIONS) { + if (loc.getId().equals(locationId)) { + return loc; + } + } + return null; + } + + @Override + public String toString() { + return "{ \"id\": " + id + ", \"name\": " + name + ", \"address\": " + address + ", \"number\": " + number + " }"; + } + +} \ No newline at end of file diff --git a/src/main/java/tech/nevets/vcardgen/Main.java b/src/main/java/tech/nevets/vcardgen/Main.java index 0b3aa5e..bc46384 100644 --- a/src/main/java/tech/nevets/vcardgen/Main.java +++ b/src/main/java/tech/nevets/vcardgen/Main.java @@ -1,40 +1,15 @@ package tech.nevets.vcardgen; import com.google.gson.Gson; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import javax.imageio.ImageIO; import java.io.*; -import java.util.List; -import java.awt.*; -import java.awt.image.BufferedImage; -import java.util.ArrayList; import static spark.Spark.*; public class Main { - - private static final Color WHITE = new Color(255, 255, 255); - private static final Color GREEN = new Color(101, 142, 61); - - private static final Font ARIAL65 = new Font("Arial", Font.PLAIN, 65); - private static final Font ARIAL55 = new Font("Arial", Font.PLAIN, 55); - private static final Font ARIAL45 = new Font("Arial", Font.PLAIN, 45); - private static final Font ARIAL45I = new Font("Arial", Font.ITALIC, 45); - private static final Font ARIAL44I = new Font("Arial", Font.ITALIC, 44); - private static final Font ARIAL40I = new Font("Arial", Font.ITALIC, 40); - private static final Font ARIAL38I = new Font("Arial", Font.ITALIC, 38); - - private static final List LOCATIONS = new ArrayList<>(); - public static void main(String[] args) { - loadLocations(); - - for (Location loc : LOCATIONS) { - System.out.println(loc); - } + Location.loadLocations(); port(8080); get("/heartbeat", (req, res) -> { @@ -54,187 +29,8 @@ public class Main { post("/", (req, res) -> { res.type("image/png"); res.header("Access-Control-Allow-Origin", "*"); - System.out.println(req.body()); JsonObject data = new Gson().fromJson(req.body(), JsonObject.class); - return generate( - data.get("name").getAsString(), - data.get("title").getAsString(), - data.get("email").getAsString(), - data.get("locationId").getAsString(), - data.get("extension").getAsString(), - data.get("directNumber").getAsString(), - data.get("cellNumber").getAsString(), - data.get("size").getAsInt() - ); + return new VCard(data).toByteArray(); }); - - } - - private static byte[] generate(String name, String title, String email, String locationId, String extension, String directNumber, String cellNumber, int size) { - Location loc = getLocation(locationId); - assert loc != null; - String location = loc.name(); - String address = loc.address(); - String schoolNumber = loc.number(); - - boolean hasExtension = extension.length() > 0; - boolean hasDirectNumber = directNumber.length() > 0; - boolean hasCell = cellNumber.length() > 0; - - BufferedImage rawImage = new BufferedImage(1080, 602, BufferedImage.TYPE_INT_ARGB); - BufferedImage background; - - try { - background = ImageIO.read(Main.class.getResource("/background.png")); - } catch (IOException e) { - e.printStackTrace(); - return null; - } - - Graphics2D g = rawImage.createGraphics(); - g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); - - g.drawImage(background, 0, 0, null); - - FontMetrics fm = g.getFontMetrics(ARIAL65); - - g.setColor(WHITE); - if (fm.stringWidth(name) <= 969){ - g.setFont(ARIAL65); - } else { - g.setFont(ARIAL55); - } - g.drawString(name, 85, 112); - - fm = g.getFontMetrics(ARIAL45I); - if (fm.stringWidth(title) <= 970) { - g.setFont(ARIAL45I); - } else { - g.setFont(ARIAL40I); - } - g.drawString(title, 89, 176); - - int doubleNumOffset = 0; - if (!hasCell) { - doubleNumOffset = 40; - } - - //TODO: Fix when 2 numbers present no mergy - int longAddrOffset = 0; - fm = g.getFontMetrics(ARIAL38I); - if (fm.stringWidth(address) > 694) { - longAddrOffset = 40; - } - - g.setFont(ARIAL45); - g.drawString(email, 62, 380 - doubleNumOffset - longAddrOffset); - - g.setColor(GREEN); - g.setFont(ARIAL44I); - g.drawString(location, 59, 447 - doubleNumOffset - longAddrOffset); - - if (fm.stringWidth(address) >= 694) { - - StringBuilder addrLineOne = new StringBuilder(); - StringBuilder addrLineTwo = new StringBuilder(); - - String[] splitAddr = address.split(","); - int i = 0; - for (int width = 0; width < 694; i++) { - int splitSize = fm.stringWidth(splitAddr[i]); - if ((width + splitSize) < 694) { - width += splitSize; - addrLineOne.append(splitAddr[i]); - addrLineOne.append(","); - } else { - addrLineOne.deleteCharAt(addrLineOne.length() - 1); - break; - } - } - - for (; i < splitAddr.length; i++) { - addrLineTwo.append(splitAddr[i]); - addrLineTwo.append(","); - } - addrLineTwo.deleteCharAt(addrLineTwo.length() - 1); - - g.setFont(ARIAL38I); - g.drawString(addrLineOne.toString().trim(), 59, 491 - doubleNumOffset - longAddrOffset); - g.drawString(addrLineTwo.toString().trim(), 59, 491 - doubleNumOffset); - } else { - g.drawString(address, 59, 491 - doubleNumOffset); - } - - String number = ""; - int numY = hasCell ? 540 : 496; - - if (hasExtension) { - number = "W: " + schoolNumber + " x" + extension; - } - if (hasDirectNumber) { - number = "W: " + directNumber; - } - - g.drawString(number, 59, numY); - - if (hasCell) { - g.drawString("C: " + cellNumber, 59, 540); - } - - g.dispose(); - - BufferedImage finalImage; - - switch (size) { - case 0 -> { - finalImage = new BufferedImage(300, 167, BufferedImage.TYPE_INT_ARGB); - g = finalImage.createGraphics(); - g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); - g.drawImage(rawImage, 0, 0, 300, 167, null); - g.dispose(); - } - case 1 -> finalImage = rawImage; - default -> finalImage = background; - } - - ByteArrayOutputStream baos; - try { - baos = new ByteArrayOutputStream(); - ImageIO.write(finalImage, "png", baos); - } catch (IOException e) { - e.printStackTrace(); - return null; - } - - return baos.toByteArray(); - } - - private static void loadLocations() { - try { - Gson gson = new Gson(); - JsonArray jsonFile = gson.fromJson(new FileReader("./locations.json"), JsonArray.class); - for (JsonElement element : jsonFile.asList()) { - LOCATIONS.add(gson.fromJson(element, Location.class)); - } - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - } - - private static Location getLocation(String locationId) { - for (Location loc : LOCATIONS) { - if (loc.id().equals(locationId)) { - return loc; - } - } - return null; - } -} - -record Location(String id, String name, String address, String number) { - - @Override - public String toString() { - return "{ \"id\": " + id + ", \"name\": " + name + ", \"address\": " + address + ", \"number\": " + number + " }"; } } diff --git a/src/main/java/tech/nevets/vcardgen/VCard.java b/src/main/java/tech/nevets/vcardgen/VCard.java new file mode 100644 index 0000000..9bf3185 --- /dev/null +++ b/src/main/java/tech/nevets/vcardgen/VCard.java @@ -0,0 +1,204 @@ +package tech.nevets.vcardgen; + +import com.google.gson.JsonObject; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +public class VCard { + private static final Color WHITE = new Color(255, 255, 255); + private static final Color GREEN = new Color(101, 142, 61); + + private static final Font ARIAL65 = new Font("Arial", Font.PLAIN, 65); + private static final Font ARIAL55 = new Font("Arial", Font.PLAIN, 55); + private static final Font ARIAL45 = new Font("Arial", Font.PLAIN, 45); + private static final Font ARIAL45I = new Font("Arial", Font.ITALIC, 45); + private static final Font ARIAL44I = new Font("Arial", Font.ITALIC, 44); + private static final Font ARIAL40I = new Font("Arial", Font.ITALIC, 40); + private static final Font ARIAL38I = new Font("Arial", Font.ITALIC, 38); + + private BufferedImage workingImage = new BufferedImage(1080, 602, BufferedImage.TYPE_INT_ARGB); + + private final String[] data = new String[9]; + private final boolean[] flags = new boolean[3]; // 0 - Long Address, 1 - Has Direct Number, 2 - Has Cell Phone + private final BufferedImage background; + private final int size; + + public VCard(JsonObject json) { + this.data[0] = json.get("name").getAsString(); //name + this.data[1] = json.get("title").getAsString(); //title + this.data[2] = json.get("email").getAsString(); //email + Location location = Location.getLocation(json.get("locationId").getAsString()); + this.data[3] = location.getName(); //locationName + this.data[4] = location.getAddress(); //address + this.data[5] = location.getName(); //schoolNumber + background = location.getBackground(); + this.data[6] = json.get("extension").getAsString(); //extension + this.data[7] = json.get("directNumber").getAsString(); //directNumber + this.data[8] = json.get("cellNumber").getAsString(); //cellNumber + this.flags[1] = this.data[7].length() > 0; //hasDirectNumber + this.flags[2] = this.data[8].length() > 0; //hasCellNumber + size = json.get("size").getAsInt(); + + renderImage(); + } + + public VCard(String name, String title, String email, String locationId, String extension, String directNumber, String cellNumber, int size) { + this.data[0] = name; //name + this.data[1] = title; //title + this.data[2] = email; //email + Location location = Location.getLocation(locationId); + this.data[3] = location.getName(); //locationName + this.data[4] = location.getAddress(); //address + this.data[5] = location.getName(); //schoolNumber + background = location.getBackground(); + this.data[6] = extension; //extension + this.data[7] = directNumber; //directNumber + this.data[8] = cellNumber; //cellNumber + this.flags[1] = this.data[7].length() > 0; //hasDirectNumber + this.flags[2] = this.data[8].length() > 0; //hasCellNumber + this.size = size; + + renderImage(); + } + + private void renderImage() { + Graphics2D g = workingImage.createGraphics(); + g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + + g.drawImage(background, 0, 0, null); + + FontMetrics fm = g.getFontMetrics(ARIAL65); + + g.setColor(WHITE); + if (fm.stringWidth(data[0]) <= 969) g.setFont(ARIAL65); + else g.setFont(ARIAL55); + g.drawString(data[0], 85, 112); + + fm = g.getFontMetrics(ARIAL45I); + if (fm.stringWidth(data[1]) <= 970) g.setFont(ARIAL45I); + else g.setFont(ARIAL40I); + g.drawString(data[1], 89, 176); + + int doubleNumOffset = 0; + if (flags[2]) { + doubleNumOffset = 40; + } + + int longAddrOffset = 0; + fm = g.getFontMetrics(ARIAL38I); + if (fm.stringWidth(data[4]) > 694) longAddrOffset = 40; + + g.setFont(ARIAL45); + g.drawString(data[2], 62, 380 - doubleNumOffset - longAddrOffset); + + g.setColor(GREEN); + g.setFont(ARIAL44I); + g.drawString(data[3], 59, 447 - doubleNumOffset - longAddrOffset); + + if (fm.stringWidth(data[4]) >= 694) { + StringBuilder addrLineOne = new StringBuilder(); + StringBuilder addrLineTwo = new StringBuilder(); + + String[] splitAddr = data[4].split(","); + int i = 0; + for (int width = 0; width < 694; i++) { + int splitSize = fm.stringWidth(splitAddr[i]); + if ((width + splitSize) < 694) { + width += splitSize; + addrLineOne.append(splitAddr[i]); + addrLineOne.append(","); + } else { + addrLineOne.deleteCharAt(addrLineOne.length() - 1); + break; + } + } + + for (; i < splitAddr.length; i++) { + addrLineTwo.append(splitAddr[i]); + addrLineTwo.append(","); + } + addrLineTwo.deleteCharAt(addrLineTwo.length() - 1); + + g.setFont(ARIAL38I); + g.drawString(addrLineOne.toString().trim(), 59, 491 - doubleNumOffset - longAddrOffset); + g.drawString(addrLineTwo.toString().trim(), 59, 491 - doubleNumOffset); + } else { + g.drawString(data[4], 59, 491 - doubleNumOffset); + } + + String number; + int numY = flags[2] ? 496 : 540; + + if (!flags[1]) number = "W: " + data[5] + " x" + data[6]; + else number = "W: " + data[7]; + + g.drawString(number, 59, numY); + + if (flags[2]) g.drawString("C: " + data[8], 59, 540); + + g.dispose(); + } + + public void resizeImage() { + resizeImage(this.size); + } + + public void resizeImage(int size) { + BufferedImage resizedImage; + switch (size) { + case 0 -> resizedImage = resizeImage(300, 167, false); + case 1 -> resizedImage = workingImage; + default -> resizedImage = background; + } + workingImage = resizedImage; + } + + public BufferedImage resizeImage(int width, int height, boolean antiAlias) { + BufferedImage resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + Graphics2D g = resizedImage.createGraphics(); + g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); + if (antiAlias) g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g.drawImage(workingImage, 0, 0, width, height, null); + g.dispose(); + return resizedImage; + } + + public byte[] toByteArray() { + ByteArrayOutputStream baos; + try { + baos = new ByteArrayOutputStream(); + ImageIO.write(workingImage, "png", baos); + } catch (IOException e) { + e.printStackTrace(); + return new byte[0]; + } + + return baos.toByteArray(); + } + + private boolean[] bitFlags(int bits) { + boolean[] flags = new boolean[bits]; + for (int i = 0; i < flags.length; i++) { + flags[i] = ((bits) & (1 << ((flags.length - i) - 1))) != 0; + } + return flags; + } + + private int bitFlagsFromFlags(boolean[] flags) { + StringBuilder sb = new StringBuilder(); + for (boolean b : flags) { + sb.append(b ? "1" : "0"); + } + return Integer.parseInt(sb.toString()); + } + + private static boolean fitsDimensions(String text, Font font, int maxLength) { + Canvas c = new Canvas(); + FontMetrics fm = c.getFontMetrics(font); + return fm.stringWidth(text) < maxLength; + } +} diff --git a/src/main/resources/background.png b/src/main/resources/backgrounds/caiu.png similarity index 100% rename from src/main/resources/background.png rename to src/main/resources/backgrounds/caiu.png diff --git a/src/main/resources/backgrounds/default.png b/src/main/resources/backgrounds/default.png new file mode 100644 index 0000000..5356b6e Binary files /dev/null and b/src/main/resources/backgrounds/default.png differ