From c4e5885007f3c61837a12ab330658b131d978247 Mon Sep 17 00:00:00 2001 From: Luis Bernardo Date: Sun, 11 May 2014 22:06:49 +0000 Subject: [PATCH] FOP-2372: New extension to resize background images git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1593863 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/area/Trait.java | 26 +++ src/java/org/apache/fop/fo/Constants.java | 6 +- .../org/apache/fop/fo/FOPropertyMapping.java | 10 ++ .../extensions/ExtensionElementMapping.java | 3 + .../CommonBorderPaddingBackground.java | 31 ++-- .../org/apache/fop/layoutmgr/TraitSetter.java | 6 + .../render/AbstractPathOrientedRenderer.java | 27 +-- .../org/apache/fop/area/TraitTestCase.java | 42 +++++ .../AbstractPathOrientedRendererTestCase.java | 162 ++++++++++++++++++ 9 files changed, 290 insertions(+), 23 deletions(-) create mode 100644 test/java/org/apache/fop/area/TraitTestCase.java create mode 100644 test/java/org/apache/fop/render/AbstractPathOrientedRendererTestCase.java diff --git a/src/java/org/apache/fop/area/Trait.java b/src/java/org/apache/fop/area/Trait.java index eac9d440d..bd8182099 100644 --- a/src/java/org/apache/fop/area/Trait.java +++ b/src/java/org/apache/fop/area/Trait.java @@ -508,6 +508,10 @@ public final class Trait implements Serializable { /** Background vertical offset for images. */ private int vertical; + private int imageTargetWidth; + + private int imageTargetHeight; + /** * Returns the background color. * @return background color, null if n/a @@ -655,9 +659,31 @@ public final class Trait implements Serializable { sb.append(",horiz=").append(horiz); sb.append(",vertical=").append(vertical); } + if (imageTargetWidth != 0) { + sb.append(",target-width=").append(Integer.toString(imageTargetWidth)); + } + if (imageTargetHeight != 0) { + sb.append(",target-height=").append(Integer.toString(imageTargetHeight)); + } return sb.toString(); } + public void setImageTargetWidth(int value) { + imageTargetWidth = value; + } + + public int getImageTargetWidth() { + return imageTargetWidth; + } + + public void setImageTargetHeight(int value) { + imageTargetHeight = value; + } + + public int getImageTargetHeight() { + return imageTargetHeight; + } + } } diff --git a/src/java/org/apache/fop/fo/Constants.java b/src/java/org/apache/fop/fo/Constants.java index 2d53d1d46..9ad483643 100644 --- a/src/java/org/apache/fop/fo/Constants.java +++ b/src/java/org/apache/fop/fo/Constants.java @@ -822,8 +822,12 @@ public interface Constants { /** Property constant */ int PR_X_AUTO_TOGGLE = 292; + /** Used for scaling of background images */ + int PR_X_BACKGROUND_IMAGE_WIDTH = 293; + int PR_X_BACKGROUND_IMAGE_HEIGHT = 294; + /** Number of property constants defined */ - int PROPERTY_COUNT = 292; + int PROPERTY_COUNT = 294; // compound property constants diff --git a/src/java/org/apache/fop/fo/FOPropertyMapping.java b/src/java/org/apache/fop/fo/FOPropertyMapping.java index 16f7ab457..2c97594ce 100644 --- a/src/java/org/apache/fop/fo/FOPropertyMapping.java +++ b/src/java/org/apache/fop/fo/FOPropertyMapping.java @@ -2624,6 +2624,16 @@ public final class FOPropertyMapping implements Constants { m.setDefault("select-first-fitting"); addPropertyMaker("fox:auto-toggle", m); + // fox:background-image-width|height, used for scaling of background images + m = new LengthProperty.Maker(PR_X_BACKGROUND_IMAGE_WIDTH); + m.setInherited(false); + m.setDefault("0pt"); + addPropertyMaker("fox:background-image-width", m); + m = new LengthProperty.Maker(PR_X_BACKGROUND_IMAGE_HEIGHT); + m.setInherited(false); + m.setDefault("0pt"); + addPropertyMaker("fox:background-image-height", m); + // fox:border-*-radius-* m = new CondLengthProperty.Maker(PR_X_BORDER_BEFORE_RADIUS_START); m.useGeneric(genericCondCornerRadius); diff --git a/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java b/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java index eb02540bc..481016df1 100644 --- a/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java +++ b/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java @@ -69,6 +69,9 @@ public class ExtensionElementMapping extends ElementMapping { PROPERTY_ATTRIBUTES.add("border-after-end-radius"); //Optional content groups (layers) PROPERTY_ATTRIBUTES.add("layer"); + // used for scaling of background images + PROPERTY_ATTRIBUTES.add("background-image-width"); + PROPERTY_ATTRIBUTES.add("background-image-height"); } /** diff --git a/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java b/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java index 78c8d9045..755d84547 100644 --- a/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java +++ b/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java @@ -84,6 +84,8 @@ public class CommonBorderPaddingBackground { */ public final Length backgroundPositionVertical; + public final Length backgroungImageTargetWidth; + public final Length backgroungImageTargetHeight; private ImageInfo backgroundImageInfo; @@ -353,6 +355,9 @@ public class CommonBorderPaddingBackground { Constants.PR_BACKGROUND_POSITION_VERTICAL).getLength(); } + backgroungImageTargetWidth = pList.get(Constants.PR_X_BACKGROUND_IMAGE_WIDTH).getLength(); + backgroungImageTargetHeight = pList.get(Constants.PR_X_BACKGROUND_IMAGE_HEIGHT).getLength(); + initBorderInfo(pList, BEFORE, Constants.PR_BORDER_BEFORE_COLOR, Constants.PR_BORDER_BEFORE_STYLE, @@ -397,18 +402,18 @@ public class CommonBorderPaddingBackground { CommonBorderPaddingBackground cachedInstance = null; /* if padding-* and background-position-* resolve to absolute lengths * the whole instance can be cached */ - if ((newInstance.padding[BEFORE] == null - || newInstance.padding[BEFORE].getLength().isAbsolute()) - && (newInstance.padding[AFTER] == null - || newInstance.padding[AFTER].getLength().isAbsolute()) - && (newInstance.padding[START] == null - || newInstance.padding[START].getLength().isAbsolute()) - && (newInstance.padding[END] == null - || newInstance.padding[END].getLength().isAbsolute()) - && (newInstance.backgroundPositionHorizontal == null - || newInstance.backgroundPositionHorizontal.isAbsolute()) - && (newInstance.backgroundPositionVertical == null - || newInstance.backgroundPositionVertical.isAbsolute())) { + if ((newInstance.padding[BEFORE] == null || newInstance.padding[BEFORE].getLength().isAbsolute()) + && (newInstance.padding[AFTER] == null || newInstance.padding[AFTER].getLength().isAbsolute()) + && (newInstance.padding[START] == null || newInstance.padding[START].getLength().isAbsolute()) + && (newInstance.padding[END] == null || newInstance.padding[END].getLength().isAbsolute()) + && (newInstance.backgroundPositionHorizontal == null || newInstance.backgroundPositionHorizontal + .isAbsolute()) + && (newInstance.backgroundPositionVertical == null || newInstance.backgroundPositionVertical + .isAbsolute()) + && (newInstance.backgroungImageTargetHeight == null || newInstance.backgroungImageTargetHeight + .isAbsolute()) + && (newInstance.backgroungImageTargetWidth == null || newInstance.backgroungImageTargetWidth + .isAbsolute())) { cachedInstance = CACHE.fetch(newInstance); } synchronized (newInstance.backgroundImage.intern()) { @@ -837,6 +842,8 @@ public class CommonBorderPaddingBackground { backgroundImage, backgroundPositionHorizontal, backgroundPositionVertical, + backgroungImageTargetWidth, + backgroungImageTargetHeight, borderInfo[BEFORE], borderInfo[AFTER], borderInfo[START], diff --git a/src/java/org/apache/fop/layoutmgr/TraitSetter.java b/src/java/org/apache/fop/layoutmgr/TraitSetter.java index af40f0681..0ff0badc8 100644 --- a/src/java/org/apache/fop/layoutmgr/TraitSetter.java +++ b/src/java/org/apache/fop/layoutmgr/TraitSetter.java @@ -443,6 +443,12 @@ public final class TraitSetter { } } } + if (backProps.backgroungImageTargetWidth.getValue() != 0) { + back.setImageTargetWidth(backProps.backgroungImageTargetWidth.getValue()); + } + if (backProps.backgroungImageTargetHeight.getValue() != 0) { + back.setImageTargetHeight(backProps.backgroungImageTargetHeight.getValue()); + } } area.addTrait(Trait.BACKGROUND, back); diff --git a/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java b/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java index 622b6d269..bc514acd9 100644 --- a/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java +++ b/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java @@ -266,10 +266,21 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer { if (back.getImageInfo() != null) { ImageSize imageSize = back.getImageInfo().getSize(); - int horzCount = (int)((paddRectWidth - * 1000 / imageSize.getWidthMpt()) + 1.0f); - int vertCount = (int)((paddRectHeight - * 1000 / imageSize.getHeightMpt()) + 1.0f); + int targetWidth = imageSize.getWidthMpt(); + int targetHeight = imageSize.getHeightMpt(); + double multiplier = 1.0; + if (back.getImageTargetWidth() != 0 && back.getImageTargetHeight() != 0) { + multiplier = Math.min(1.0 * back.getImageTargetWidth() / targetWidth, + 1.0 * back.getImageTargetHeight() / targetHeight); + } else if (back.getImageTargetHeight() != 0) { + multiplier = 1.0 * back.getImageTargetHeight() / targetHeight; + } else if (back.getImageTargetWidth() != 0) { + multiplier = 1.0 * back.getImageTargetWidth() / targetWidth; + } + targetWidth = (int) (targetWidth * multiplier); + targetHeight = (int) (targetHeight * multiplier); + int horzCount = (int) ((paddRectWidth * 1000 / targetWidth) + 1.0f); + int vertCount = (int) ((paddRectHeight * 1000 / targetHeight) + 1.0f); if (back.getRepeat() == EN_NOREPEAT) { horzCount = 1; vertCount = 1; @@ -292,12 +303,8 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer { // place once Rectangle2D pos; // Image positions are relative to the currentIP/BP - pos = new Rectangle2D.Float(sx - currentIPPosition - + (x * imageSize.getWidthMpt()), - sy - currentBPPosition - + (y * imageSize.getHeightMpt()), - imageSize.getWidthMpt(), - imageSize.getHeightMpt()); + pos = new Rectangle2D.Float(sx - currentIPPosition + (x * targetWidth), sy + - currentBPPosition + (y * targetHeight), targetWidth, targetHeight); drawImage(back.getURL(), pos); } } diff --git a/test/java/org/apache/fop/area/TraitTestCase.java b/test/java/org/apache/fop/area/TraitTestCase.java new file mode 100644 index 000000000..2c77228c5 --- /dev/null +++ b/test/java/org/apache/fop/area/TraitTestCase.java @@ -0,0 +1,42 @@ +/* + * 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: ActiveLayouts.java 99 2008-11-24 11:06:55Z vincent $ */ + +package org.apache.fop.area; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class TraitTestCase { + + @Test + public void testImageTargetWidthAndHeight() { + int width = 2911; + int height = 1911; + Trait.Background background = new Trait.Background(); + background.setImageTargetWidth(width); + background.setImageTargetHeight(height); + assertEquals(width, background.getImageTargetWidth()); + assertEquals(height, background.getImageTargetHeight()); + assertTrue(background.toString().contains(Integer.toString(width))); + assertTrue(background.toString().contains(Integer.toString(height))); + } + +} diff --git a/test/java/org/apache/fop/render/AbstractPathOrientedRendererTestCase.java b/test/java/org/apache/fop/render/AbstractPathOrientedRendererTestCase.java new file mode 100644 index 000000000..b7ab64fcf --- /dev/null +++ b/test/java/org/apache/fop/render/AbstractPathOrientedRendererTestCase.java @@ -0,0 +1,162 @@ +/* + * 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; + +import java.awt.Color; +import java.awt.Rectangle; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.util.List; +import java.util.Map; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; + +import org.apache.xmlgraphics.image.loader.ImageInfo; +import org.apache.xmlgraphics.image.loader.ImageSize; + +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.area.CTM; +import org.apache.fop.area.Trait; + +public class AbstractPathOrientedRendererTestCase { + + @Before + public void setUp() throws Exception { + } + + @Test + public void testDrawBackgroundWithTargetImageSizes() { + FOUserAgent userAgent = mock(FOUserAgent.class); + MyAPOR myAPOR = new MyAPOR(userAgent); + ImageSize imgSize = new ImageSize(300, 300, 300); + imgSize.setSizeInMillipoints(72000, 72000); + ImageInfo imgInfo = new ImageInfo(null, null); + imgInfo.setSize(imgSize); + Trait.Background background = new Trait.Background(); + background.setImageTargetWidth(300000); + background.setImageTargetHeight(300000); + background.setImageInfo(imgInfo); + myAPOR.drawBackground(0, 0, 600, 900, background, null, null, null, null); + String expected = "[x=0.0,y=0.0,w=3.0,h=3.0][x=0.0,y=3.0,w=3.0,h=3.0][x=0.0,y=6.0,w=3.0,h=3.0]" + + "[x=0.0,y=9.0,w=3.0,h=3.0][x=3.0,y=0.0,w=3.0,h=3.0][x=3.0,y=3.0,w=3.0,h=3.0]" + + "[x=3.0,y=6.0,w=3.0,h=3.0][x=3.0,y=9.0,w=3.0,h=3.0][x=6.0,y=0.0,w=3.0,h=3.0]" + + "[x=6.0,y=3.0,w=3.0,h=3.0][x=6.0,y=6.0,w=3.0,h=3.0][x=6.0,y=9.0,w=3.0,h=3.0]"; + assertEquals(expected, myAPOR.getActual().replaceAll("00000", "")); + myAPOR.resetActual(); + background.setImageTargetWidth(0); + myAPOR.drawBackground(0, 0, 600, 900, background, null, null, null, null); + assertEquals(expected, myAPOR.getActual().replaceAll("00000", "")); + myAPOR.resetActual(); + background.setImageTargetWidth(300000); + background.setImageTargetHeight(0); + myAPOR.drawBackground(0, 0, 600, 900, background, null, null, null, null); + assertEquals(expected, myAPOR.getActual().replaceAll("00000", "")); + } + + private class MyAPOR extends AbstractPathOrientedRenderer { + + private String actual = ""; + + public MyAPOR(FOUserAgent userAgent) { + super(userAgent); + } + + public String getActual() { + return actual; + } + + public void resetActual() { + actual = ""; + } + + public String getMimeType() { + return null; + } + + protected void concatenateTransformationMatrix(AffineTransform at) { + } + + protected void restoreStateStackAfterBreakOut(List breakOutList) { + } + + protected List breakOutOfStateStack() { + return null; + } + + protected void saveGraphicsState() { + } + + protected void restoreGraphicsState() { + } + + protected void beginTextObject() { + } + + protected void endTextObject() { + } + + protected void clip() { + } + + protected void clipRect(float x, float y, float width, float height) { + } + + protected void moveTo(float x, float y) { + } + + protected void lineTo(float x, float y) { + } + + protected void closePath() { + } + + protected void fillRect(float x, float y, float width, float height) { + } + + protected void updateColor(Color col, boolean fill) { + } + + protected void drawImage(String url, Rectangle2D pos, Map foreignAttributes) { + String s = pos.toString(); + actual += s.substring(s.indexOf('[')); + } + + protected void drawBorderLine(float x1, float y1, float x2, float y2, boolean horz, + boolean startOrBefore, int style, Color col) { + } + + protected void startVParea(CTM ctm, Rectangle clippingRect) { + } + + protected void endVParea() { + } + + protected void startLayer(String layer) { + } + + protected void endLayer() { + } + + } +} -- 2.39.5