Skip to content

Commit

Permalink
Added tshirt rendering code and fonts.
Browse files Browse the repository at this point in the history
  • Loading branch information
Leandro committed Aug 9, 2011
1 parent 92cb132 commit bdefbfb
Show file tree
Hide file tree
Showing 44 changed files with 498 additions and 8 deletions.
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/eclipse
/tmp
/crud
/.classpath
/.project
/.settings
/crud
11 changes: 4 additions & 7 deletions app/controllers/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import models.TShirt.Size;
import models.dineromail.DineroMailHttpPost;
import models.dineromail.DineroMailHttpPostFactory;
import play.Play;
import play.data.validation.Valid;
import play.mvc.Controller;
import play.mvc.Router;
Expand All @@ -17,6 +18,7 @@ public class Application extends Controller {
private static final String LOGO_URL = "http://customica.com/images/logo.png";

public static void index() {
System.out.println("application path: " + Play.applicationPath);
renderArgs.put("newestTShirts", TShirt.findLatest6());
renderArgs.put("categories", Category.findAll());
render();
Expand Down Expand Up @@ -111,14 +113,9 @@ public static void submitDesign(Long id, String xml, String title, Long category
if(id != null) tShirt = TShirt.findById(id);

if(tShirt == null) {
tShirt = TShirt.create(title, xml, categoryId);
tShirt = TShirt.create(title, categoryId, xml);
} else {
if(!tShirt.isAuthorLoggedIn()) error("User is not author.");
tShirt.xml = xml;
tShirt.title = title;
tShirt.category = Category.findById(categoryId);
if(tShirt.category == null) error("Category doesn't exist.");
tShirt.save();
tShirt.update(title, categoryId, xml);
}

tshirt(tShirt.id);
Expand Down
25 changes: 24 additions & 1 deletion app/models/TShirt.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import javax.persistence.Lob;
import javax.persistence.ManyToOne;

import play.Play;
import play.db.jpa.Model;

@Entity
Expand Down Expand Up @@ -41,6 +42,9 @@ public static Size fromString(String string) {
public static final Integer PRICE = 50;
public static final Integer SHIPPING_COST = 25;

private static final String BASE_DESIGN_PATH = Play.applicationPath + "/public/designs";
private static final String BASE_DESIGN_URL = "/designs";

public Date created;
public String title;

Expand All @@ -53,7 +57,7 @@ public static Size fromString(String string) {
@ManyToOne
public Category category;

public static TShirt create(String title, String xml, Long categoryId) {
public static TShirt create(String title, Long categoryId, String xml) {
TShirt tShirt = new TShirt();
tShirt.created = new Date();
tShirt.title = title;
Expand All @@ -63,13 +67,32 @@ public static TShirt create(String title, String xml, Long categoryId) {
if(tShirt.author == null) throw new RuntimeException("User not logged in.");
if(tShirt.category == null) throw new RuntimeException("Category doesn't exist.");
tShirt.save();
ThumbnailService.get().generateDesignAndThumbnail(tShirt);
return tShirt;
}

public void update(String title, Long categoryId, String xml) {
if(!isAuthorLoggedIn()) throw new RuntimeException("User is not author.");
this.title = title;
this.category = Category.findById(categoryId);
this.xml = xml;
if(this.category == null) throw new RuntimeException("Category doesn't exist.");
save();
ThumbnailService.get().generateDesignAndThumbnail(this);
}

public boolean isAuthorLoggedIn() {
return User.current() == author;
}

public String getDesignPath() {
return BASE_DESIGN_PATH + "/" + id + ".png";
}

public String getThumbnailPath() {
return BASE_DESIGN_PATH + "/" + id + "_thumb.png";
}

public static List<TShirt> findLatest6() {
return TShirt.find("order by created desc").fetch(6);
}
Expand Down
94 changes: 94 additions & 0 deletions app/models/ThumbnailService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package models;

import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import models.design.DesignRenderingService;
import models.design.ImageUtils;
import play.Play;

public class ThumbnailService {

private static final String BASE_TSHIRT_PATH = Play.applicationPath + "/assets/base-tshirt.png";
private static final double ON_SCREEN_DESIGN_WIDTH = 212;
private static final int DESIGN_POSITION_X = 124;
private static final int DESIGN_POSITION_Y = 90;
private static final double THUMBNAIL_SCALE = 0.5;

private static ThumbnailService instance;

public static ThumbnailService get() {
if(instance == null) instance = new ThumbnailService();
return instance;
}

private ThumbnailService() {
}

public void generateDesignAndThumbnail(TShirt tShirt) {
BufferedImage designOnTShirt = composeDesignOnTShirtImage(tShirt);
savePicture(tShirt, designOnTShirt);
saveThumbnail(tShirt, designOnTShirt);
}

private BufferedImage composeDesignOnTShirtImage(TShirt tShirt) {
BufferedImage scaledDesign = getScaledDesign(tShirt);
BufferedImage baseTShirt = getBaseTShirt();
BufferedImage composite = new BufferedImage(baseTShirt.getWidth(), baseTShirt.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = composite.createGraphics();
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
graphics.drawImage(baseTShirt, 0, 0, baseTShirt.getWidth(), baseTShirt.getHeight(), null);
graphics.drawImage(scaledDesign, DESIGN_POSITION_X, DESIGN_POSITION_Y, scaledDesign.getWidth(), scaledDesign.getHeight(), null);
return composite;
}

private BufferedImage getScaledDesign(TShirt tShirt) {
BufferedImage design = DesignRenderingService.get().render(tShirt);
return ImageUtils.scale(
design,
ON_SCREEN_DESIGN_WIDTH / Double.valueOf(design.getWidth()));
}

private BufferedImage getBaseTShirt() {
File file = new File(BASE_TSHIRT_PATH);
byte[] imageData = new byte[(int) file.length()];
try {
FileInputStream stream = new FileInputStream(file);
stream.read(imageData);
stream.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
return ImageUtils.getImage(imageData);
}

private void saveThumbnail(TShirt tShirt, BufferedImage designOnTShirt) {
BufferedImage thumbnail = ImageUtils.scale(designOnTShirt, THUMBNAIL_SCALE);
writeImageToDisk(thumbnail, tShirt.getThumbnailPath());
}

private void savePicture(TShirt tShirt, BufferedImage designOnTShirt) {
writeImageToDisk(designOnTShirt, tShirt.getDesignPath());
}

private void writeImageToDisk(BufferedImage image, String path) {
FileOutputStream stream = null;
try {
stream = new FileOutputStream(path);
stream.write(ImageUtils.getBytes(image));
stream.close();
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}

}
52 changes: 52 additions & 0 deletions app/models/design/AbstractStamp.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package models.design;

public abstract class AbstractStamp {

private double x;
private double y;
private double rotation;
private double scale;

public AbstractStamp() {
}

public AbstractStamp(double x, double y, double rotation, double scale) {
this.x = x;
this.y = y;
this.rotation = rotation;
this.scale = scale;
}

public double getX() {
return x;
}

public void setX(double x) {
this.x = x;
}

public double getY() {
return y;
}

public void setY(double y) {
this.y = y;
}

public double getRotation() {
return rotation;
}

public void setRotation(double rotation) {
this.rotation = rotation;
}

public double getScale() {
return scale;
}

public void setScale(double scale) {
this.scale = scale;
}

}
27 changes: 27 additions & 0 deletions app/models/design/Design.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package models.design;

import java.util.ArrayList;
import java.util.List;

public class Design {

private String tShirtColor;
private List<AbstractStamp> stamps = new ArrayList<AbstractStamp>();

public String getTShirtColor() {
return tShirtColor;
}

public void setTShirtColor(String tShirtColor) {
this.tShirtColor = tShirtColor;
}

public List<AbstractStamp> getStamps() {
return stamps;
}

public void setStamps(List<AbstractStamp> stamps) {
this.stamps = stamps;
}

}
75 changes: 75 additions & 0 deletions app/models/design/DesignParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package models.design;

import java.io.StringReader;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import play.libs.Codec;

public class DesignParser {

private Document document;
private Design design;

public static Design parse(String xml) {
try {
return new DesignParser(xml).design;
} catch (DocumentException e) {
throw new RuntimeException("Cannot parse design XML.", e);
}
}

private DesignParser(String xml) throws DocumentException {
document = new SAXReader().read(new StringReader(xml));
parseDesign();
}

private void parseDesign() {
design = new Design();
setTShirtColor();
setStamps();
}

@SuppressWarnings("unchecked")
private void setStamps() {
for(Element element : (List<Element>) document.getRootElement().elements()) {
if(element.getName().equals("imageStamp")) {
design.getStamps().add(parseImageStamp(element));
} else if(element.getName().equals("textStamp")) {
design.getStamps().add(parseTextStamp(element));
}
}
}

private void setTShirtColor() {
design.setTShirtColor(document.getRootElement().attributeValue("tShirtColor"));
}

private ImageStamp parseImageStamp(Element element) {
ImageStamp imageStamp = new ImageStamp();
parseAbstractStamp(element, imageStamp);
imageStamp.setImage(Codec.decodeBASE64(element.element("image").getText()));
return imageStamp;
}

private TextStamp parseTextStamp(Element element) {
TextStamp textStamp = new TextStamp();
parseAbstractStamp(element, textStamp);
textStamp.setText(element.element("text").getText());
textStamp.setFont(element.element("font").getText());
textStamp.setColor(element.element("color").getText());
return textStamp;
}

private void parseAbstractStamp(Element element, AbstractStamp stamp) {
stamp.setX(Float.valueOf(element.attributeValue("x")));
stamp.setY(Float.valueOf(element.attributeValue("y")));
stamp.setRotation(Float.valueOf(element.attributeValue("rotation")));
stamp.setScale(Float.valueOf(element.attributeValue("scale")));
}

}
Loading

0 comments on commit bdefbfb

Please sign in to comment.