Crop and convert to JPG embeeded images

This commit is contained in:
Georgy Litvinov 2020-12-07 19:21:00 +01:00
parent 56a815bc9b
commit 93f1aa83d3
4 changed files with 123 additions and 6 deletions

View file

@ -25,12 +25,25 @@
package w2phtml.base; package w2phtml.base;
import static w2phtml.office.XMLString.FO_CLIP;
import java.awt.image.BufferedImage;
import java.awt.image.RasterFormatException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import javax.imageio.ImageIO;
import org.apache.commons.imaging.ImageInfo;
import org.apache.commons.imaging.ImageReadException;
import org.apache.commons.imaging.Imaging;
import w2phtml.api.OutputFile; import w2phtml.api.OutputFile;
import w2phtml.office.MIMETypes;
import java.io.IOException; import w2phtml.office.StyleWithProperties;
import w2phtml.util.DimensionsConverter;
/** This class is used to represent a binary graphics document to be included in the converter result. /** This class is used to represent a binary graphics document to be included in the converter result.
* I may also represent a linked image, which should <em>not</em> be included (and will produce an empty file * I may also represent a linked image, which should <em>not</em> be included (and will produce an empty file
@ -49,6 +62,9 @@ public class BinaryGraphicsDocument implements OutputFile {
private byte[] blob = null; private byte[] blob = null;
private int nOff = 0; private int nOff = 0;
private int nLen = 0; private int nLen = 0;
private boolean cropped = false;
private float horizontalPPI = 96.0F;
private float verticalPPI = 96.0F;
/**Constructs a new graphics document. /**Constructs a new graphics document.
* Until data is added using the <code>read</code> methods, the document is considered a link to * Until data is added using the <code>read</code> methods, the document is considered a link to
@ -75,9 +91,27 @@ public class BinaryGraphicsDocument implements OutputFile {
this.blob = bgd.getData(); this.blob = bgd.getData();
this.bAcceptedFormat = bgd.isAcceptedFormat(); this.bAcceptedFormat = bgd.isAcceptedFormat();
this.bRecycled = true; this.bRecycled = true;
} }
/** Is this graphics document recycled? private void extractPPI() {
try {
ImageInfo info = Imaging.getImageInfo(blob);
int heightDPI = info.getPhysicalHeightDpi();
if (heightDPI > 0) {
this.verticalPPI = heightDPI;
}
int widthDPI = info.getPhysicalWidthDpi();
if (widthDPI > 0) {
this.horizontalPPI = widthDPI;
}
} catch (ImageReadException | IOException e) {
e.printStackTrace();
}
}
/** Is this graphics document recycled?
* *
* @return true if this is the case * @return true if this is the case
*/ */
@ -170,8 +204,76 @@ public class BinaryGraphicsDocument implements OutputFile {
public boolean isMasterDocument() { public boolean isMasterDocument() {
return false; return false;
} }
/** Does this document contain formulas? public boolean isCropped() {
return cropped;
}
/* Crop image from byte array */
public void cropImage(StyleWithProperties style) {
if (blob == null || style == null) {
return;
}
if (sMimeType == null || (
!sMimeType.equals(MIMETypes.PNG)
&& !sMimeType.equals(MIMETypes.JPEG)
&& !sMimeType.equals(MIMETypes.GIF)
&& !sMimeType.equals(MIMETypes.TIFF)
)){
return;
}
extractPPI();
int[] offsets = getOffsets(style);
ByteArrayInputStream bis = new ByteArrayInputStream(blob);
try {
BufferedImage image = ImageIO.read(bis);
int height = image.getHeight();
int width = image.getWidth();
String formatName = MIMETypes.getFormatType(blob);
int xTopLeft = offsets[3];
int yTopLeft = offsets[0];
int xBottomRight = width - offsets[3] - offsets[1];
int yBottomRight = height - offsets[0] - offsets[2];
BufferedImage croppedImage = image.getSubimage(xTopLeft, yTopLeft, xBottomRight , yBottomRight );
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(croppedImage, "JPG", baos);
sMimeType = MIMETypes.JPEG;
blob = baos.toByteArray();
cropped = true;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (RasterFormatException e ) {
e.printStackTrace();
}
}
private int[] getOffsets(StyleWithProperties style) {
/* top, right, bottom, left */
int[] offsets = { 0, 0, 0, 0 };
String fo_clip = style.getProperty(FO_CLIP);
if (!fo_clip.startsWith("rect(") || !fo_clip.endsWith(")")) {
return offsets;
}
fo_clip = fo_clip.replaceAll("^rect\\(", "");
fo_clip = fo_clip.replaceAll("\\)", "");
String[] inputOffsets = fo_clip.split("\\s*,\\s*");
for (int i = 0; i < inputOffsets.length; i++) {
String inputOffset = inputOffsets[i];
float ppi;
if (i % 2 == 0) {
ppi = verticalPPI;
} else {
ppi = horizontalPPI;
}
offsets[i] = Math.round(DimensionsConverter.length2px(inputOffset, ppi));
}
return offsets;
}
/** Does this document contain formulas?
* *
* @return false - a graphics file does not contain formulas * @return false - a graphics file does not contain formulas
*/ */

View file

@ -124,6 +124,18 @@ public final class MIMETypes extends w2phtml.api.MIMETypes {
if (isSVG(blob)) { return SVG; } if (isSVG(blob)) { return SVG; }
return ""; return "";
} }
public static final String getFormatType(byte[] blob) {
if (isType(blob,PNG_SIG)) { return "PNG"; }
if (isType(blob,JPEG_SIG)) { return "JPG"; }
if (isType(blob,JPEG_EXIF_SIG)) { return "JPG"; }
if (isType(blob,GIF87_SIG)) { return "GIF"; }
if (isType(blob,GIF89_SIG)) { return "GIF"; }
if (isType(blob,TIFF_SIG)) { return "TIFF"; }
if (isType(blob,BMP_SIG)) { return "BMP"; }
if (isSVG(blob)) { return "SVG"; }
return "";
}
public static final String getFileExtension(String sMIME) { public static final String getFileExtension(String sMIME) {
if (PNG.equals(sMIME)) { return PNG_EXT; } if (PNG.equals(sMIME)) { return PNG_EXT; }

View file

@ -434,6 +434,7 @@ public class XMLString {
// fo namespace // fo namespace
public static final String FO_LANGUAGE = "fo:language"; public static final String FO_LANGUAGE = "fo:language";
public static final String FO_COUNTRY = "fo:country"; public static final String FO_COUNTRY = "fo:country";
public static final String FO_CLIP = "fo:clip";
public static final String FO_TEXT_SHADOW = "fo:text-shadow"; public static final String FO_TEXT_SHADOW = "fo:text-shadow";
public static final String FO_COLOR = "fo:color"; public static final String FO_COLOR = "fo:color";
public static final String FO_BACKGROUND_COLOR = "fo:background-color"; public static final String FO_BACKGROUND_COLOR = "fo:background-color";

View file

@ -539,6 +539,8 @@ public class DrawParser extends Parser {
String sFileName = null; String sFileName = null;
bgd = converter.getImageCv().getImage(onode); bgd = converter.getImageCv().getImage(onode);
if (bgd!=null) { if (bgd!=null) {
StyleWithProperties style = ofr.getFrameStyle(frame.getAttribute(XMLString.DRAW_STYLE_NAME));
bgd.cropImage(style);
if (!bgd.isLinked()) { // embedded image if (!bgd.isLinked()) { // embedded image
sFileName = bgd.getFileName(); sFileName = bgd.getFileName();
// If this is the cover image, add it to the converter result // If this is the cover image, add it to the converter result