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();
port(8080);
get("/heartbeat", (req, res) -> {
res.status(200);
res.type("application/json");
res.header("Access-Control-Allow-Origin", "*");
return "{ \"up\":true }";
});
path("/backend", () -> {
before("/*");
get("/data/locations", (req, res) -> {
res.status(200);
res.type("application/json");
res.header("Access-Control-Allow-Origin", "*");
return new FileInputStream("locations.json");
});
get("/heartbeat", (req, res) -> {
res.status(200);
res.type("application/json");
res.header("Access-Control-Allow-Origin", "*");
return "{ \"up\":true }";
});
post("/", (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();
get("/data/locations", (req, res) -> {
res.status(200);
res.type("application/json");
res.header("Access-Control-Allow-Origin", "*");
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;
import com.google.gson.Gson;
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.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class VCard {
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 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 IIOImage finalImage;
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
@ -34,7 +46,7 @@ public class VCard {
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
this.data[5] = location.getNumber(); //schoolNumber
background = location.getBackground();
this.data[6] = json.get("extension").getAsString(); //extension
this.data[7] = json.get("directNumber").getAsString(); //directNumber
@ -44,6 +56,13 @@ public class VCard {
size = json.get("size").getAsInt();
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) {
@ -63,6 +82,13 @@ public class VCard {
this.size = size;
renderImage();
resizeImage();
try {
addMetadata();
} catch (IOException e) {
System.out.println("Error adding metadata");
e.printStackTrace();
}
}
private void renderImage() {
@ -71,15 +97,12 @@ public class VCard {
g.drawImage(background, 0, 0, null);
FontMetrics fm = g.getFontMetrics(ARIAL65);
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);
g.drawString(data[0], 85, 112);
fm = g.getFontMetrics(ARIAL45I);
if (fm.stringWidth(data[1]) <= 970) g.setFont(ARIAL45I);
if (fitsDimensions(data[1], ARIAL45I, 970)) g.setFont(ARIAL45I);
else g.setFont(ARIAL40I);
g.drawString(data[1], 89, 176);
@ -88,9 +111,7 @@ public class VCard {
doubleNumOffset = 40;
}
int longAddrOffset = 0;
fm = g.getFontMetrics(ARIAL38I);
if (fm.stringWidth(data[4]) > 694) longAddrOffset = 40;
int longAddrOffset = fitsDimensions(data[4], ARIAL38I, 694) ? 0 : 40;
g.setFont(ARIAL45);
g.drawString(data[2], 62, 380 - doubleNumOffset - longAddrOffset);
@ -99,14 +120,14 @@ public class VCard {
g.setFont(ARIAL44I);
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 addrLineTwo = new StringBuilder();
String[] splitAddr = data[4].split(",");
int i = 0;
for (int width = 0; width < 694; i++) {
int splitSize = fm.stringWidth(splitAddr[i]);
int splitSize = g.getFontMetrics().stringWidth(splitAddr[i]);
if ((width + splitSize) < 694) {
width += splitSize;
addrLineOne.append(splitAddr[i]);
@ -132,15 +153,13 @@ public class VCard {
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();
rawImage = workingImage;
}
public void resizeImage() {
@ -151,7 +170,7 @@ public class VCard {
BufferedImage resizedImage;
switch (size) {
case 0 -> resizedImage = resizeImage(300, 167, false);
case 1 -> resizedImage = workingImage;
case 1 -> resizedImage = rawImage;
default -> resizedImage = background;
}
workingImage = resizedImage;
@ -162,43 +181,63 @@ public class VCard {
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.drawImage(rawImage, 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];
}
public void addMetadata() throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(workingImage, "png", baos);
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();
}
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 final Canvas C = new Canvas();
private static boolean fitsDimensions(String text, Font font, int maxLength) {
Canvas c = new Canvas();
FontMetrics fm = c.getFontMetrics(font);
return fm.stringWidth(text) < maxLength;
return C.getFontMetrics(font).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);
}
}