This commit is contained in:
Steven Tracey 2023-05-12 16:15:39 -04:00
parent c530a55f2f
commit c7bfdd4fc1
2 changed files with 112 additions and 62 deletions

View File

@ -12,25 +12,36 @@ public class Main {
Location.loadLocations(); Location.loadLocations();
port(8080); port(8080);
get("/heartbeat", (req, res) -> { path("/backend", () -> {
res.status(200); before("/*");
res.type("application/json");
res.header("Access-Control-Allow-Origin", "*");
return "{ \"up\":true }";
});
get("/data/locations", (req, res) -> { get("/heartbeat", (req, res) -> {
res.status(200); res.status(200);
res.type("application/json"); res.type("application/json");
res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Origin", "*");
return new FileInputStream("locations.json"); return "{ \"up\":true }";
}); });
post("/", (req, res) -> { get("/data/locations", (req, res) -> {
res.type("image/png"); res.status(200);
res.header("Access-Control-Allow-Origin", "*"); res.type("application/json");
JsonObject data = new Gson().fromJson(req.body(), JsonObject.class); res.header("Access-Control-Allow-Origin", "*");
return new VCard(data).toByteArray(); return new FileInputStream("locations.json");
});
post("/generate", (req, res) -> {
res.type("image/png");
res.header("Access-Control-Allow-Origin", "*");
JsonObject data = new Gson().fromJson(req.body(), JsonObject.class);
return new VCard(data).toByteArray();
});
post("/edit", (req, res) -> {
res.status(200);
res.type("application/json");
res.header("Access-Control-Allow-Origin", "*");
return VCard.getDataFromVCard(req.bodyAsBytes());
});
}); });
} }
} }

View File

@ -1,12 +1,20 @@
package tech.nevets.vcardgen; package tech.nevets.vcardgen;
import com.google.gson.Gson;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import javax.imageio.ImageIO; import javax.imageio.*;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*; import java.awt.*;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class VCard { public class VCard {
private static final Color WHITE = new Color(255, 255, 255); private static final Color WHITE = new Color(255, 255, 255);
@ -20,7 +28,11 @@ public class VCard {
private static final Font ARIAL40I = new Font("Arial", Font.ITALIC, 40); 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 Font ARIAL38I = new Font("Arial", Font.ITALIC, 38);
private static final String[] KEYS = {"Name", "Title", "Email", "Location", "Address", "SchoolNumber", "Extension", "DirectNumber", "CellNumber"};
private BufferedImage rawImage = new BufferedImage(1080, 602, BufferedImage.TYPE_INT_ARGB);
private BufferedImage workingImage = new BufferedImage(1080, 602, BufferedImage.TYPE_INT_ARGB); private BufferedImage workingImage = new BufferedImage(1080, 602, BufferedImage.TYPE_INT_ARGB);
private IIOImage finalImage;
private final String[] data = new String[9]; 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 boolean[] flags = new boolean[3]; // 0 - Long Address, 1 - Has Direct Number, 2 - Has Cell Phone
@ -34,7 +46,7 @@ public class VCard {
Location location = Location.getLocation(json.get("locationId").getAsString()); Location location = Location.getLocation(json.get("locationId").getAsString());
this.data[3] = location.getName(); //locationName this.data[3] = location.getName(); //locationName
this.data[4] = location.getAddress(); //address this.data[4] = location.getAddress(); //address
this.data[5] = location.getName(); //schoolNumber this.data[5] = location.getNumber(); //schoolNumber
background = location.getBackground(); background = location.getBackground();
this.data[6] = json.get("extension").getAsString(); //extension this.data[6] = json.get("extension").getAsString(); //extension
this.data[7] = json.get("directNumber").getAsString(); //directNumber this.data[7] = json.get("directNumber").getAsString(); //directNumber
@ -44,6 +56,13 @@ public class VCard {
size = json.get("size").getAsInt(); size = json.get("size").getAsInt();
renderImage(); renderImage();
resizeImage();
try {
addMetadata();
} catch (IOException e) {
System.out.println("Error adding metadata");
e.printStackTrace();
}
} }
public VCard(String name, String title, String email, String locationId, String extension, String directNumber, String cellNumber, int size) { public VCard(String name, String title, String email, String locationId, String extension, String directNumber, String cellNumber, int size) {
@ -63,6 +82,13 @@ public class VCard {
this.size = size; this.size = size;
renderImage(); renderImage();
resizeImage();
try {
addMetadata();
} catch (IOException e) {
System.out.println("Error adding metadata");
e.printStackTrace();
}
} }
private void renderImage() { private void renderImage() {
@ -71,15 +97,12 @@ public class VCard {
g.drawImage(background, 0, 0, null); g.drawImage(background, 0, 0, null);
FontMetrics fm = g.getFontMetrics(ARIAL65);
g.setColor(WHITE); g.setColor(WHITE);
if (fm.stringWidth(data[0]) <= 969) g.setFont(ARIAL65); if (fitsDimensions(data[0], ARIAL65, 969)) g.setFont(ARIAL65);
else g.setFont(ARIAL55); else g.setFont(ARIAL55);
g.drawString(data[0], 85, 112); g.drawString(data[0], 85, 112);
fm = g.getFontMetrics(ARIAL45I); if (fitsDimensions(data[1], ARIAL45I, 970)) g.setFont(ARIAL45I);
if (fm.stringWidth(data[1]) <= 970) g.setFont(ARIAL45I);
else g.setFont(ARIAL40I); else g.setFont(ARIAL40I);
g.drawString(data[1], 89, 176); g.drawString(data[1], 89, 176);
@ -88,9 +111,7 @@ public class VCard {
doubleNumOffset = 40; doubleNumOffset = 40;
} }
int longAddrOffset = 0; int longAddrOffset = fitsDimensions(data[4], ARIAL38I, 694) ? 0 : 40;
fm = g.getFontMetrics(ARIAL38I);
if (fm.stringWidth(data[4]) > 694) longAddrOffset = 40;
g.setFont(ARIAL45); g.setFont(ARIAL45);
g.drawString(data[2], 62, 380 - doubleNumOffset - longAddrOffset); g.drawString(data[2], 62, 380 - doubleNumOffset - longAddrOffset);
@ -99,14 +120,14 @@ public class VCard {
g.setFont(ARIAL44I); g.setFont(ARIAL44I);
g.drawString(data[3], 59, 447 - doubleNumOffset - longAddrOffset); g.drawString(data[3], 59, 447 - doubleNumOffset - longAddrOffset);
if (fm.stringWidth(data[4]) >= 694) { if (!fitsDimensions(data[4], ARIAL38I, 694)) {
StringBuilder addrLineOne = new StringBuilder(); StringBuilder addrLineOne = new StringBuilder();
StringBuilder addrLineTwo = new StringBuilder(); StringBuilder addrLineTwo = new StringBuilder();
String[] splitAddr = data[4].split(","); String[] splitAddr = data[4].split(",");
int i = 0; int i = 0;
for (int width = 0; width < 694; i++) { for (int width = 0; width < 694; i++) {
int splitSize = fm.stringWidth(splitAddr[i]); int splitSize = g.getFontMetrics().stringWidth(splitAddr[i]);
if ((width + splitSize) < 694) { if ((width + splitSize) < 694) {
width += splitSize; width += splitSize;
addrLineOne.append(splitAddr[i]); addrLineOne.append(splitAddr[i]);
@ -132,15 +153,13 @@ public class VCard {
String number; String number;
int numY = flags[2] ? 496 : 540; int numY = flags[2] ? 496 : 540;
if (!flags[1]) number = "W: " + data[5] + " x" + data[6]; if (!flags[1]) number = "W: " + data[5] + " x" + data[6];
else number = "W: " + data[7]; else number = "W: " + data[7];
g.drawString(number, 59, numY); g.drawString(number, 59, numY);
if (flags[2]) g.drawString("C: " + data[8], 59, 540); if (flags[2]) g.drawString("C: " + data[8], 59, 540);
g.dispose(); g.dispose();
rawImage = workingImage;
} }
public void resizeImage() { public void resizeImage() {
@ -151,7 +170,7 @@ public class VCard {
BufferedImage resizedImage; BufferedImage resizedImage;
switch (size) { switch (size) {
case 0 -> resizedImage = resizeImage(300, 167, false); case 0 -> resizedImage = resizeImage(300, 167, false);
case 1 -> resizedImage = workingImage; case 1 -> resizedImage = rawImage;
default -> resizedImage = background; default -> resizedImage = background;
} }
workingImage = resizedImage; workingImage = resizedImage;
@ -162,43 +181,63 @@ public class VCard {
Graphics2D g = resizedImage.createGraphics(); Graphics2D g = resizedImage.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
if (antiAlias) g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); if (antiAlias) g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.drawImage(workingImage, 0, 0, width, height, null); g.drawImage(rawImage, 0, 0, width, height, null);
g.dispose(); g.dispose();
return resizedImage; return resizedImage;
} }
public byte[] toByteArray() { public void addMetadata() throws IOException {
ByteArrayOutputStream baos; ByteArrayOutputStream baos = new ByteArrayOutputStream();
try { ImageIO.write(workingImage, "png", baos);
baos = new ByteArrayOutputStream();
ImageIO.write(workingImage, "png", baos);
} catch (IOException e) {
e.printStackTrace();
return new byte[0];
}
ImageReader reader = ImageIO.getImageReadersByMIMEType("image/png").next();
reader.setInput(ImageIO.createImageInputStream(new ByteArrayInputStream(baos.toByteArray())));
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 root = new IIOMetadataNode("javax_imageio_png_1.0");
root.appendChild(text);
finalImage.getMetadata().mergeTree("javax_imageio_png_1.0", root);
}
public byte[] toByteArray() throws IOException {
ImageWriter writer = ImageIO.getImageWritersByMIMEType("image/png").next();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageOutputStream ios = ImageIO.createImageOutputStream(baos);
writer.setOutput(ios);
writer.write(finalImage);
return baos.toByteArray(); return baos.toByteArray();
} }
private boolean[] bitFlags(int bits) { private static final Canvas C = new Canvas();
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) { private static boolean fitsDimensions(String text, Font font, int maxLength) {
Canvas c = new Canvas(); return C.getFontMetrics(font).stringWidth(text) < maxLength;
FontMetrics fm = c.getFontMetrics(font); }
return fm.stringWidth(text) < maxLength;
public static String getDataFromVCard(byte[] rawImage) throws IOException {
ImageReader reader = ImageIO.getImageReadersByMIMEType("image/png").next();
reader.setInput(ImageIO.createImageInputStream(new ByteArrayInputStream(rawImage)));
IIOMetadata metadata = reader.getImageMetadata(0);
IIOMetadataNode root = (IIOMetadataNode) metadata.getAsTree("javax_imageio_png_1.0");
IIOMetadataNode text = (IIOMetadataNode) root.getElementsByTagName("tEXt").item(0);
int numTextEntries = text.getLength();
Map<String, String> 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");
keyValueMap.put(key, value);
}
return new Gson().toJson(keyValueMap);
} }
} }