/** * Process the text so that it will render with a combination of fonts if needed. * * @param text the text * @return a <CODE>Phrase</CODE> with one or more chunks */ public Phrase process(String text) { int fsize = fonts.size(); if (fsize == 0) throw new IndexOutOfBoundsException("No font is defined."); char cc[] = text.toCharArray(); int len = cc.length; StringBuffer sb = new StringBuffer(); Font font = null; int lastidx = -1; Phrase ret = new Phrase(); for (int k = 0; k < len; ++k) { char c = cc[k]; if (c == '\n' || c == '\r') { sb.append(c); continue; } if (Utilities.isSurrogatePair(cc, k)) { int u = Utilities.convertToUtf32(cc, k); for (int f = 0; f < fsize; ++f) { font = (Font) fonts.get(f); if (font.getBaseFont().charExists(u)) { if (lastidx != f) { if (sb.length() > 0 && lastidx != -1) { Chunk ck = new Chunk(sb.toString(), (Font) fonts.get(lastidx)); ret.add(ck); sb.setLength(0); } lastidx = f; } sb.append(c); sb.append(cc[++k]); break; } } } else { for (int f = 0; f < fsize; ++f) { font = (Font) fonts.get(f); if (font.getBaseFont().charExists(c)) { if (lastidx != f) { if (sb.length() > 0 && lastidx != -1) { Chunk ck = new Chunk(sb.toString(), (Font) fonts.get(lastidx)); ret.add(ck); sb.setLength(0); } lastidx = f; } sb.append(c); break; } } } } if (sb.length() > 0) { Chunk ck = new Chunk(sb.toString(), (Font) fonts.get(lastidx == -1 ? 0 : lastidx)); ret.add(ck); } return ret; }
/** * Truncates this <CODE>PdfChunk</CODE> if it's too long for the given width. * * <p>Returns <VAR>null</VAR> if the <CODE>PdfChunk</CODE> wasn't truncated. * * @param width a given width * @return the <CODE>PdfChunk</CODE> that doesn't fit into the width. */ PdfChunk truncate(float width) { if (image != null) { if (image.getScaledWidth() > width) { PdfChunk pc = new PdfChunk("", this); value = ""; attributes.remove(Chunk.IMAGE); image = null; font = PdfFont.getDefaultFont(); return pc; } else return null; } int currentPosition = 0; float currentWidth = 0; // it's no use trying to split if there isn't even enough place for a space if (width < font.width()) { String returnValue = value.substring(1); value = value.substring(0, 1); PdfChunk pc = new PdfChunk(returnValue, this); return pc; } // loop over all the characters of a string // or until the totalWidth is reached int length = value.length(); boolean surrogate = false; char character; while (currentPosition < length) { // the width of every character is added to the currentWidth surrogate = Utilities.isSurrogatePair(value, currentPosition); if (surrogate) currentWidth += font.width(Utilities.convertToUtf32(value, currentPosition)); else currentWidth += font.width(value.charAt(currentPosition)); if (currentWidth > width) break; if (surrogate) currentPosition++; currentPosition++; } // if all the characters fit in the total width, null is returned (there is no overflow) if (currentPosition == length) { return null; } // otherwise, the string has to be truncated // currentPosition -= 2; // we have to chop off minimum 1 character from the chunk if (currentPosition == 0) { currentPosition = 1; if (surrogate) ++currentPosition; } String returnValue = value.substring(currentPosition); value = value.substring(0, currentPosition); PdfChunk pc = new PdfChunk(returnValue, this); return pc; }
int lengthUtf32() { if (!BaseFont.IDENTITY_H.equals(encoding)) return value.length(); int total = 0; int len = value.length(); for (int k = 0; k < len; ++k) { if (Utilities.isSurrogateHigh(value.charAt(k))) ++k; ++total; } return total; }
/** * Constructs an <CODE>ImgWMF</CODE>-object, using a <VAR>filename</VAR>. * * @param filename a <CODE>String</CODE>-representation of the file that contains the image. * @throws BadElementException on error * @throws MalformedURLException on error * @throws IOException on error */ public ImgWMF(String filename) throws BadElementException, MalformedURLException, IOException { this(Utilities.toURL(filename)); }
/** * Splits this <CODE>PdfChunk</CODE> if it's too long for the given width. * * <p>Returns <VAR>null</VAR> if the <CODE>PdfChunk</CODE> wasn't truncated. * * @param width a given width * @return the <CODE>PdfChunk</CODE> that doesn't fit into the width. */ PdfChunk split(float width) { newlineSplit = false; if (image != null) { if (image.getScaledWidth() > width) { PdfChunk pc = new PdfChunk(Chunk.OBJECT_REPLACEMENT_CHARACTER, this); value = ""; attributes = new HashMap(); image = null; font = PdfFont.getDefaultFont(); return pc; } else return null; } HyphenationEvent hyphenationEvent = (HyphenationEvent) noStroke.get(Chunk.HYPHENATION); int currentPosition = 0; int splitPosition = -1; float currentWidth = 0; // loop over all the characters of a string // or until the totalWidth is reached int lastSpace = -1; float lastSpaceWidth = 0; int length = value.length(); char valueArray[] = value.toCharArray(); char character = 0; BaseFont ft = font.getFont(); boolean surrogate = false; if (ft.getFontType() == BaseFont.FONT_TYPE_CJK && ft.getUnicodeEquivalent(' ') != ' ') { while (currentPosition < length) { // the width of every character is added to the currentWidth char cidChar = valueArray[currentPosition]; character = (char) ft.getUnicodeEquivalent(cidChar); // if a newLine or carriageReturn is encountered if (character == '\n') { newlineSplit = true; String returnValue = value.substring(currentPosition + 1); value = value.substring(0, currentPosition); if (value.length() < 1) { value = "\u0001"; } PdfChunk pc = new PdfChunk(returnValue, this); return pc; } currentWidth += font.width(cidChar); if (character == ' ') { lastSpace = currentPosition + 1; lastSpaceWidth = currentWidth; } if (currentWidth > width) break; // if a split-character is encountered, the splitPosition is altered if (splitCharacter.isSplitCharacter(0, currentPosition, length, valueArray, thisChunk)) splitPosition = currentPosition + 1; currentPosition++; } } else { while (currentPosition < length) { // the width of every character is added to the currentWidth character = valueArray[currentPosition]; // if a newLine or carriageReturn is encountered if (character == '\r' || character == '\n') { newlineSplit = true; int inc = 1; if (character == '\r' && currentPosition + 1 < length && valueArray[currentPosition + 1] == '\n') inc = 2; String returnValue = value.substring(currentPosition + inc); value = value.substring(0, currentPosition); if (value.length() < 1) { value = " "; } PdfChunk pc = new PdfChunk(returnValue, this); return pc; } surrogate = Utilities.isSurrogatePair(valueArray, currentPosition); if (surrogate) currentWidth += font.width( Utilities.convertToUtf32( valueArray[currentPosition], valueArray[currentPosition + 1])); else currentWidth += font.width(character); if (character == ' ') { lastSpace = currentPosition + 1; lastSpaceWidth = currentWidth; } if (surrogate) currentPosition++; if (currentWidth > width) break; // if a split-character is encountered, the splitPosition is altered if (splitCharacter.isSplitCharacter(0, currentPosition, length, valueArray, null)) splitPosition = currentPosition + 1; currentPosition++; } } // if all the characters fit in the total width, null is returned (there is no overflow) if (currentPosition == length) { return null; } // otherwise, the string has to be truncated if (splitPosition < 0) { String returnValue = value; value = ""; PdfChunk pc = new PdfChunk(returnValue, this); return pc; } if (lastSpace > splitPosition && splitCharacter.isSplitCharacter(0, 0, 1, singleSpace, null)) splitPosition = lastSpace; if (hyphenationEvent != null && lastSpace >= 0 && lastSpace < currentPosition) { int wordIdx = getWord(value, lastSpace); if (wordIdx > lastSpace) { String pre = hyphenationEvent.getHyphenatedWordPre( value.substring(lastSpace, wordIdx), font.getFont(), font.size(), width - lastSpaceWidth); String post = hyphenationEvent.getHyphenatedWordPost(); if (pre.length() > 0) { String returnValue = post + value.substring(wordIdx); value = trim(value.substring(0, lastSpace) + pre); PdfChunk pc = new PdfChunk(returnValue, this); return pc; } } } String returnValue = value.substring(splitPosition); value = trim(value.substring(0, splitPosition)); PdfChunk pc = new PdfChunk(returnValue, this); return pc; }
/** * Constructs a <CODE>PdfChunk</CODE>-object. * * @param chunk the original <CODE>Chunk</CODE>-object * @param action the <CODE>PdfAction</CODE> if the <CODE>Chunk</CODE> comes from an <CODE>Anchor * </CODE> */ PdfChunk(Chunk chunk, PdfAction action) { thisChunk[0] = this; value = chunk.getContent(); Font f = chunk.getFont(); float size = f.getSize(); if (size == Font.UNDEFINED) size = 12; baseFont = f.getBaseFont(); int style = f.getStyle(); if (style == Font.UNDEFINED) { style = Font.NORMAL; } if (baseFont == null) { // translation of the font-family to a PDF font-family baseFont = f.getCalculatedBaseFont(false); } else { // bold simulation if ((style & Font.BOLD) != 0) attributes.put( Chunk.TEXTRENDERMODE, new Object[] { new Integer(PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE), new Float(size / 30f), null }); // italic simulation if ((style & Font.ITALIC) != 0) attributes.put(Chunk.SKEW, new float[] {0, ITALIC_ANGLE}); } font = new PdfFont(baseFont, size); // other style possibilities HashMap attr = chunk.getAttributes(); if (attr != null) { for (Iterator i = attr.entrySet().iterator(); i.hasNext(); ) { Map.Entry entry = (Map.Entry) i.next(); Object name = entry.getKey(); if (keysAttributes.containsKey(name)) { attributes.put(name, entry.getValue()); } else if (keysNoStroke.containsKey(name)) { noStroke.put(name, entry.getValue()); } } if ("".equals(attr.get(Chunk.GENERICTAG))) { attributes.put(Chunk.GENERICTAG, chunk.getContent()); } } if (f.isUnderlined()) { Object obj[] = {null, new float[] {0, 1f / 15, 0, -1f / 3, 0}}; Object unders[][] = Utilities.addToArray((Object[][]) attributes.get(Chunk.UNDERLINE), obj); attributes.put(Chunk.UNDERLINE, unders); } if (f.isStrikethru()) { Object obj[] = {null, new float[] {0, 1f / 15, 0, 1f / 3, 0}}; Object unders[][] = Utilities.addToArray((Object[][]) attributes.get(Chunk.UNDERLINE), obj); attributes.put(Chunk.UNDERLINE, unders); } if (action != null) attributes.put(Chunk.ACTION, action); // the color can't be stored in a PdfFont noStroke.put(Chunk.COLOR, f.getColor()); noStroke.put(Chunk.ENCODING, font.getFont().getEncoding()); Object obj[] = (Object[]) attributes.get(Chunk.IMAGE); if (obj == null) { image = null; } else { attributes.remove(Chunk.HSCALE); // images are scaled in other ways image = (Image) obj[0]; offsetX = ((Float) obj[1]).floatValue(); offsetY = ((Float) obj[2]).floatValue(); changeLeading = ((Boolean) obj[3]).booleanValue(); } font.setImage(image); Float hs = (Float) attributes.get(Chunk.HSCALE); if (hs != null) font.setHorizontalScaling(hs.floatValue()); encoding = font.getFont().getEncoding(); splitCharacter = (SplitCharacter) noStroke.get(Chunk.SPLITCHARACTER); if (splitCharacter == null) splitCharacter = DefaultSplitCharacter.DEFAULT; }
/** * Converts the text into bytes to be placed in the document. The conversion is done according to * the font and the encoding and the characters used are stored. * * @param text the text to convert * @return the conversion */ byte[] convertToBytes(final String text) { byte b[] = null; switch (this.fontType) { case BaseFont.FONT_TYPE_T3: return this.baseFont.convertToBytes(text); case BaseFont.FONT_TYPE_T1: case BaseFont.FONT_TYPE_TT: { b = this.baseFont.convertToBytes(text); final int len = b.length; for (int k = 0; k < len; ++k) { this.shortTag[b[k] & 0xff] = 1; } break; } case BaseFont.FONT_TYPE_CJK: { final int len = text.length(); for (int k = 0; k < len; ++k) { this.cjkTag.put(this.cjkFont.getCidCode(text.charAt(k)), 0); } b = this.baseFont.convertToBytes(text); break; } case BaseFont.FONT_TYPE_DOCUMENT: { b = this.baseFont.convertToBytes(text); break; } case BaseFont.FONT_TYPE_TTUNI: { try { int len = text.length(); int metrics[] = null; final char glyph[] = new char[len]; int i = 0; if (this.symbolic) { b = PdfEncodings.convertToBytes(text, "symboltt"); len = b.length; for (int k = 0; k < len; ++k) { metrics = this.ttu.getMetricsTT(b[k] & 0xff); if (metrics == null) { continue; } this.longTag.put( new Integer(metrics[0]), new int[] { metrics[0], metrics[1], this.ttu.getUnicodeDifferences(b[k] & 0xff) }); glyph[i++] = (char) metrics[0]; } } else { for (int k = 0; k < len; ++k) { int val; if (Utilities.isSurrogatePair(text, k)) { val = Utilities.convertToUtf32(text, k); k++; } else { val = text.charAt(k); } metrics = this.ttu.getMetricsTT(val); if (metrics == null) { continue; } final int m0 = metrics[0]; final Integer gl = new Integer(m0); if (!this.longTag.containsKey(gl)) { this.longTag.put(gl, new int[] {m0, metrics[1], val}); } glyph[i++] = (char) m0; } } final String s = new String(glyph, 0, i); b = s.getBytes(CJKFont.CJK_ENCODING); } catch (final UnsupportedEncodingException e) { throw new ExceptionConverter(e); } break; } } return b; }
void readPng() throws IOException { for (int i = 0; i < PNGID.length; i++) { if (PNGID[i] != is.read()) { throw new IOException("File is not a valid PNG."); } } byte buffer[] = new byte[TRANSFERSIZE]; while (true) { int len = getInt(is); String marker = getString(is); if (len < 0 || !checkMarker(marker)) throw new IOException("Corrupted PNG file."); if (IDAT.equals(marker)) { int size; while (len != 0) { size = is.read(buffer, 0, Math.min(len, TRANSFERSIZE)); if (size < 0) return; idat.write(buffer, 0, size); len -= size; } } else if (tRNS.equals(marker)) { switch (colorType) { case 0: if (len >= 2) { len -= 2; int gray = getWord(is); if (bitDepth == 16) transRedGray = gray; else additional.put(PdfName.MASK, new PdfLiteral("[" + gray + " " + gray + "]")); } break; case 2: if (len >= 6) { len -= 6; int red = getWord(is); int green = getWord(is); int blue = getWord(is); if (bitDepth == 16) { transRedGray = red; transGreen = green; transBlue = blue; } else additional.put( PdfName.MASK, new PdfLiteral( "[" + red + " " + red + " " + green + " " + green + " " + blue + " " + blue + "]")); } break; case 3: if (len > 0) { trans = new byte[len]; for (int k = 0; k < len; ++k) trans[k] = (byte) is.read(); len = 0; } break; } Utilities.skip(is, len); } else if (IHDR.equals(marker)) { width = getInt(is); height = getInt(is); bitDepth = is.read(); colorType = is.read(); compressionMethod = is.read(); filterMethod = is.read(); interlaceMethod = is.read(); } else if (PLTE.equals(marker)) { if (colorType == 3) { PdfArray colorspace = new PdfArray(); colorspace.add(PdfName.INDEXED); colorspace.add(getColorspace()); colorspace.add(new PdfNumber(len / 3 - 1)); ByteBuffer colortable = new ByteBuffer(); while ((len--) > 0) { colortable.append_i(is.read()); } colorspace.add(new PdfString(colorTable = colortable.toByteArray())); additional.put(PdfName.COLORSPACE, colorspace); } else { Utilities.skip(is, len); } } else if (pHYs.equals(marker)) { int dx = getInt(is); int dy = getInt(is); int unit = is.read(); if (unit == 1) { dpiX = (int) ((float) dx * 0.0254f + 0.5f); dpiY = (int) ((float) dy * 0.0254f + 0.5f); } else { if (dy != 0) XYRatio = (float) dx / (float) dy; } } else if (cHRM.equals(marker)) { xW = (float) getInt(is) / 100000f; yW = (float) getInt(is) / 100000f; xR = (float) getInt(is) / 100000f; yR = (float) getInt(is) / 100000f; xG = (float) getInt(is) / 100000f; yG = (float) getInt(is) / 100000f; xB = (float) getInt(is) / 100000f; yB = (float) getInt(is) / 100000f; hasCHRM = !(Math.abs(xW) < 0.0001f || Math.abs(yW) < 0.0001f || Math.abs(xR) < 0.0001f || Math.abs(yR) < 0.0001f || Math.abs(xG) < 0.0001f || Math.abs(yG) < 0.0001f || Math.abs(xB) < 0.0001f || Math.abs(yB) < 0.0001f); } else if (sRGB.equals(marker)) { int ri = is.read(); intent = intents[ri]; gamma = 2.2f; xW = 0.3127f; yW = 0.329f; xR = 0.64f; yR = 0.33f; xG = 0.3f; yG = 0.6f; xB = 0.15f; yB = 0.06f; hasCHRM = true; } else if (gAMA.equals(marker)) { int gm = getInt(is); if (gm != 0) { gamma = 100000f / (float) gm; if (!hasCHRM) { xW = 0.3127f; yW = 0.329f; xR = 0.64f; yR = 0.33f; xG = 0.3f; yG = 0.6f; xB = 0.15f; yB = 0.06f; hasCHRM = true; } } } else if (iCCP.equals(marker)) { do { --len; } while (is.read() != 0); is.read(); --len; byte icccom[] = new byte[len]; int p = 0; while (len > 0) { int r = is.read(icccom, p, len); if (r < 0) throw new IOException("Premature end of file."); p += r; len -= r; } byte iccp[] = PdfReader.FlateDecode(icccom, true); icccom = null; // try { // icc_profile = ICC_Profile.getInstance(iccp); // } // catch (Exception e) { icc_profile = null; // } } else if (IEND.equals(marker)) { break; } else { Utilities.skip(is, len); } Utilities.skip(is, 4); } }
/** * Reads a PNG from a file. * * @param file the file * @throws IOException on error * @return the image */ public static Image getImage(String file) throws IOException { return getImage(Utilities.toURL(file)); }