W2X relative image size

git-svn-id: svn://svn.code.sf.net/p/writer2latex/code/trunk@100 f0f2a975-2e09-46c8-9428-3b39399b9f3c
This commit is contained in:
henrikjust 2011-03-21 10:40:02 +00:00
parent 4ecd5ede1e
commit 4a63a1ce8c
18 changed files with 306 additions and 138 deletions

View file

@ -20,7 +20,7 @@
*
* All Rights Reserved.
*
* Version 1.2 (2011-03-10)
* Version 1.2 (2011-03-21)
*
*/
@ -33,7 +33,7 @@ public class ConverterFactory {
// Version information
private static final String VERSION = "1.1.7";
private static final String DATE = "2011-03-10";
private static final String DATE = "2011-03-21";
/** Return the Writer2LaTeX version in the form
* (major version).(minor version).(patch level)<br/>

View file

@ -16,11 +16,11 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Copyright: 2002-2010 by Henrik Just
* Copyright: 2002-2011 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.2 (2010-12-19)
* Version 1.2 (2011-03-16)
*
*/
@ -206,6 +206,12 @@ public class Misc{
// Divide dividend by divisor and return the quotient as an integer percentage
// (never below 1% except if the dividend is zero)
public static final String divide(String sDividend, String sDivisor) {
return divide(sDividend,sDivisor,false);
}
// Divide dividend by divisor and return the quotient as an integer percentage
// (never below 1% except if the dividend is zero, and never above 100% if last parameter is true)
public static final String divide(String sDividend, String sDivisor, boolean bMax100) {
if (sDividend.equals("0")) { return "0%"; }
if (sDivisor.equals("0")) { return "100%"; }
@ -214,7 +220,10 @@ public class Misc{
float fDivisor=getFloat(sDivisor.substring(0,sDivisor.length()-2),1);
String sDivisorUnit=sDivisor.substring(sDivisor.length()-2);
int nPercent = Math.round(100*fDividend*getUpi(sDivisorUnit)/fDivisor/getUpi(sDividendUnit));
if (nPercent>0) {
if (bMax100 && nPercent>100) {
return "100%";
}
else if (nPercent>0) {
return Integer.toString(nPercent)+"%";
}
else {

View file

@ -20,7 +20,7 @@
*
* All Rights Reserved.
*
* Version 1.2 (2011-03-09)
* Version 1.2 (2011-03-21)
*
*/
@ -32,6 +32,7 @@ import java.util.HashSet;
import java.util.ListIterator;
import java.util.LinkedList;
import java.util.Set;
import java.util.Stack;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Iterator;
@ -108,6 +109,10 @@ public class Converter extends ConverterBase {
// Strip illegal characters from internal hyperlink targets
private ExportNameCollection targetNames = new ExportNameCollection(true);
// The current context (currently we only track the content width, but this might be expanded with formatting
// attributes - at least background color and font size later)
private Stack<String> contentWidth = new Stack<String>();
// Constructor setting the DOCTYPE
public Converter(int nType) {
super();
@ -145,6 +150,22 @@ public class Converter extends ConverterBase {
@Override public void readResource(File file, String sFileName, String sMediaType) throws IOException {
readResource(new FileInputStream(file), sFileName, sMediaType);
}
protected String getContentWidth() {
return contentWidth.peek();
}
protected String pushContentWidth(String sWidth) {
return contentWidth.push(sWidth);
}
protected void popContentWidth() {
contentWidth.pop();
}
protected boolean isTopLevel() {
return contentWidth.size()==1;
}
protected StyleConverter getStyleCv() { return styleCv; }
@ -230,6 +251,9 @@ public class Converter extends ConverterBase {
if (style!=null) {
l10n.setLocale(style.getProperty(XMLString.FO_LANGUAGE), style.getProperty(XMLString.FO_COUNTRY));
}
// Set the main content width
pushContentWidth(getStyleCv().getPageSc().getTextWidth());
// Traverse the body
Element body = ofr.getContent();

View file

@ -16,11 +16,11 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Copyright: 2002-2010 by Henrik Just
* Copyright: 2002-2011 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.2 (2010-05-13)
* Version 1.2 (2011-03-21)
*
*/
@ -91,11 +91,11 @@ public class DrawConverter extends ConverterHelper {
private FormReader form = null;
private String sScale;
private boolean bConvertToPx;
private boolean bOriginalImageSize;
private int nImageSize;
// Frames in spreadsheet documents are collected here
private Vector<Element> frames = new Vector<Element>();
// This flag determines wether to collect frames or insert them immediately
// This flag determines whether to collect frames or insert them immediately
private boolean bCollectFrames = false;
public DrawConverter(OfficeReader ofr, XhtmlConfig config, Converter converter) {
@ -109,7 +109,7 @@ public class DrawConverter extends ConverterHelper {
bCollectFrames = ofr.isSpreadsheet();
sScale = config.getXhtmlScaling();
bConvertToPx = config.xhtmlConvertToPx();
bOriginalImageSize = config.originalImageSize();
nImageSize = config.imageSize();
}
///////////////////////////////////////////////////////////////////////
@ -414,7 +414,7 @@ public class DrawConverter extends ConverterHelper {
StyleInfo info = new StyleInfo();
String sStyleName = Misc.getAttribute(frame, XMLString.DRAW_STYLE_NAME);
getFrameSc().applyStyle(sStyleName,info);
if (!bOriginalImageSize) { applySize(frame,info.props,false); }
applyImageSize(frame,info.props,false);
// Apply placement
applyPlacement(frame, hnodeBlock, hnodeInline, nMode, image, info);
@ -435,7 +435,7 @@ public class DrawConverter extends ConverterHelper {
// Add name, if defined
String sName = Misc.getAttribute(getFrame(onode),XMLString.DRAW_NAME);
if (sName!=null) { converter.addTarget(textbox,sName+"|frame"); }
// Now style it
Element frame = getFrame(onode);
StyleInfo info = new StyleInfo();
@ -459,47 +459,55 @@ public class DrawConverter extends ConverterHelper {
}
// Apply placement
String sContentWidth = null;
switch (nMode) {
case INLINE:
break;
case ABSOLUTE:
applySize(frame,info.props,false);
applyPosition(frame,info.props);
break;
case CENTERED:
info.props.addValue("maring-top","2px");
info.props.addValue("maring-bottom","2px");
info.props.addValue("margin-left","auto");
info.props.addValue("margin-right","auto");
applySize(frame,info.props,true);
break;
case FLOATING:
applySize(frame,info.props,true);
StyleWithProperties style = ofr.getFrameStyle(sStyleName);
if (style!=null) {
String sPos = style.getProperty(XMLString.STYLE_HORIZONTAL_POS);
String sWrap = style.getProperty(XMLString.STYLE_WRAP);
if (isLeft(sPos) && mayWrapRight(sWrap)) {
info.props.addValue("float","left");
}
else if (isRight(sPos) && mayWrapLeft(sWrap)) {
info.props.addValue("float","right");
}
else if (isFromLeft(sPos)) {
if (mayWrapRight(sWrap)) {
info.props.addValue("float","left");
}
String sX = frame.getAttribute(XMLString.SVG_X);
if (sX!=null && sX.length()>0) {
info.props.addValue("margin-left",scale(sX));
}
}
}
case INLINE:
break;
case ABSOLUTE:
sContentWidth = applyImageSize(frame,info.props,false);
applyPosition(frame,info.props);
break;
case CENTERED:
info.props.addValue("maring-top","2px");
info.props.addValue("maring-bottom","2px");
info.props.addValue("margin-left","auto");
info.props.addValue("margin-right","auto");
sContentWidth = applyImageSize(frame,info.props,true);
break;
case FLOATING:
sContentWidth = applyImageSize(frame,info.props,true);
StyleWithProperties style = ofr.getFrameStyle(sStyleName);
if (style!=null) {
String sPos = style.getProperty(XMLString.STYLE_HORIZONTAL_POS);
String sWrap = style.getProperty(XMLString.STYLE_WRAP);
if (isLeft(sPos) && mayWrapRight(sWrap)) {
info.props.addValue("float","left");
}
else if (isRight(sPos) && mayWrapLeft(sWrap)) {
info.props.addValue("float","right");
}
else if (isFromLeft(sPos)) {
if (mayWrapRight(sWrap)) {
info.props.addValue("float","left");
}
String sX = frame.getAttribute(XMLString.SVG_X);
if (sX!=null && sX.length()>0) {
info.props.addValue("margin-left",scale(sX));
}
}
}
}
//Finish
applyStyle(info,textbox);
if (sContentWidth!=null) {
converter.pushContentWidth(sContentWidth);
}
getTextCv().traverseBlockText(onode,textbox);
if (sContentWidth!=null) {
converter.popContentWidth();
}
getPresentationSc().exitOutline();
}
@ -770,36 +778,38 @@ public class DrawConverter extends ConverterHelper {
}
}
}
private void applySize(Element node, CSVList props, boolean bOnlyWidth) {
// The width attribute in css refers to the content width, excluding borders and padding
// We thus have to subtract the borders and padding to get the correct width
StyleWithProperties style = ofr.getFrameStyle(node.getAttribute(XMLString.DRAW_STYLE_NAME));
String sWidth = node.getAttribute(XMLString.SVG_WIDTH);
if (sWidth.length()>0) {
if (style!=null) {
// Subtract padding
String s = style.getProperty(XMLString.FO_PADDING_LEFT);
if (s!=null) sWidth = Misc.sub(sWidth, s);
s = style.getProperty(XMLString.FO_PADDING_RIGHT);
if (s!=null) sWidth = Misc.sub(sWidth, s);
s = style.getProperty(XMLString.FO_PADDING);
if (s!=null) sWidth = Misc.sub(sWidth, Misc.multiply("200%", s));
// Subtract border
s = style.getProperty(XMLString.FO_BORDER_LEFT);
if (s!=null) sWidth = Misc.sub(sWidth, getTableCv().borderWidth(s));
s = style.getProperty(XMLString.FO_BORDER_RIGHT);
if (s!=null) sWidth = Misc.sub(sWidth, getTableCv().borderWidth(s));
s = style.getProperty(XMLString.FO_BORDER);
if (s!=null) sWidth = Misc.sub(sWidth, Misc.multiply("200%", getTableCv().borderWidth(s)));
}
props.addValue("width",scale(sWidth));
}
String sHeight = node.getAttribute(XMLString.SVG_HEIGHT);
if (sHeight.length()>0 && !bOnlyWidth) {
// The width attribute in CSS refers to the content width, excluding borders and padding
// We thus have to subtract the borders and padding to get the correct width
// This method handles this
private String getFrameWidth(Element node, StyleWithProperties style) {
String sWidth = node.getAttribute(XMLString.SVG_WIDTH);
if (sWidth.length()>0) {
if (style!=null) {
// Subtract padding
String s = style.getProperty(XMLString.FO_PADDING_LEFT);
if (s!=null) sWidth = Misc.sub(sWidth, s);
s = style.getProperty(XMLString.FO_PADDING_RIGHT);
if (s!=null) sWidth = Misc.sub(sWidth, s);
s = style.getProperty(XMLString.FO_PADDING);
if (s!=null) sWidth = Misc.sub(sWidth, Misc.multiply("200%", s));
// Subtract border
s = style.getProperty(XMLString.FO_BORDER_LEFT);
if (s!=null) sWidth = Misc.sub(sWidth, getTableCv().borderWidth(s));
s = style.getProperty(XMLString.FO_BORDER_RIGHT);
if (s!=null) sWidth = Misc.sub(sWidth, getTableCv().borderWidth(s));
s = style.getProperty(XMLString.FO_BORDER);
if (s!=null) sWidth = Misc.sub(sWidth, Misc.multiply("200%", getTableCv().borderWidth(s)));
}
return sWidth;
}
return null;
}
// Same for height
private String getFrameHeight(Element node, StyleWithProperties style) {
String sHeight = node.getAttribute(XMLString.SVG_HEIGHT);
if (sHeight.length()>0) {
if (style!=null) {
// Subtract padding
String s = style.getProperty(XMLString.FO_PADDING_TOP);
@ -816,9 +826,47 @@ public class DrawConverter extends ConverterHelper {
s = style.getProperty(XMLString.FO_BORDER);
if (s!=null) sHeight = Misc.sub(sHeight, Misc.multiply("200%", getTableCv().borderWidth(s)));
}
props.addValue("height",scale(sHeight));
}
return sHeight;
}
return null;
}
// Return the (unscaled) content width, or null if it's unknown
private String applySize(Element node, CSVList props, boolean bOnlyWidth) {
StyleWithProperties style = ofr.getFrameStyle(node.getAttribute(XMLString.DRAW_STYLE_NAME));
String sWidth = getFrameWidth(node, style);
if (sWidth!=null) {
props.addValue("width",scale(sWidth));
}
if (!bOnlyWidth) {
String sHeight = getFrameHeight(node,style);
if (sHeight!=null) {
props.addValue("height",scale(sHeight));
}
}
return sWidth;
}
// TODO: For absolute placement, only absolute size makes sense
// TODO: How to handle NONE in case of text boxes? (currently using browser default, usually 100% width)
private String applyImageSize(Element node, CSVList props, boolean bOnlyWidth) {
switch (nImageSize) {
case XhtmlConfig.ABSOLUTE:
return applySize(node, props, bOnlyWidth);
case XhtmlConfig.RELATIVE:
String sWidth = getFrameWidth(node, ofr.getFrameStyle(node.getAttribute(XMLString.DRAW_STYLE_NAME)));
if (sWidth!=null) {
props.addValue("width", Misc.divide(Misc.multiply(sScale,Misc.truncateLength(sWidth)),converter.getContentWidth()));
}
return sWidth;
case XhtmlConfig.NONE:
// Nothing to do :-)
return getFrameWidth(node, ofr.getFrameStyle(node.getAttribute(XMLString.DRAW_STYLE_NAME)));
}
return null;
}
private void applyPosition(Element node, CSVList props) {
@ -949,7 +997,6 @@ public class DrawConverter extends ConverterHelper {
return Misc.multiply(sScale,Misc.truncateLength(s));
}
}
}

View file

@ -16,11 +16,11 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Copyright: 2002-2010 by Henrik Just
* Copyright: 2002-2011 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.2 (2010-03-08)
* Version 1.2 (2011-03-16)
*
*/
@ -35,6 +35,7 @@ import writer2latex.office.PageLayout;
import writer2latex.office.StyleWithProperties;
import writer2latex.office.XMLString;
import writer2latex.util.CSVList;
import writer2latex.util.Misc;
/**
* This class converts OpenDocument page styles to CSS2 styles.
@ -60,6 +61,32 @@ public class PageStyleConverter extends StyleConverterHelper {
this.bConvertStyles = config.xhtmlFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlFormatting()==XhtmlConfig.IGNORE_HARD;
}
/** Get the text width of the first master page (page width minus left and right margin)
*
* @return the text width
*/
public String getTextWidth() {
MasterPage masterPage = ofr.getFirstMasterPage();
if (masterPage!=null) {
PageLayout pageLayout = ofr.getPageLayout(masterPage.getPageLayoutName());
if (pageLayout!=null) {
String sWidth = pageLayout.getProperty(XMLString.FO_PAGE_WIDTH);
if (sWidth!=null) {
String sMarginLeft = pageLayout.getProperty(XMLString.FO_MARGIN_LEFT);
if (sMarginLeft!=null) {
sWidth = Misc.sub(sWidth, sMarginLeft);
}
String sMarginRight = pageLayout.getProperty(XMLString.FO_MARGIN_RIGHT);
if (sMarginRight!=null) {
sWidth = Misc.sub(sWidth, sMarginRight);
}
return sWidth;
}
}
}
return "17cm"; // Default in Writer, hence usable as a fallback value
}
/** Apply footnote rule formatting (based on first master page)
*
* @param info then StyleInfo to which style information should be attached

View file

@ -20,7 +20,7 @@
*
* All Rights Reserved.
*
* Version 1.2 (2011-03-09)
* Version 1.2 (2011-03-21)
*
*/
@ -266,7 +266,14 @@ public class TableConverter extends ConverterHelper {
// Handle content
if (!isEmptyCell(cell)) {
getTextCv().traverseBlockText(cell,td);
String sWidth = view.getCellWidth(nRow, nCol);
if (sWidth!=null) {
converter.pushContentWidth(sWidth);
}
getTextCv().traverseBlockText(cell,td);
if (sWidth!=null) {
converter.popContentWidth();
}
}
else {
// Hack to display empty cells even in msie...

View file

@ -20,7 +20,7 @@
*
* All Rights Reserved.
*
* Version 1.2 (2011-03-08)
* Version 1.2 (2011-03-16)
*
*/
@ -50,6 +50,12 @@ public class XhtmlConfig extends writer2latex.base.ConfigBase {
if (sName.startsWith("xhtml_")) { sName = sName.substring(6); }
// this option has been renamed:
if (sName.equals("keep_image_size")) { sName = "original_image_size"; }
// and later renamed and extended:
if (sName.equals("original_image_size")) {
sName = "image_size";
if (sValue.equals("true")) { sValue = "none"; }
else { sValue="absolute"; }
}
// this option has been renamed and extended:
if (sName.equals("use_list_hack")) {
sName = "list_formatting";
@ -69,6 +75,11 @@ public class XhtmlConfig extends writer2latex.base.ConfigBase {
public static final int CSS1 = 0;
public static final int CSS1_HACK = 1;
public static final int HARD_LABELS = 2;
// Image dimensions
public static final int NONE = 0;
public static final int ABSOLUTE = 1;
public static final int RELATIVE = 2;
// Formulas (for XHTML 1.0 strict)
public static final int STARMATH = 0;
@ -77,7 +88,7 @@ public class XhtmlConfig extends writer2latex.base.ConfigBase {
public static final int IMAGE_LATEX = 3;
// Page breaks
public static final int NONE = 0;
// public static final int NONE = 0;
public static final int STYLES = 1;
public static final int EXPLICIT = 2;
public static final int ALL = 3;
@ -86,7 +97,7 @@ public class XhtmlConfig extends writer2latex.base.ConfigBase {
private static final int IGNORE_HARD_LINE_BREAKS = 0;
private static final int IGNORE_EMPTY_PARAGRAPHS = 1;
private static final int IGNORE_DOUBLE_SPACES = 2;
private static final int ORIGINAL_IMAGE_SIZE = 3;
private static final int IMAGE_SIZE = 3;
private static final int NO_DOCTYPE = 4;
private static final int ADD_BOM = 5;
private static final int ENCODING = 6;
@ -151,7 +162,15 @@ public class XhtmlConfig extends writer2latex.base.ConfigBase {
options[IGNORE_HARD_LINE_BREAKS] = new BooleanOption("ignore_hard_line_breaks","false");
options[IGNORE_EMPTY_PARAGRAPHS] = new BooleanOption("ignore_empty_paragraphs","false");
options[IGNORE_DOUBLE_SPACES] = new BooleanOption("ignore_double_spaces","false");
options[ORIGINAL_IMAGE_SIZE] = new BooleanOption("original_image_size","false");
options[IMAGE_SIZE] = new IntegerOption("image_size","auto") {
@Override public void setString(String sValue) {
super.setString(sValue);
if ("relative".equals(sValue)) { nValue = RELATIVE; }
else if ("none".equals(sValue)) { nValue = NONE; }
else if ("original_image_size".equals(sValue)) { nValue = NONE; }
else { nValue = ABSOLUTE; }
}
};
options[NO_DOCTYPE] = new BooleanOption("no_doctype","false");
options[ADD_BOM] = new BooleanOption("add_bom","false");
options[ENCODING] = new Option("encoding","UTF-8");
@ -323,7 +342,7 @@ public class XhtmlConfig extends writer2latex.base.ConfigBase {
public boolean ignoreHardLineBreaks() { return ((BooleanOption) options[IGNORE_HARD_LINE_BREAKS]).getValue(); }
public boolean ignoreEmptyParagraphs() { return ((BooleanOption) options[IGNORE_EMPTY_PARAGRAPHS]).getValue(); }
public boolean ignoreDoubleSpaces() { return ((BooleanOption) options[IGNORE_DOUBLE_SPACES]).getValue(); }
public boolean originalImageSize() { return ((BooleanOption) options[ORIGINAL_IMAGE_SIZE]).getValue(); }
public int imageSize() { return ((IntegerOption) options[IMAGE_SIZE]).getValue(); }
public boolean xhtmlNoDoctype() { return ((BooleanOption) options[NO_DOCTYPE]).getValue(); }
public boolean xhtmlAddBOM() { return ((BooleanOption) options[ADD_BOM]).getValue(); }
public String xhtmlEncoding() { return options[ENCODING].getString(); }