123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687 |
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /* $Id$ */
-
- package org.apache.fop.render.rtf.rtflib.rtfdoc;
-
- /*
- * This file is part of the RTF library of the FOP project, which was originally
- * created by Bertrand Delacretaz <bdelacretaz@codeconsult.ch> and by other
- * contributors to the jfor project (www.jfor.org), who agreed to donate jfor to
- * the FOP project.
- */
-
- import java.io.File;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.Writer;
- import java.net.MalformedURLException;
- import java.net.URL;
-
- import org.apache.commons.io.IOUtils;
-
- import org.apache.fop.render.rtf.rtflib.tools.ImageConstants;
- import org.apache.fop.render.rtf.rtflib.tools.ImageUtil;
-
- /**
- * Creates an RTF image from an external graphic file.
- * This class belongs to the <fo:external-graphic> tag processing. <br>
- *
- * Supports relative path like "../test.gif", too (01-08-24) <br>
- *
- * Limitations:
- * <li> Only the image types PNG, JPEG and EMF are supported
- * <li> The GIF is supported, too, but will be converted to JPG
- * <li> Only the attributes SRC (required), WIDTH, HEIGHT, SCALING are supported
- * <li> The SCALING attribute supports (uniform | non-uniform)
- *
- * Known Bugs:
- * <li> If the emf image has a desired size, the image will be clipped
- * <li> The emf, jpg & png image will not be displayed in correct size
- *
- * @author <a href="mailto:a.putz@skynamics.com">Andreas Putz</a>
- * @author Gianugo Rabellino gianugo@rabellino.it
- */
-
- public class RtfExternalGraphic extends RtfElement {
- /** Exception thrown when an image file/URL cannot be read */
- public static class ExternalGraphicException extends IOException {
- ExternalGraphicException(String reason) {
- super(reason);
- }
- }
-
- //////////////////////////////////////////////////
- // Supported Formats
- //////////////////////////////////////////////////
- private static class FormatBase {
-
- /**
- * Determines whether the image is in the according format.
- *
- * @param data Image
- *
- * @return
- * true If according type\n
- * false Other type
- */
- public static boolean isFormat(byte[] data) {
- return false;
- }
-
- /**
- * Convert image data if necessary - for example when format is not supported by rtf.
- *
- * @param data Image
- * @param type Format type
- */
- public FormatBase convert(FormatBase format, byte[] data) {
- return format;
- }
-
- /**
- * Determine image file format.
- *
- * @param data Image
- *
- * @return Image format class
- */
-
- public static FormatBase determineFormat(byte[] data) {
-
- if (FormatPNG.isFormat(data)) {
- return new FormatPNG();
- } else if (FormatJPG.isFormat(data)) {
- return new FormatJPG();
- } else if (FormatEMF.isFormat(data)) {
- return new FormatEMF();
- } else if (FormatGIF.isFormat(data)) {
- return new FormatGIF();
- } else if (FormatBMP.isFormat(data)) {
- return new FormatBMP();
- } else {
- return null;
- }
- }
-
- /**
- * Get image type.
- *
- * @return Image format class
- */
- public int getType() {
- return ImageConstants.I_NOT_SUPPORTED;
- }
-
- /**
- * Get rtf tag.
- *
- * @return Rtf tag for image format.
- */
- public String getRtfTag() {
- return "";
- }
- }
-
- private static class FormatGIF extends FormatBase {
- public static boolean isFormat(byte[] data) {
- // Indentifier "GIF8" on position 0
- byte [] pattern = new byte [] {(byte) 0x47, (byte) 0x49, (byte) 0x46, (byte) 0x38};
-
- return ImageUtil.compareHexValues(pattern, data, 0, true);
- }
-
- public int getType() {
- return ImageConstants.I_GIF;
- }
- }
-
- private static class FormatEMF extends FormatBase {
- public static boolean isFormat(byte[] data) {
- // No offical Indentifier known
- byte [] pattern = new byte [] {(byte) 0x01, (byte) 0x00, (byte) 0x00};
-
- return ImageUtil.compareHexValues(pattern, data, 0, true);
- }
-
- public int getType() {
- return ImageConstants.I_EMF;
- }
-
- public String getRtfTag() {
- return "emfblip";
- }
- }
-
- private static class FormatBMP extends FormatBase {
- public static boolean isFormat(byte[] data) {
- byte [] pattern = new byte [] {(byte) 0x42, (byte) 0x4D};
-
- return ImageUtil.compareHexValues(pattern, data, 0, true);
- }
-
- public int getType() {
- return ImageConstants.I_BMP;
- }
- }
-
- private static class FormatJPG extends FormatBase {
- public static boolean isFormat(byte[] data) {
- // Indentifier "0xFFD8" on position 0
- byte [] pattern = new byte [] {(byte) 0xFF, (byte) 0xD8};
-
- return ImageUtil.compareHexValues(pattern, data, 0, true);
- }
-
- public int getType() {
- return ImageConstants.I_JPG;
- }
-
- public String getRtfTag() {
- return "jpegblip";
- }
- }
-
- private static class FormatPNG extends FormatBase {
- public static boolean isFormat(byte[] data) {
- // Indentifier "PNG" on position 1
- byte [] pattern = new byte [] {(byte) 0x50, (byte) 0x4E, (byte) 0x47};
-
- return ImageUtil.compareHexValues(pattern, data, 1, true);
- }
-
- public int getType() {
- return ImageConstants.I_PNG;
- }
-
- public String getRtfTag() {
- return "pngblip";
- }
- }
-
- //////////////////////////////////////////////////
- // @@ Members
- //////////////////////////////////////////////////
-
-
- /**
- * The url of the image
- */
- protected URL url = null;
-
- /**
- * The height of the image (in pixels)
- */
- protected int height = -1;
-
- /**
- * The desired percent value of the height
- */
- protected int heightPercent = -1;
-
- /**
- * The desired height (in twips)
- */
- protected int heightDesired = -1;
-
- /**
- * Flag whether the desired height is a percentage
- */
- protected boolean perCentH = false;
-
- /**
- * The width of the image (in pixels)
- */
- protected int width = -1;
-
- /**
- * The desired percent value of the width
- */
- protected int widthPercent = -1;
-
- /**
- * The desired width (in twips)
- */
- protected int widthDesired = -1;
-
- /**
- * Flag whether the desired width is a percentage
- */
- protected boolean perCentW = false;
-
- /**
- * Flag whether the image size shall be adjusted
- */
- protected boolean scaleUniform = false;
-
- /** cropping on left/top/right/bottom edges for \piccrop*N */
- private int[] cropValues = new int[4];
-
- /**
- * Graphic compression rate
- */
- protected int graphicCompressionRate = 80;
-
- /** The image data */
- private byte[] imagedata = null;
-
- /** The image format */
- private FormatBase imageformat;
-
- //////////////////////////////////////////////////
- // @@ Construction
- //////////////////////////////////////////////////
-
-
- /**
- * Default constructor.
- * Create an RTF element as a child of given container.
- *
- * @param container a <code>RtfContainer</code> value
- * @param writer a <code>Writer</code> value
- * @throws IOException for I/O problems
- */
- public RtfExternalGraphic(RtfContainer container, Writer writer) throws IOException {
- super (container, writer);
- }
-
- /**
- * Default constructor.
- *
- * @param container a <code>RtfContainer</code> value
- * @param writer a <code>Writer</code> value
- * @param attributes a <code>RtfAttributes</code> value
- * @throws IOException for I/O problems
- */
- public RtfExternalGraphic(RtfContainer container, Writer writer,
- RtfAttributes attributes) throws IOException {
- super (container, writer, attributes);
- }
-
-
- //////////////////////////////////////////////////
- // @@ RtfElement implementation
- //////////////////////////////////////////////////
-
- /**
- * RtfElement override - catches ExternalGraphicException and writes a warning
- * message to the document if image cannot be read
- * @throws IOException for I/O problems
- */
- protected void writeRtfContent() throws IOException {
- try {
- writeRtfContentWithException();
- } catch (ExternalGraphicException ie) {
- writeExceptionInRtf(ie);
- }
- }
-
- /**
- * Writes the RTF content to m_writer - this one throws ExternalGraphicExceptions
- *
- * @exception IOException On error
- */
- protected void writeRtfContentWithException() throws IOException {
-
- if (writer == null) {
- return;
- }
-
-
- if (url == null && imagedata == null) {
- throw new ExternalGraphicException(
- "No image data is available (neither URL, nor in-memory)");
- }
-
- String linkToRoot = System.getProperty("jfor_link_to_root");
- if (url != null && linkToRoot != null) {
- writer.write("{\\field {\\* \\fldinst { INCLUDEPICTURE \"");
- writer.write(linkToRoot);
- File urlFile = new File(url.getFile());
- writer.write(urlFile.getName());
- writer.write("\" \\\\* MERGEFORMAT \\\\d }}}");
- return;
- }
-
- // getRtfFile ().getLog ().logInfo ("Writing image '" + url + "'.");
-
-
- if (imagedata == null) {
- try {
- final InputStream in = url.openStream();
- try {
- imagedata = IOUtils.toByteArray(url.openStream());
- } finally {
- IOUtils.closeQuietly(in);
- }
- } catch (Exception e) {
- throw new ExternalGraphicException("The attribute 'src' of "
- + "<fo:external-graphic> has a invalid value: '"
- + url + "' (" + e + ")");
- }
- }
-
- if (imagedata == null) {
- return;
- }
-
- // Determine image file format
- String file = (url != null ? url.getFile() : "<unknown>");
- imageformat = FormatBase.determineFormat(imagedata);
- if (imageformat != null) {
- imageformat = imageformat.convert(imageformat, imagedata);
- }
-
- if (imageformat == null
- || imageformat.getType() == ImageConstants.I_NOT_SUPPORTED
- || "".equals(imageformat.getRtfTag())) {
- throw new ExternalGraphicException("The tag <fo:external-graphic> "
- + "does not support "
- + file.substring(file.lastIndexOf(".") + 1)
- + " - image type.");
- }
-
- // Writes the beginning of the rtf image
-
- writeGroupMark(true);
- writeStarControlWord("shppict");
- writeGroupMark(true);
- writeControlWord("pict");
-
- StringBuffer buf = new StringBuffer(imagedata.length * 3);
-
- writeControlWord(imageformat.getRtfTag());
-
- computeImageSize();
- writeSizeInfo();
- writeAttributes(getRtfAttributes(), null);
-
- for (int i = 0; i < imagedata.length; i++) {
- int iData = imagedata [i];
-
- // Make positive byte
- if (iData < 0) {
- iData += 256;
- }
-
- if (iData < 16) {
- // Set leading zero and append
- buf.append('0');
- }
-
- buf.append(Integer.toHexString(iData));
- }
-
- int len = buf.length();
- char[] chars = new char[len];
-
- buf.getChars(0, len, chars, 0);
- writer.write(chars);
-
- // Writes the end of RTF image
-
- writeGroupMark(false);
- writeGroupMark(false);
- }
-
- private void computeImageSize () {
- if (imageformat.getType() == ImageConstants.I_PNG) {
- width = ImageUtil.getIntFromByteArray(imagedata, 16, 4, true);
- height = ImageUtil.getIntFromByteArray(imagedata, 20, 4, true);
- } else if (imageformat.getType() == ImageConstants.I_JPG) {
- int basis = -1;
- byte ff = (byte) 0xff;
- byte c0 = (byte) 0xc0;
- for (int i = 0; i < imagedata.length; i++) {
- byte b = imagedata[i];
- if (b != ff) {
- continue;
- }
- if (i == imagedata.length - 1) {
- continue;
- }
- b = imagedata[i + 1];
- if (b != c0) {
- continue;
- }
- basis = i + 5;
- break;
- }
-
- if (basis != -1) {
- width = ImageUtil.getIntFromByteArray(imagedata, basis + 2, 2, true);
- height = ImageUtil.getIntFromByteArray(imagedata, basis, 2, true);
- }
- } else if (imageformat.getType() == ImageConstants.I_EMF) {
- int i = 0;
-
- i = ImageUtil.getIntFromByteArray(imagedata, 151, 4, false);
- if (i != 0 ) {
- width = i;
- }
-
- i = ImageUtil.getIntFromByteArray(imagedata, 155, 4, false);
- if (i != 0 ) {
- height = i;
- }
-
- }
- }
-
- private void writeSizeInfo () throws IOException {
- // Set image size
- if (width != -1) {
- writeControlWord("picw" + width);
- }
- if (height != -1) {
- writeControlWord("pich" + height);
- }
-
- if (widthDesired != -1) {
- if (perCentW) {
- writeControlWord("picscalex" + widthDesired);
- } else {
- //writeControlWord("picscalex" + widthDesired * 100 / width);
- writeControlWord("picwgoal" + widthDesired);
- }
-
- } else if (scaleUniform && heightDesired != -1) {
- if (perCentH) {
- writeControlWord("picscalex" + heightDesired);
- } else {
- writeControlWord("picscalex" + heightDesired * 100 / height);
- }
- }
-
- if (heightDesired != -1) {
- if (perCentH) {
- writeControlWord("picscaley" + heightDesired);
- } else {
- //writeControlWord("picscaley" + heightDesired * 100 / height);
- writeControlWord("pichgoal" + heightDesired);
- }
-
- } else if (scaleUniform && widthDesired != -1) {
- if (perCentW) {
- writeControlWord("picscaley" + widthDesired);
- } else {
- writeControlWord("picscaley" + widthDesired * 100 / width);
- }
- }
-
- if (this.cropValues[0] != 0) {
- writeOneAttribute("piccropl", new Integer(this.cropValues[0]));
- }
- if (this.cropValues[1] != 0) {
- writeOneAttribute("piccropt", new Integer(this.cropValues[1]));
- }
- if (this.cropValues[2] != 0) {
- writeOneAttribute("piccropr", new Integer(this.cropValues[2]));
- }
- if (this.cropValues[3] != 0) {
- writeOneAttribute("piccropb", new Integer(this.cropValues[3]));
- }
- }
-
- //////////////////////////////////////////////////
- // @@ Member access
- //////////////////////////////////////////////////
-
- /**
- * Sets the desired height of the image.
- *
- * @param theHeight The desired image height (as a string in twips or as a percentage)
- */
- public void setHeight(String theHeight) {
- this.heightDesired = ImageUtil.getInt(theHeight);
- this.perCentH = ImageUtil.isPercent(theHeight);
- }
-
- /**
- * Sets the desired width of the image.
- *
- * @param theWidth The desired image width (as a string in twips or as a percentage)
- */
- public void setWidth(String theWidth) {
- this.widthDesired = ImageUtil.getInt(theWidth);
- this.perCentW = ImageUtil.isPercent(theWidth);
- }
-
- /**
- * Sets the desired width of the image.
- * @param twips The desired image width (in twips)
- */
- public void setWidthTwips(int twips) {
- this.widthDesired = twips;
- this.perCentW = false;
- }
-
- /**
- * Sets the desired height of the image.
- * @param twips The desired image height (in twips)
- */
- public void setHeightTwips(int twips) {
- this.heightDesired = twips;
- this.perCentH = false;
- }
-
- /**
- * Sets the flag whether the image size shall be adjusted.
- *
- * @param value
- * true image width or height shall be adjusted automatically\n
- * false no adjustment
- */
- public void setScaling(String value) {
- setUniformScaling("uniform".equalsIgnoreCase(value));
- }
-
- /**
- * Sets the flag whether the image size shall be adjusted.
- *
- * @param uniform
- * true image width or height shall be adjusted automatically\n
- * false no adjustment
- */
- public void setUniformScaling(boolean uniform) {
- this.scaleUniform = uniform;
- }
-
- /**
- * Sets cropping values for all four edges for the \piccrop*N commands.
- * A positive value crops toward the center of the picture;
- * a negative value crops away from the center, adding a space border around the picture
- * @param left left cropping value (in twips)
- * @param top top cropping value (in twips)
- * @param right right cropping value (in twips)
- * @param bottom bottom cropping value (in twips)
- */
- public void setCropping(int left, int top, int right, int bottom) {
- this.cropValues[0] = left;
- this.cropValues[1] = top;
- this.cropValues[2] = right;
- this.cropValues[3] = bottom;
- }
-
- /**
- * Sets the binary imagedata of the image.
- *
- * @param data binary imagedata as read from file.
- * @throws IOException On error
- */
- public void setImageData(byte[] data) throws IOException {
- this.imagedata = data;
- }
-
- /**
- * Sets the url of the image.
- *
- * @param urlString Image url like "file://..."
- * @throws IOException On error
- */
- public void setURL(String urlString) throws IOException {
- URL tmpUrl = null;
- try {
- tmpUrl = new URL (urlString);
- } catch (MalformedURLException e) {
- try {
- tmpUrl = new File (urlString).toURL ();
- } catch (MalformedURLException ee) {
- throw new ExternalGraphicException("The attribute 'src' of "
- + "<fo:external-graphic> has a invalid value: '"
- + urlString + "' (" + ee + ")");
- }
- }
- this.url = tmpUrl;
- }
-
- /**
- * Gets the compression rate for the image in percent.
- * @return Compression rate
- */
- public int getCompressionRate () {
- return graphicCompressionRate;
- }
-
- /**
- * Sets the compression rate for the image in percent.
- *
- * @param percent Compression rate
- * @return true if the compression rate is valid (0..100), false if invalid
- */
- public boolean setCompressionRate (int percent) {
- if (percent < 1 || percent > 100) {
- return false;
- }
-
- graphicCompressionRate = percent;
- return true;
- }
-
-
- //////////////////////////////////////////////////
- // @@ Helpers
- //////////////////////////////////////////////////
-
- /**
- * @return true if this element would generate no "useful" RTF content
- */
- public boolean isEmpty() {
- return url == null;
- }
- }
|