Refactoring Galore!

This commit is contained in:
Steven Tracey 2023-05-11 13:51:15 -04:00
parent 8a9dd0afd4
commit c530a55f2f
5 changed files with 292 additions and 206 deletions

View File

@ -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<Location> 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 + " }";
}
}

View File

@ -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<Location> 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 + " }";
}
}

View File

@ -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;
}
}

View File

Before

Width:  |  Height:  |  Size: 2.5 MiB

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB