diff --git a/src/main/java/tech/nevets/vcardgen/Card.java b/src/main/java/tech/nevets/vcardgen/Card.java index 6aa8eac..abdb3bb 100644 --- a/src/main/java/tech/nevets/vcardgen/Card.java +++ b/src/main/java/tech/nevets/vcardgen/Card.java @@ -17,7 +17,7 @@ public class Card { // ---------------- COLORS ---------------- // private static final Color WHITE = new Color(255, 255, 255); - private static final Color GREEN = new Color(101, 142, 61); + private static final Color GREEN = new Color(101, 141, 27); // ---------------- FONTS ---------------- // private static final Font ARIAL65 = new Font("Arial", Font.PLAIN, 65); @@ -30,11 +30,11 @@ public class Card { // ---------------- LAYERS ---------------- // private BufferedImage background; - private BufferedImage nameLayer = new BufferedImage(975, 90, BufferedImage.TYPE_INT_ARGB); - private BufferedImage titleLayer = new BufferedImage(975, 55, BufferedImage.TYPE_INT_ARGB); - private BufferedImage emailLayer = new BufferedImage(1000, 55, BufferedImage.TYPE_INT_ARGB); - private BufferedImage locationLayer = new BufferedImage(700, 134, BufferedImage.TYPE_INT_ARGB); - private BufferedImage phoneNumbersLayer = new BufferedImage(700, 90, BufferedImage.TYPE_INT_ARGB); + private BufferedImage nameLayer = new BufferedImage(1080, 602, BufferedImage.TYPE_INT_ARGB); + private BufferedImage titleLayer = new BufferedImage(1080, 602, BufferedImage.TYPE_INT_ARGB); + private BufferedImage emailLayer = new BufferedImage(1080, 602, BufferedImage.TYPE_INT_ARGB); + private BufferedImage locationLayer = new BufferedImage(1080, 602, BufferedImage.TYPE_INT_ARGB); + private BufferedImage phoneNumbersLayer = new BufferedImage(1080, 602, BufferedImage.TYPE_INT_ARGB); // ---------------- Working Images ---------------- // private Graphics2D graphics; @@ -43,7 +43,7 @@ public class Card { private IIOImage finalImage; // ---------------- DATA ---------------- // - public String id; + public final String id; private String name; private String title; private String email; @@ -147,40 +147,37 @@ public class Card { return background; } - private BufferedImage renderLayer(BufferedImage layer, String content, Color textColor, Font font) { - return renderLayer(layer, content, textColor, font, 0, 0); - } - private BufferedImage renderLayer(BufferedImage layer, String content, Color textColor, Font font, int x, int y) { graphics = layer.createGraphics(); setAntiAlias(graphics); graphics.setColor(textColor); + graphics.setFont(font); graphics.drawString(content, x, y); graphics.dispose(); return layer; } - private BufferedImage renderResizableLayer(BufferedImage layer, String content, Color textColor, int maxLength, Font defaultFont, Font smallFont) { + private BufferedImage renderResizableLayer(BufferedImage layer, String content, Color textColor, int maxLength, Font defaultFont, Font smallFont, int x, int y) { graphics = layer.createGraphics(); setAntiAlias(graphics); graphics.setColor(textColor); if (fitsDimensions(content, defaultFont, maxLength)) graphics.setFont(defaultFont); else graphics.setFont(smallFont); - graphics.drawString(content, 0, 0); + graphics.drawString(content, x, y); graphics.dispose(); return layer; } public BufferedImage renderNameLayer() { - return renderResizableLayer(nameLayer, name, WHITE, 970, ARIAL65, ARIAL55); + return renderResizableLayer(nameLayer, name, WHITE, 970, ARIAL65, ARIAL55, 85, 112); } public BufferedImage renderTitleLayer() { - return renderResizableLayer(titleLayer, title, WHITE, 970, ARIAL45I, ARIAL40I); + return renderResizableLayer(titleLayer, title, WHITE, 970, ARIAL45I, ARIAL40I, 89, 176); } public BufferedImage renderEmailLayer() { - return renderLayer(emailLayer, email, WHITE, ARIAL45); + return renderLayer(emailLayer, email, WHITE, ARIAL45, 62, (380 - getOffsets(0))); } public BufferedImage renderLocationLayer() { @@ -205,71 +202,54 @@ public class Card { sb.insert(newLineIndex - 2, "\n"); sb.deleteCharAt(sb.length() - 1); } - renderLayer(locationLayer, location.getName(), GREEN, ARIAL44I); - return renderLayer(locationLayer, sb.toString(), GREEN, ARIAL38I, 0, 44); + renderLayer(locationLayer, location.getName(), GREEN, ARIAL44I, 59, (447 - getOffsets(0))); + return renderLayer(locationLayer, sb.toString(), GREEN, ARIAL38I, 59, (491 - getOffsets(0))); } public BufferedImage renderPhoneNumbersLayer() { - return null; + if (hasDirectNumber) { + renderLayer(phoneNumbersLayer, ("W: " + directNumber), GREEN, ARIAL38I, 59, (540 - getOffsets(1))); + } else { + renderLayer(phoneNumbersLayer, ("W: " + location.getNumber() + " x" + extension), GREEN, ARIAL38I, 59, (540 - getOffsets(1))); + } + if (hasCellNumber) { + renderLayer(phoneNumbersLayer, ("C: " + cellNumber), GREEN, ARIAL38I, 59, 540); + } + return phoneNumbersLayer; } - private void renderImage() { + public void renderImage() { graphics = rawImage.createGraphics(); setAntiAlias(graphics); graphics.drawImage(background, 0, 0, null); - graphics.drawImage(renderNameLayer(), 85, 112, null); - graphics.drawImage(renderTitleLayer(), 89, 176, null); - - int doubleNumOffset = hasDirectNumber ? 40 : 0; - int longAddrOffset = fitsDimensions(location.getAddress(), ARIAL38I, 700) ? 0 : 40; - - graphics.drawImage(renderEmailLayer(), 62, (380 - doubleNumOffset - longAddrOffset), null); - - graphics.setColor(GREEN); - graphics.setFont(ARIAL44I); - graphics.drawString(location.getName(), 59, 447 - doubleNumOffset - longAddrOffset); - - if (!fitsDimensions(location.getAddress(), ARIAL38I, 694)) { - StringBuilder addrLineOne = new StringBuilder(); - StringBuilder addrLineTwo = new StringBuilder(); - - String[] splitAddr = location.getAddress().split(","); - int i = 0; - for (int width = 0; width < 694; i++) { - int splitSize = graphics.getFontMetrics().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); - - graphics.setFont(ARIAL38I); - graphics.drawString(addrLineOne.toString().trim(), 59, 491 - doubleNumOffset - longAddrOffset); - graphics.drawString(addrLineTwo.toString().trim(), 59, 491 - doubleNumOffset); - } else { - graphics.drawString(location.getAddress(), 59, 491 - doubleNumOffset); - } - - String number; - int numY = hasDirectNumber ? 496 : 540; - if (!hasDirectNumber) number = "W: " + location.getNumber() + " x" + extension; - else number = "W: " + directNumber; - graphics.drawString(number, 59, numY); - if (hasCellNumber) graphics.drawString("C: " + cellNumber, 59, 540); + graphics.drawImage(renderNameLayer(), 0, 0, null); + graphics.drawImage(renderTitleLayer(), 0, 0, null); + graphics.drawImage(renderEmailLayer(), 0, 0, null); + graphics.drawImage(renderLocationLayer(), 0, 0, null); + graphics.drawImage(renderPhoneNumbersLayer(), 0, 0, null); graphics.dispose(); - rawImage = workingImage; + resizeImage(); + } + + /** + * Gets offsets for necessary layers + * @param type
0: Both double number and long address
1: Only double number + * @return Negative integer value for pixel offset + */ + private int getOffsets(int type) { + int totalOffset = 0; + int doubleNumberOffset = hasDirectNumber ? 40 : 0; + int longAddrOffset = fitsDimensions(location.getAddress(), ARIAL38I, 700) ? 0 : 40; + switch (type) { + case 0 -> { + totalOffset -= doubleNumberOffset; + totalOffset -= longAddrOffset; + } + case 1 -> totalOffset -= doubleNumberOffset; + } + return totalOffset; } public void resizeImage() { @@ -305,12 +285,9 @@ public class Card { finalImage = reader.readAll(0, null); IIOMetadataNode text = new IIOMetadataNode("tEXt"); -// for (int i = 0; i < KEYS.length; i++) { -// IIOMetadataNode textEntry = new IIOMetadataNode("tEXtEntry"); -// textEntry.setAttribute("keyword", KEYS[i]); -// textEntry.setAttribute("value", data[i]); -// text.appendChild(textEntry); -// } + IIOMetadataNode textEntry = new IIOMetadataNode("tEXtEntry"); + textEntry.setAttribute("contents", toMetaString(this)); + text.appendChild(textEntry); IIOMetadataNode root = new IIOMetadataNode("javax_imageio_png_1.0"); root.appendChild(text); @@ -318,6 +295,7 @@ public class Card { } public byte[] toByteArray() throws IOException { + addMetadata(); ImageWriter writer = ImageIO.getImageWritersByMIMEType("image/png").next(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageOutputStream ios = ImageIO.createImageOutputStream(baos); @@ -338,6 +316,16 @@ public class Card { return C.getFontMetrics(font).stringWidth(text); } + public static String toMetaString(Card card) { + return "name=" + card.name + ";" + + "title=" + card.title + ";" + + "email=" + card.email + ";" + + "locationId=" + card.location.getId() + ";" + + "extension=" + card.extension + ";" + + "directNumber=" + card.directNumber + ";" + + "cellNumber=" + card.cellNumber + ";"; + } + public static String getDataFromVCard(InputStream rawImage) throws IOException { ImageReader reader = ImageIO.getImageReadersByMIMEType("image/png").next(); reader.setInput(ImageIO.createImageInputStream(rawImage)); @@ -348,20 +336,13 @@ public class Card { if (text == null) { return "$null"; } - int numTextEntries = text.getLength(); Map keyValueMap = new HashMap<>(); - for (int i = 0; i < numTextEntries; i++) { - IIOMetadataNode textEntry = (IIOMetadataNode) text.item(i); - String key = textEntry.getAttribute("keyword"); - String value = textEntry.getAttribute("value"); - if (key.equals("Address") || key.equals("SchoolNumber")) { - continue; - } - if (key.equals("Location")) { - value = Location.getLocationId(value); - } - keyValueMap.put(key, value); + String contents = ((IIOMetadataNode) text.item(0)).getAttribute("contents"); + String[] contentSplit = contents.split(";"); + for (String entry : contentSplit) { + String[] kvPair = entry.split("="); + keyValueMap.put(kvPair[0], kvPair[1]); } return new Gson().toJson(keyValueMap); diff --git a/src/main/java/tech/nevets/vcardgen/GenerateRoute.java b/src/main/java/tech/nevets/vcardgen/GenerateRoute.java index 81bb579..b1a5fdf 100644 --- a/src/main/java/tech/nevets/vcardgen/GenerateRoute.java +++ b/src/main/java/tech/nevets/vcardgen/GenerateRoute.java @@ -20,13 +20,15 @@ public class GenerateRoute implements Route { res.status(422); return "Not valid json: " + e.getMessage(); } + card = new Card(data); + card.renderImage(); res.type("image/png"); res.header("Access-Control-Expose-Headers", "Id"); - card = new Card(data); + res.header("Id", card.id); try { res.status(200); - return new Card(data).toByteArray(); + return card.toByteArray(); } catch (IOException e) { res.status(500); return "Error getting image stream: " + e.getMessage(); diff --git a/src/main/java/tech/nevets/vcardgen/LiveGenWebSocket.java b/src/main/java/tech/nevets/vcardgen/LiveGenWebSocket.java index ed84b64..43785e9 100644 --- a/src/main/java/tech/nevets/vcardgen/LiveGenWebSocket.java +++ b/src/main/java/tech/nevets/vcardgen/LiveGenWebSocket.java @@ -19,21 +19,33 @@ public class LiveGenWebSocket { public void connected(Session session) {} @OnWebSocketClose - public void closed(Session session, int statusCode, String reason) {} + public void closed(Session session, int statusCode, String reason) { + card = null; + } + + @OnWebSocketError + public void error(Session session, Throwable throwable) { + throwable.printStackTrace(); + } @OnWebSocketMessage public void message(Session session, String message) throws IOException { - String[] splitMsg = message.split(";"); - String messageType = splitMsg[0]; - String messageContent = splitMsg[1]; - RemoteEndpoint client = session.getRemote(); - switch (messageType) { - case "start" -> { + System.out.println(message); + String[] splitMsg = message.split(";"); + String messageType = splitMsg[0]; + + if (splitMsg.length == 1) { + if (messageType.equals("start")) { card = new Card(); client.sendString("success;Card successfully created."); } + return; + } + String messageContent = splitMsg[1]; + + switch (messageType) { case "continue" -> { card = Card.CARD_SESSIONS.get(messageContent); if (card == null) { @@ -43,32 +55,46 @@ public class LiveGenWebSocket { client.sendString("success;Card loaded successfully."); } } - case "location" -> { - card.setLocation(Location.getLocation(messageContent)); + case "background" -> { client.sendString("background"); client.sendBytes(byteBufferFromImage(card.getBackground())); + } + case "location" -> { + card.setLocation(Location.getLocation(messageContent)); client.sendString("location"); client.sendBytes(byteBufferFromImage(card.renderLocationLayer())); } case "name" -> { - + card.setName(messageContent); + client.sendString("name"); + client.sendBytes(byteBufferFromImage(card.renderNameLayer())); } case "title" -> { - + card.setTitle(messageContent); + client.sendString("title"); + client.sendBytes(byteBufferFromImage(card.renderTitleLayer())); } case "email" -> { - + card.setEmail(messageContent); + client.sendString("email"); + client.sendBytes(byteBufferFromImage(card.renderEmailLayer())); } case "extension" -> { - + card.setExtension(messageContent); + client.sendString("extension"); + client.sendBytes(byteBufferFromImage(card.renderPhoneNumbersLayer())); } case "directNumber" -> { - + card.setDirectNumber(messageContent); + client.sendString("directNumber"); + client.sendBytes(byteBufferFromImage(card.renderPhoneNumbersLayer())); } case "cellNumber" -> { - + card.setCellNumber(messageContent); + client.sendString("cellNumber"); + client.sendBytes(byteBufferFromImage(card.renderPhoneNumbersLayer())); } - default -> session.getRemote().sendString("Unknown Message Type: " + messageType); + default -> client.sendString("Unknown Message Type: " + messageType); } } diff --git a/src/main/java/tech/nevets/vcardgen/Location.java b/src/main/java/tech/nevets/vcardgen/Location.java index c00d641..cb7ab8b 100644 --- a/src/main/java/tech/nevets/vcardgen/Location.java +++ b/src/main/java/tech/nevets/vcardgen/Location.java @@ -21,12 +21,12 @@ public class Location { private final String number; private transient BufferedImage background; - public Location(String id, String name, String address, String number) throws IOException { + public Location(String id, String name, String address, String number) { this.id = id; this.name = name; this.address = address; this.number = number; - background = ImageIO.read(this.getClass().getResourceAsStream("/backgrounds/" + id + ".png")); + loadBackground(); } public String getId() { @@ -49,10 +49,14 @@ public class Location { return background; } - public void loadBackground() throws IOException { + public void loadBackground() { URL backgroundURL = this.getClass().getResource("/backgrounds/" + id + ".png"); if (backgroundURL == null) backgroundURL = this.getClass().getResource("/backgrounds/default.png"); - background = ImageIO.read(backgroundURL); + try { + background = ImageIO.read(backgroundURL); + } catch (IOException e) { + e.printStackTrace(); + } } @Override @@ -74,13 +78,13 @@ public class Location { } } - public static Location getLocation (String locationId){ + public static Location getLocation (String locationId) { for (Location loc : LOCATIONS) { if (loc.getId().equals(locationId)) { return loc; } } - return null; + return new Location("", "", "", ""); } public static String getLocationId(String name) { @@ -91,6 +95,4 @@ public class Location { } return null; } - - } \ No newline at end of file