/* * ==================================================================== * 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.xslf.util; import static java.util.Spliterator.NONNULL; import static java.util.Spliterator.ORDERED; import java.awt.Graphics2D; import java.awt.geom.Dimension2D; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import java.util.Set; import java.util.Spliterator; import java.util.Spliterators; import java.util.TreeSet; import java.util.function.Consumer; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; import java.util.stream.StreamSupport; import org.apache.poi.common.usermodel.GenericRecord; import org.apache.poi.sl.draw.EmbeddedExtractor.EmbeddedPart; import org.apache.poi.sl.usermodel.ObjectData; import org.apache.poi.sl.usermodel.ObjectShape; import org.apache.poi.sl.usermodel.Shape; import org.apache.poi.sl.usermodel.Slide; import org.apache.poi.sl.usermodel.SlideShow; import org.apache.poi.sl.usermodel.SlideShowFactory; import org.apache.poi.util.IOUtils; import org.apache.poi.util.Internal; /** Handler for ppt and pptx files */ @Internal class PPTHandler extends MFProxy { private SlideShow ppt; private Slide slide; @Override public void parse(File file) throws IOException { try { ppt = SlideShowFactory.create(file, null, true); } catch (IOException e) { if (e.getMessage().contains("scratchpad")) { throw new PPTX2PNG.NoScratchpadException(e); } else { throw e; } } if (ppt == null) { throw new IOException("Unknown file format or missing poi-scratchpad.jar / poi-ooxml.jar"); } slide = ppt.getSlides().get(0); } @Override public void parse(InputStream is) throws IOException { try { ppt = SlideShowFactory.create(is, null); } catch (IOException e) { if (e.getMessage().contains("scratchpad")) { throw new PPTX2PNG.NoScratchpadException(e); } else { throw e; } } if (ppt == null) { throw new IOException("Unknown file format or missing poi-scratchpad.jar / poi-ooxml.jar"); } slide = ppt.getSlides().get(0); } @Override public Dimension2D getSize() { return ppt.getPageSize(); } @Override public int getSlideCount() { return ppt.getSlides().size(); } @Override public void setSlideNo(int slideNo) { slide = ppt.getSlides().get(slideNo-1); } @Override public String getTitle() { return slide.getTitle(); } private static final String RANGE_PATTERN = "(^|,)(?\\d+)?(-(?\\d+))?"; @Override public Set slideIndexes(String range) { final Matcher matcher = Pattern.compile(RANGE_PATTERN).matcher(range); Spliterator sp = new Spliterators.AbstractSpliterator(range.length(), ORDERED|NONNULL){ @Override public boolean tryAdvance(Consumer action) { boolean b = matcher.find(); if (b) { action.accept(matcher); } return b; } }; return StreamSupport.stream(sp, false). flatMap(this::range). collect(Collectors.toCollection(TreeSet::new)); } @Override public void draw(Graphics2D ctx) { slide.draw(ctx); } @Override public void close() throws IOException { if (ppt != null) { ppt.close(); } } @Override public GenericRecord getRoot() { return (ppt instanceof GenericRecord) ? (GenericRecord)ppt : null; } private Stream range(Matcher m) { final int slideCount = ppt.getSlides().size(); String fromStr = m.group("from"); String toStr = m.group("to"); int from = (fromStr == null || fromStr.isEmpty() ? 1 : Integer.parseInt(fromStr)); int to = (toStr == null) ? from : (toStr.isEmpty() || ((fromStr == null || fromStr.isEmpty()) && "1".equals(toStr))) ? slideCount : Integer.parseInt(toStr); return IntStream.rangeClosed(from, to).filter(i -> i <= slideCount).boxed(); } @Override public Iterable getEmbeddings(int slideNo) { return () -> ppt.getSlides().get(slideNo).getShapes().stream(). filter(s -> s instanceof ObjectShape). map(PPTHandler::fromObjectShape). iterator() ; } private static EmbeddedPart fromObjectShape(Shape s) { final ObjectShape os = (ObjectShape)s; final ObjectData od = os.getObjectData(); EmbeddedPart embed = new EmbeddedPart(); embed.setName(od.getFileName()); embed.setData(() -> { try (InputStream is = od.getInputStream()) { return IOUtils.toByteArray(is); } catch (IOException e) { // TODO: change to custom runtime exception throw new IllegalStateException(e); } }); return embed; } @Override void setDefaultCharset(Charset charset) { } }