package com.brew.brewshop.pdf; import android.content.Context; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.util.Log; import com.brew.brewshop.R; import com.brew.brewshop.settings.Settings; import com.brew.brewshop.storage.recipes.HopAddition; import com.brew.brewshop.storage.recipes.MaltAddition; import com.brew.brewshop.storage.recipes.Recipe; import com.brew.brewshop.storage.recipes.Weight; import com.brew.brewshop.storage.recipes.Yeast; import com.brew.brewshop.util.IngredientInfo; import com.brew.brewshop.util.UnitConverter; import com.brew.brewshop.util.Util; import com.itextpdf.text.BaseColor; import com.itextpdf.text.Chunk; import com.itextpdf.text.Document; import com.itextpdf.text.DocumentException; import com.itextpdf.text.Element; import com.itextpdf.text.Font; import com.itextpdf.text.Image; import com.itextpdf.text.PageSize; import com.itextpdf.text.Paragraph; import com.itextpdf.text.Phrase; import com.itextpdf.text.Rectangle; import com.itextpdf.text.pdf.PdfPCell; import com.itextpdf.text.pdf.PdfPTable; import com.itextpdf.text.pdf.PdfWriter; import com.itextpdf.text.pdf.draw.LineSeparator; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; public class PdfRecipeWriter { private static final String TAG = PdfRecipeWriter.class.getName(); private static final int NORMAL_POINT = 12; private static final Font TITLE_FONT = new Font(Font.FontFamily.TIMES_ROMAN, 36, Font.BOLD); private static final Font HEADER_FONT = new Font(Font.FontFamily.TIMES_ROMAN, 18, Font.BOLD); private static final Font NORMAL_FONT = new Font(Font.FontFamily.TIMES_ROMAN, NORMAL_POINT, Font.NORMAL); private static final Font SMALL_FONT = new Font(Font.FontFamily.TIMES_ROMAN, 11, Font.NORMAL, new BaseColor(64, 64, 64)); private static final Font SPACING_FONT = new Font(Font.FontFamily.TIMES_ROMAN, 6); private Recipe mRecipe; private Context mContext; private UnitConverter mConverter; private Settings mSettings; //NOTE: There are 72 units per inch public PdfRecipeWriter(Context context, Recipe recipe) { mContext = context; mRecipe = recipe; mConverter = new UnitConverter(context); mSettings = new Settings(context); } public void write(OutputStream outStream) { try { Document document = newDocument(); PdfWriter.getInstance(document, outStream); document.open(); addMetaData(document); addHeader(document); addRecipeInfo(document); addIngredients(document); addNotes(document); document.close(); } catch (Exception e) { Log.e(TAG, "Error writing PDF", e); } finally { try { outStream.close(); } catch (IOException e) { Log.e(TAG, "Error closing stream", e); } } } private Document newDocument() { Document document = new Document(); document.setPageSize(PageSize.LETTER); document.setMargins(72, 72, 72, 72); return document; } private void addHeader(Document document) throws Exception { Image image = loadDrawable(R.drawable.ic_launcher, 26); Paragraph para = new Paragraph(); para.setAlignment(Element.ALIGN_CENTER); para.setIndentationLeft(20); para.setIndentationRight(20); para.setSpacingBefore(0); para.setSpacingAfter(24); para.add(new Chunk(image, 0, 0)); para.add(new Phrase(" ", TITLE_FONT)); para.add(new Phrase(mContext.getString(R.string.brew_shop_recipe), TITLE_FONT)); para.add(new Phrase(" ", TITLE_FONT)); para.add(new Chunk(image, 0, 0)); document.add(para); } private void addRecipeInfo(Document document) throws DocumentException { int iconRes = mRecipe.getStyle().getIconDrawable(); Image image = loadDrawable(iconRes, 40); Paragraph namePara = new Paragraph(); namePara.setSpacingBefore(0); namePara.add(new Phrase(mRecipe.getName() + "\n", HEADER_FONT)); namePara.add(new Phrase("\n", new Font(Font.FontFamily.TIMES_ROMAN, 2))); namePara.add(new Phrase(mRecipe.getStyle().getDisplayName(), SMALL_FONT)); PdfPTable table = new PdfPTable(new float[] {50, 400}); table.setHorizontalAlignment(Element.ALIGN_LEFT); PdfPCell cellOne = new PdfPCell(image); cellOne.setBorder(Rectangle.NO_BORDER); PdfPCell cellTwo = new PdfPCell(namePara); cellTwo.setBorder(Rectangle.NO_BORDER); table.addCell(cellOne); table.addCell(cellTwo); document.add(table); addLineSeparator(document); Paragraph setupPara = new Paragraph(); setupPara.add(new Phrase("Batch Volume: " + mConverter.fromGallonsWithUnits(mRecipe.getBatchVolume(), 1), NORMAL_FONT)); setupPara.add(new Phrase("\n\n", SPACING_FONT)); setupPara.add(new Phrase("Boil Volume: " + mConverter.fromGallonsWithUnits(mRecipe.getBoilVolume(), 1), NORMAL_FONT)); setupPara.add(new Phrase("\n\n", SPACING_FONT)); setupPara.add(new Phrase("Boil Time: " + Util.fromDouble(mRecipe.getBoilTime(), 0) + " minutes", NORMAL_FONT)); setupPara.add(new Phrase("\n\n", SPACING_FONT)); setupPara.add(new Phrase("Efficiency: " + Util.fromDouble(mRecipe.getEfficiency(), 1) + "%", NORMAL_FONT)); Paragraph para = new Paragraph(); String og = ""; switch (mSettings.getExtractUnits()) { case SPECIFIC_GRAVITY: og = Util.fromDouble(mRecipe.getOg(), 3, false); break; case DEGREES_PLATO: og = Util.fromDouble(mRecipe.getOgPlato(), 1, false) + "°P"; break; } para.add(new Phrase("OG: " + og, NORMAL_FONT)); para.add(new Phrase("\n\n", SPACING_FONT)); para.add(new Phrase("IBU: " + Util.fromDouble(mRecipe.getTotalIbu(), 1), NORMAL_FONT)); para.add(new Phrase("\n\n", SPACING_FONT)); para.add(new Phrase("SRM: " + Util.fromDouble(mRecipe.getSrm(), 1), NORMAL_FONT)); para.add(new Phrase("\n\n", SPACING_FONT)); String fg = "n/a"; if (mRecipe.hasYeast()) { switch (mSettings.getExtractUnits()) { case SPECIFIC_GRAVITY: fg = Util.fromDouble(mRecipe.getFg(), 3, false); break; case DEGREES_PLATO: fg = Util.fromDouble(mRecipe.getFgPlato(), 1, false) + "°P"; break; } } para.add(new Phrase("Estimated FG: " + fg, NORMAL_FONT)); para.add(new Phrase("\n\n", SPACING_FONT)); String abv = "n/a"; if (mRecipe.hasYeast()) { abv = Util.fromDouble(mRecipe.getAbv(), 1) + "%"; } para.add(new Phrase("Estimated ABV: " + abv, NORMAL_FONT)); PdfPTable statsTable = new PdfPTable(new float[] {200, 200}); statsTable.setHorizontalAlignment(Element.ALIGN_LEFT); PdfPCell statsCellOne = new PdfPCell(para); statsCellOne.setBorder(Rectangle.NO_BORDER); PdfPCell statsCellTwo = new PdfPCell(setupPara); statsCellTwo.setBorder(Rectangle.NO_BORDER); statsTable.addCell(statsCellOne); statsTable.addCell(statsCellTwo); document.add(statsTable); } private void addIngredients(Document document) throws DocumentException { Paragraph titlePara = new Paragraph(mContext.getString(R.string.ingredients), HEADER_FONT); document.add(titlePara); addLineSeparator(document); for (Object ingredient : mRecipe.getIngredients()) { if (ingredient instanceof MaltAddition) { addIngredient((MaltAddition) ingredient, document); } else if (ingredient instanceof HopAddition) { addIngredient((HopAddition) ingredient, document); } else if (ingredient instanceof Yeast) { addIngredient((Yeast) ingredient, document); } document.add(new Paragraph(" ", SPACING_FONT)); } } private void addIngredient(MaltAddition malt, Document document) throws DocumentException { Image image = loadDrawable(R.drawable.barley_cap, 30); Paragraph namePara = new Paragraph(); namePara.setSpacingBefore(0); namePara.add(new Phrase(formatWeight(malt.getWeight(), 2) + " ", NORMAL_FONT)); namePara.add(new Phrase(malt.getMalt().getName() + "\n", NORMAL_FONT)); namePara.add(new Phrase("\n", new Font(Font.FontFamily.TIMES_ROMAN, 2))); namePara.add(new Phrase(IngredientInfo.getInfo(malt, mRecipe), SMALL_FONT)); PdfPTable table = new PdfPTable(new float[] {40, 400}); table.setHorizontalAlignment(Element.ALIGN_LEFT); PdfPCell cellOne = new PdfPCell(image); cellOne.setBorder(Rectangle.NO_BORDER); PdfPCell cellTwo = new PdfPCell(namePara); cellTwo.setBorder(Rectangle.NO_BORDER); table.addCell(cellOne); table.addCell(cellTwo); document.add(table); } private void addIngredient(HopAddition hop, Document document) throws DocumentException { Image image = loadDrawable(R.drawable.hops_cap, 30); Paragraph namePara = new Paragraph(); namePara.setSpacingBefore(0); namePara.add(new Phrase(formatWeight(hop.getWeight(), 3) + " ", NORMAL_FONT)); namePara.add(new Phrase(hop.getHop().getName() + "\n", NORMAL_FONT)); namePara.add(new Phrase("\n", new Font(Font.FontFamily.TIMES_ROMAN, 2))); namePara.add(new Phrase(IngredientInfo.getInfo(hop), SMALL_FONT)); PdfPTable table = new PdfPTable(new float[] {40, 400}); table.setHorizontalAlignment(Element.ALIGN_LEFT); PdfPCell cellOne = new PdfPCell(image); cellOne.setBorder(Rectangle.NO_BORDER); PdfPCell cellTwo = new PdfPCell(namePara); cellTwo.setBorder(Rectangle.NO_BORDER); table.addCell(cellOne); table.addCell(cellTwo); document.add(table); } private void addIngredient(Yeast yeast, Document document) throws DocumentException { Image image = loadDrawable(R.drawable.yeast_cap, 30); Paragraph namePara = new Paragraph(); namePara.setSpacingBefore(0); namePara.add(new Phrase("1 Pkg. " + yeast.getName() + "\n", NORMAL_FONT)); namePara.add(new Phrase("\n", new Font(Font.FontFamily.TIMES_ROMAN, 2))); namePara.add(new Phrase(IngredientInfo.getInfo(yeast), SMALL_FONT)); PdfPTable table = new PdfPTable(new float[] {40, 400}); table.setHorizontalAlignment(Element.ALIGN_LEFT); PdfPCell cellOne = new PdfPCell(image); cellOne.setBorder(Rectangle.NO_BORDER); PdfPCell cellTwo = new PdfPCell(namePara); cellTwo.setBorder(Rectangle.NO_BORDER); table.addCell(cellOne); table.addCell(cellTwo); document.add(table); } private void addNotes(Document document) throws DocumentException { if (!mRecipe.getNotes().equals("")) { document.add(new Paragraph(mContext.getString(R.string.notes), HEADER_FONT)); addLineSeparator(document); Paragraph notesPara = new Paragraph(mRecipe.getNotes(), NORMAL_FONT); notesPara.setLeading(NORMAL_POINT); document.add(notesPara); } } private void addMetaData(Document document) { String title = mContext.getString(R.string.brew_shop_recipe_colon) + " " + mRecipe.getName(); String author = mContext.getString(R.string.brew_shop); document.addTitle(title); document.addSubject(title); document.addAuthor(author); document.addCreator(author); } private void addLineSeparator(Document document) throws DocumentException { document.add(new Paragraph(" ", SPACING_FONT)); document.add(new LineSeparator(0.25f, 100, BaseColor.LIGHT_GRAY, Element.ALIGN_LEFT, 0)); document.add(new Paragraph(" ", SPACING_FONT)); } private String formatWeight(Weight weight, int significance) { String string = ""; switch (mSettings.getUnits()) { case IMPERIAL: string = Util.formatImperialWeight(weight, significance); break; case METRIC: string = Util.formatMetricWeight(weight, significance); break; } return string; } private Image loadDrawable(int resId, float scale) { Drawable d = mContext.getResources().getDrawable(resId); BitmapDrawable bitDw = ((BitmapDrawable) d); Bitmap bmp = bitDw.getBitmap(); ByteArrayOutputStream stream = new ByteArrayOutputStream(); bmp.compress(Bitmap.CompressFormat.PNG, 100, stream); Image image = null; try { image = Image.getInstance(stream.toByteArray()); image.scaleAbsolute(scale, scale); } catch (Exception e) { e.printStackTrace(); } return image; } }