| /* ==================================================================== |
| 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. |
| ==================================================================== */ |
| |
| package org.apache.poi.hslf.usermodel; |
| |
| import java.awt.Color; |
| import java.io.ByteArrayInputStream; |
| import java.io.InputStream; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| |
| import org.apache.logging.log4j.LogManager; |
| import org.apache.logging.log4j.Logger; |
| import org.apache.poi.ddf.AbstractEscherOptRecord; |
| import org.apache.poi.ddf.EscherArrayProperty; |
| import org.apache.poi.ddf.EscherBSERecord; |
| import org.apache.poi.ddf.EscherColorRef; |
| import org.apache.poi.ddf.EscherContainerRecord; |
| import org.apache.poi.ddf.EscherPropertyTypes; |
| import org.apache.poi.ddf.EscherRecord; |
| import org.apache.poi.ddf.EscherRecordTypes; |
| import org.apache.poi.ddf.EscherSimpleProperty; |
| import org.apache.poi.hslf.record.Document; |
| import org.apache.poi.sl.draw.DrawPaint; |
| import org.apache.poi.sl.usermodel.ColorStyle; |
| import org.apache.poi.sl.usermodel.FillStyle; |
| import org.apache.poi.sl.usermodel.PaintStyle; |
| import org.apache.poi.sl.usermodel.PaintStyle.GradientPaint; |
| import org.apache.poi.sl.usermodel.PaintStyle.GradientPaint.GradientType; |
| import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint; |
| import org.apache.poi.sl.usermodel.PictureData; |
| import org.apache.poi.util.BitField; |
| import org.apache.poi.util.BitFieldFactory; |
| import org.apache.poi.util.LittleEndian; |
| import org.apache.poi.util.Units; |
| |
| import static org.apache.logging.log4j.util.Unbox.box; |
| |
| /** |
| * Represents functionality provided by the 'Fill Effects' dialog in PowerPoint. |
| */ |
| @SuppressWarnings("WeakerAccess") |
| public final class HSLFFill { |
| private static final Logger LOG = LogManager.getLogger(HSLFFill.class); |
| |
| /** |
| * Fill with a solid color |
| */ |
| static final int FILL_SOLID = 0; |
| |
| /** |
| * Fill with a pattern (bitmap) |
| */ |
| static final int FILL_PATTERN = 1; |
| |
| /** |
| * A texture (pattern with its own color map) |
| */ |
| static final int FILL_TEXTURE = 2; |
| |
| /** |
| * Center a picture in the shape |
| */ |
| static final int FILL_PICTURE = 3; |
| |
| /** |
| * Shade from start to end points |
| */ |
| static final int FILL_SHADE = 4; |
| |
| /** |
| * Shade from bounding rectangle to end point |
| */ |
| static final int FILL_SHADE_CENTER = 5; |
| |
| /** |
| * Shade from shape outline to end point |
| */ |
| static final int FILL_SHADE_SHAPE = 6; |
| |
| /** |
| * Similar to FILL_SHADE, but the fill angle |
| * is additionally scaled by the aspect ratio of |
| * the shape. If shape is square, it is the same as FILL_SHADE |
| */ |
| static final int FILL_SHADE_SCALE = 7; |
| |
| /** |
| * shade to title |
| */ |
| static final int FILL_SHADE_TITLE = 8; |
| |
| /** |
| * Use the background fill color/pattern |
| */ |
| static final int FILL_BACKGROUND = 9; |
| |
| /** |
| * A bit that specifies whether the RecolorFillAsPicture bit is set. |
| * A value of 0x0 specifies that the fRecolorFillAsPicture MUST be ignored. |
| * The default value for this property is 0x0. |
| */ |
| private static final BitField FILL_USE_RECOLOR_FILL_AS_PICTURE = BitFieldFactory.getInstance(0x00400000); |
| |
| /** |
| * A bit that specifies whether the UseShapeAnchor bit is set. |
| * A value of 0x0 specifies that the fUseShapeAnchor MUST be ignored. |
| * The default value for this property is 0x0. |
| */ |
| private static final BitField FILL_USE_USE_SHAPE_ANCHOR = BitFieldFactory.getInstance(0x00200000); |
| |
| /** |
| * A bit that specifies whether the Filled bit is set. |
| * A value of 0x0 specifies that the Filled MUST be ignored. |
| * The default value for this property is 0x0. |
| */ |
| private static final BitField FILL_USE_FILLED = BitFieldFactory.getInstance(0x00100000); |
| |
| /** |
| * A bit that specifies whether the HitTestFill bit is set. |
| * A value of 0x0 specifies that the HitTestFill MUST be ignored. |
| * The default value for this property is 0x0. |
| */ |
| private static final BitField FILL_USE_HIT_TEST_FILL = BitFieldFactory.getInstance(0x00080000); |
| |
| /** |
| * A bit that specifies whether the fillShape bit is set. |
| * A value of 0x0 specifies that the fillShape MUST be ignored. |
| * The default value for this property is 0x0. |
| */ |
| private static final BitField FILL_USE_FILL_SHAPE = BitFieldFactory.getInstance(0x00040000); |
| |
| /** |
| * A bit that specifies whether the fillUseRect bit is set. |
| * A value of 0x0 specifies that the fillUseRect MUST be ignored. |
| * The default value for this property is 0x0. |
| */ |
| private static final BitField FILL_USE_FILL_USE_RECT = BitFieldFactory.getInstance(0x00020000); |
| |
| /** |
| * A bit that specifies whether the fNoFillHitTest bit is set. |
| * A value of 0x0 specifies that the fNoFillHitTest MUST be ignored. |
| * The default value for this property is 0x0. |
| */ |
| private static final BitField FILL_USE_NO_FILL_HIT_TEST = BitFieldFactory.getInstance(0x00010000); |
| |
| /** |
| * A bit that specifies how to recolor a picture fill. If this bit is set to 0x1, the pictureFillCrMod |
| * property of the picture fill is used for recoloring. If this bit is set to 0x0, the fillCrMod property, |
| * as defined in section 2.3.7.6, is used for recoloring. |
| * If UsefRecolorFillAsPicture equals 0x0, this value MUST be ignored. |
| * The default value for this property is 0x0. |
| */ |
| private static final BitField FILL_RECOLOR_FILL_AS_PICTURE = BitFieldFactory.getInstance(0x00000040); |
| |
| /** |
| * A bit that specifies whether the fill is rotated with the shape. |
| * If UseUseShapeAnchor equals 0x0, this value MUST be ignored. |
| * The default value for this property is 0x0. |
| */ |
| private static final BitField FILL_USE_SHAPE_ANCHOR = BitFieldFactory.getInstance(0x00000020); |
| |
| /** |
| * A bit that specifies whether the fill is rendered if the shape is a 2-D shape. |
| * If this bit is set to 0x1, the fill of this shape is rendered based on the properties of the Fill Style |
| * property set. If this bit is set to 0x0, the fill of this shape is not rendered. |
| * If UseFilled is 0x0, this value MUST be ignored. The default value for this property is 0x1. |
| */ |
| private static final BitField FILL_FILLED = BitFieldFactory.getInstance(0x00000010); |
| |
| /** |
| * A bit that specifies whether this fill will be hit tested. |
| * If UsefHitTestFill equals 0x0, this value MUST be ignored. |
| * The default value for this property is 0x1. |
| */ |
| private static final BitField FILL_HIT_TEST_FILL = BitFieldFactory.getInstance(0x00000008); |
| |
| /** |
| * A bit that specifies how the fill is aligned. If this bit is set to 0x1, the fill is |
| * aligned relative to the shape so that it moves with the shape. If this bit is set to 0x0, |
| * the fill is aligned with the origin of the view. If fUsefillShape equals 0x0, this value MUST be ignored. |
| * The default value for this property is 0x1. |
| */ |
| private static final BitField FILL_FILL_SHAPE = BitFieldFactory.getInstance(0x00000004); |
| |
| /** |
| * A bit that specifies whether to use the rectangle specified by the fillRectLeft, fillRectRight, |
| * fillRectTop, and fillRectBottom properties, rather than the bounding rectangle of the shape, |
| * as the filled area. If fUsefillUseRect equals 0x0, this value MUST be ignored. |
| * The default value for this property is 0x0. |
| */ |
| private static final BitField FILL_FILL_USE_RECT = BitFieldFactory.getInstance(0x00000002); |
| |
| /** |
| * A bit that specifies whether this shape will be hit tested as though it were filled. |
| * If UsefNoFillHitTest equals 0x0, this value MUST be ignored. |
| * The default value for this property is 0x0. |
| */ |
| private static final BitField FILL_NO_FILL_HIT_TEST = BitFieldFactory.getInstance(0x00000001); |
| |
| |
| /** |
| * The shape this background applies to |
| */ |
| private HSLFShape shape; |
| |
| /** |
| * Construct a {@code Fill} object for a shape. |
| * Fill information will be read from shape's escher properties. |
| * |
| * @param shape the shape this background applies to |
| */ |
| public HSLFFill(HSLFShape shape){ |
| this.shape = shape; |
| } |
| |
| |
| public FillStyle getFillStyle() { |
| return this::getPaintStyle; |
| } |
| |
| private PaintStyle getPaintStyle() { |
| AbstractEscherOptRecord opt = shape.getEscherOptRecord(); |
| |
| EscherSimpleProperty hitProp = HSLFShape.getEscherProperty(opt, EscherPropertyTypes.FILL__NOFILLHITTEST); |
| int propVal = (hitProp == null) ? 0 : hitProp.getPropertyValue(); |
| |
| EscherSimpleProperty masterProp = HSLFShape.getEscherProperty(opt, EscherPropertyTypes.SHAPE__MASTER); |
| |
| if (!FILL_USE_FILLED.isSet(propVal) && masterProp != null) { |
| int masterId = masterProp.getPropertyValue(); |
| HSLFShape o = shape.getSheet().getMasterSheet().getShapes().stream().filter(s -> s.getShapeId() == masterId).findFirst().orElse(null); |
| return o != null ? o.getFillStyle().getPaint() : null; |
| } |
| |
| final int fillType = getFillType(); |
| // TODO: fix gradient types, this mismatches with the MS-ODRAW definition ... |
| // need to handle (not only) the type (radial,rectangular,linear), |
| // the direction, e.g. top right, and bounds (e.g. for rectangular boxes) |
| switch (fillType) { |
| case FILL_SOLID: |
| return DrawPaint.createSolidPaint(getForegroundColor()); |
| case FILL_SHADE_SHAPE: |
| return getGradientPaint(GradientType.shape); |
| case FILL_SHADE_CENTER: |
| case FILL_SHADE_TITLE: |
| return getGradientPaint(GradientType.circular); |
| case FILL_SHADE: |
| case FILL_SHADE_SCALE: |
| return getGradientPaint(GradientType.linear); |
| case FILL_PICTURE: |
| return getTexturePaint(); |
| default: |
| LOG.atWarn().log("unsupported fill type: {}", box(fillType)); |
| return null; |
| } |
| } |
| |
| private boolean isRotatedWithShape() { |
| // NOFILLHITTEST can be in the normal escher opt record but also in the tertiary record |
| // the extended bit fields seem to be in the second |
| AbstractEscherOptRecord opt = shape.getEscherChild(EscherRecordTypes.USER_DEFINED); |
| EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherPropertyTypes.FILL__NOFILLHITTEST); |
| int propVal = (p == null) ? 0 : p.getPropertyValue(); |
| return FILL_USE_USE_SHAPE_ANCHOR.isSet(propVal) && FILL_USE_SHAPE_ANCHOR.isSet(propVal); |
| } |
| |
| private GradientPaint getGradientPaint(final GradientType gradientType) { |
| AbstractEscherOptRecord opt = shape.getEscherOptRecord(); |
| |
| EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherPropertyTypes.FILL__NOFILLHITTEST); |
| int propVal = (p == null) ? 0 : p.getPropertyValue(); |
| |
| if (FILL_USE_FILLED.isSet(propVal) && !FILL_FILLED.isSet(propVal)) { |
| return null; |
| } |
| |
| |
| final EscherArrayProperty ep = HSLFShape.getEscherProperty(opt, EscherPropertyTypes.FILL__SHADECOLORS); |
| final int colorCnt = (ep == null) ? 0 : ep.getNumberOfElementsInArray(); |
| |
| final List<Color> colors = new ArrayList<>(); |
| final List<Float> fractions = new ArrayList<>(); |
| |
| // TODO: handle palette colors and alpha(?) value |
| if (colorCnt == 0) { |
| colors.add(getBackgroundColor()); |
| colors.add(getForegroundColor()); |
| fractions.add(0f); |
| fractions.add(1f); |
| } else { |
| ep.forEach(data -> { |
| EscherColorRef ecr = new EscherColorRef(data, 0, 4); |
| colors.add(shape.getColor(ecr)); |
| double pos = Units.fixedPointToDouble(LittleEndian.getInt(data, 4)); |
| fractions.add((float)pos); |
| }); |
| } |
| |
| int focus = getFillFocus(); |
| if (focus == 100 || focus == -100) { |
| Collections.reverse(colors); |
| } else if (focus != 0) { |
| if (focus < 0) { |
| focus = 100+focus; |
| } |
| // TODO: depending on fill focus, rotation with shape and other escher properties |
| // there are still a lot of cases where we get the gradients wrong |
| List<Color> reflectedColors = new ArrayList<>(colors.subList(1,colors.size())); |
| Collections.reverse(reflectedColors); |
| colors.addAll(0, reflectedColors); |
| |
| final List<Float> fractRev = new ArrayList<>(); |
| for (int i=fractions.size()-2; i >= 0; i--) { |
| float val = (float)(1 - fractions.get(i) * focus / 100.); |
| fractRev.add(val); |
| } |
| for (int i=0; i<fractions.size(); i++) { |
| float val = (float)(fractions.get(i) * focus / 100.); |
| fractions.set(i, val); |
| } |
| fractions.addAll(fractRev); |
| } |
| |
| return new GradientPaint() { |
| @Override |
| public double getGradientAngle() { |
| // A value of type FixedPoint, as specified in [MS-OSHARED] section 2.2.1.6, |
| // that specifies the angle of the gradient fill. Zero degrees represents a vertical vector from |
| // bottom to top. The default value for this property is 0x00000000. |
| int rot = shape.getEscherProperty(EscherPropertyTypes.FILL__ANGLE); |
| return 90-Units.fixedPointToDouble(rot); |
| } |
| |
| @Override |
| public ColorStyle[] getGradientColors() { |
| return colors.stream().map(this::wrapColor).toArray(ColorStyle[]::new); |
| } |
| |
| private ColorStyle wrapColor(Color col) { |
| return (col == null) ? null : DrawPaint.createSolidPaint(col).getSolidColor(); |
| } |
| |
| @Override |
| public float[] getGradientFractions() { |
| float[] frc = new float[fractions.size()]; |
| for (int i = 0; i<fractions.size(); i++) { |
| frc[i] = fractions.get(i); |
| } |
| return frc; |
| } |
| |
| @Override |
| public boolean isRotatedWithShape() { |
| return HSLFFill.this.isRotatedWithShape(); |
| } |
| |
| @Override |
| public GradientType getGradientType() { |
| return gradientType; |
| } |
| }; |
| } |
| |
| private TexturePaint getTexturePaint() { |
| final HSLFPictureData pd = getPictureData(); |
| if (pd == null) { |
| return null; |
| } |
| |
| return new TexturePaint() { |
| @Override |
| public InputStream getImageData() { |
| return new ByteArrayInputStream(pd.getData()); |
| } |
| |
| @Override |
| public String getContentType() { |
| return pd.getContentType(); |
| } |
| |
| @Override |
| public int getAlpha() { |
| return (int)(shape.getAlpha(EscherPropertyTypes.FILL__FILLOPACITY)*100000.0); |
| } |
| |
| @Override |
| public boolean isRotatedWithShape() { |
| return HSLFFill.this.isRotatedWithShape(); |
| } |
| }; |
| } |
| |
| /** |
| * Returns fill type. |
| * Must be one of the {@code FILL_*} constants defined in this class. |
| * |
| * @return type of fill |
| */ |
| public int getFillType(){ |
| AbstractEscherOptRecord opt = shape.getEscherOptRecord(); |
| EscherSimpleProperty prop = HSLFShape.getEscherProperty(opt, EscherPropertyTypes.FILL__FILLTYPE); |
| return prop == null ? FILL_SOLID : prop.getPropertyValue(); |
| } |
| |
| /** |
| * The fillFocus property specifies the relative position of the last color in the shaded fill. |
| * Its used to specify the center of an reflected fill. 0 = no reflection, 50 = reflected in the middle. |
| * If fillFocus is less than 0, the relative position of the last color is outside the shape, |
| * and the relative position of the first color is within the shape. |
| * |
| * @return a percentage in the range of -100 .. 100; defaults to 0 |
| */ |
| public int getFillFocus() { |
| AbstractEscherOptRecord opt = shape.getEscherOptRecord(); |
| EscherSimpleProperty prop = HSLFShape.getEscherProperty(opt, EscherPropertyTypes.FILL__FOCUS); |
| return prop == null ? 0 : prop.getPropertyValue(); |
| } |
| |
| void afterInsert(HSLFSheet sh){ |
| AbstractEscherOptRecord opt = shape.getEscherOptRecord(); |
| EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherPropertyTypes.FILL__PATTERNTEXTURE); |
| if(p != null) { |
| int idx = p.getPropertyValue(); |
| EscherBSERecord bse = getEscherBSERecord(idx); |
| if (bse != null) { |
| bse.setRef(bse.getRef() + 1); |
| } |
| } |
| } |
| |
| @SuppressWarnings("resource") |
| EscherBSERecord getEscherBSERecord(int idx){ |
| HSLFSheet sheet = shape.getSheet(); |
| if(sheet == null) { |
| LOG.atDebug().log("Fill has not yet been assigned to a sheet"); |
| return null; |
| } |
| HSLFSlideShow ppt = sheet.getSlideShow(); |
| Document doc = ppt.getDocumentRecord(); |
| EscherContainerRecord dggContainer = doc.getPPDrawingGroup().getDggContainer(); |
| EscherContainerRecord bstore = HSLFShape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER); |
| if(bstore == null) { |
| LOG.atDebug().log("EscherContainerRecord.BSTORE_CONTAINER was not found "); |
| return null; |
| } |
| List<EscherRecord> lst = bstore.getChildRecords(); |
| return (EscherBSERecord)lst.get(idx-1); |
| } |
| |
| /** |
| * Sets fill type. |
| * Must be one of the {@code FILL_*} constants defined in this class. |
| * |
| * @param type type of the fill |
| */ |
| public void setFillType(int type){ |
| AbstractEscherOptRecord opt = shape.getEscherOptRecord(); |
| HSLFShape.setEscherProperty(opt, EscherPropertyTypes.FILL__FILLTYPE, type); |
| } |
| |
| /** |
| * Foreground color |
| */ |
| public Color getForegroundColor(){ |
| AbstractEscherOptRecord opt = shape.getEscherOptRecord(); |
| EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherPropertyTypes.FILL__NOFILLHITTEST); |
| int propVal = (p == null) ? 0 : p.getPropertyValue(); |
| |
| return (!FILL_USE_FILLED.isSet(propVal) || (FILL_USE_FILLED.isSet(propVal) && FILL_FILLED.isSet(propVal))) |
| ? shape.getColor(EscherPropertyTypes.FILL__FILLCOLOR, EscherPropertyTypes.FILL__FILLOPACITY) |
| : null; |
| } |
| |
| /** |
| * Foreground color |
| */ |
| public void setForegroundColor(Color color){ |
| AbstractEscherOptRecord opt = shape.getEscherOptRecord(); |
| opt.removeEscherProperty(EscherPropertyTypes.FILL__FILLOPACITY); |
| opt.removeEscherProperty(EscherPropertyTypes.FILL__FILLCOLOR); |
| |
| if (color != null) { |
| int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 0).getRGB(); |
| HSLFShape.setEscherProperty(opt, EscherPropertyTypes.FILL__FILLCOLOR, rgb); |
| int alpha = color.getAlpha(); |
| if (alpha < 255) { |
| int alphaFP = Units.doubleToFixedPoint(alpha/255d); |
| HSLFShape.setEscherProperty(opt, EscherPropertyTypes.FILL__FILLOPACITY, alphaFP); |
| } |
| } |
| |
| EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherPropertyTypes.FILL__NOFILLHITTEST); |
| int propVal = (p == null) ? 0 : p.getPropertyValue(); |
| propVal = FILL_FILLED.setBoolean(propVal, color != null); |
| propVal = FILL_NO_FILL_HIT_TEST.setBoolean(propVal, color != null); |
| propVal = FILL_USE_FILLED.set(propVal); |
| propVal = FILL_USE_FILL_SHAPE.set(propVal); |
| propVal = FILL_USE_NO_FILL_HIT_TEST.set(propVal); |
| // TODO: check why we always clear this ... |
| propVal = FILL_FILL_SHAPE.clear(propVal); |
| |
| HSLFShape.setEscherProperty(opt, EscherPropertyTypes.FILL__NOFILLHITTEST, propVal); |
| } |
| |
| /** |
| * Background color |
| */ |
| public Color getBackgroundColor(){ |
| AbstractEscherOptRecord opt = shape.getEscherOptRecord(); |
| EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherPropertyTypes.FILL__NOFILLHITTEST); |
| int propVal = (p == null) ? 0 : p.getPropertyValue(); |
| |
| return (!FILL_USE_FILLED.isSet(propVal) || (FILL_USE_FILLED.isSet(propVal) && FILL_FILLED.isSet(propVal))) |
| ? shape.getColor(EscherPropertyTypes.FILL__FILLBACKCOLOR, EscherPropertyTypes.FILL__FILLOPACITY) |
| : null; |
| } |
| |
| /** |
| * Background color |
| */ |
| public void setBackgroundColor(Color color){ |
| AbstractEscherOptRecord opt = shape.getEscherOptRecord(); |
| if (color == null) { |
| HSLFShape.setEscherProperty(opt, EscherPropertyTypes.FILL__FILLBACKCOLOR, -1); |
| } |
| else { |
| int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 0).getRGB(); |
| HSLFShape.setEscherProperty(opt, EscherPropertyTypes.FILL__FILLBACKCOLOR, rgb); |
| } |
| } |
| |
| /** |
| * {@code PictureData} object used in a texture, pattern of picture fill. |
| */ |
| @SuppressWarnings("resource") |
| public HSLFPictureData getPictureData(){ |
| AbstractEscherOptRecord opt = shape.getEscherOptRecord(); |
| EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherPropertyTypes.FILL__PATTERNTEXTURE); |
| if (p == null) { |
| return null; |
| } |
| |
| HSLFSlideShow ppt = shape.getSheet().getSlideShow(); |
| List<HSLFPictureData> pict = ppt.getPictureData(); |
| Document doc = ppt.getDocumentRecord(); |
| |
| EscherContainerRecord dggContainer = doc.getPPDrawingGroup().getDggContainer(); |
| EscherContainerRecord bstore = HSLFShape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER); |
| |
| List<EscherRecord> lst = bstore.getChildRecords(); |
| int idx = p.getPropertyValue(); |
| if (idx == 0){ |
| LOG.atWarn().log("no reference to picture data found "); |
| } else { |
| EscherBSERecord bse = (EscherBSERecord)lst.get(idx - 1); |
| for (HSLFPictureData pd : pict) { |
| if (pd.getOffset() == bse.getOffset()){ |
| return pd; |
| } |
| } |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Assign picture used to fill the underlying shape. |
| * |
| * @param data the picture data added to this ppt by {@link HSLFSlideShow#addPicture(byte[], PictureData.PictureType)} method. |
| */ |
| public void setPictureData(HSLFPictureData data){ |
| AbstractEscherOptRecord opt = shape.getEscherOptRecord(); |
| HSLFShape.setEscherProperty(opt, EscherPropertyTypes.FILL__PATTERNTEXTURE, true, (data == null ? 0 : data.getIndex())); |
| if(data != null && shape.getSheet() != null) { |
| EscherBSERecord bse = getEscherBSERecord(data.getIndex()); |
| if (bse != null) { |
| bse.setRef(bse.getRef() + 1); |
| } |
| } |
| } |
| |
| } |