From 4f812913ea63842a181586d43ac3a19e0bccfd9b Mon Sep 17 00:00:00 2001 From: Sean McDevitt Date: Wed, 8 Nov 2017 23:30:09 -0700 Subject: [PATCH 1/2] ContentPlaceholder support A quick hack that: - adds insert_picture to generic SlidePlaceholder. Still need to figure out how the various placeholder types are associated to the specific classes. - Implement crop kwarg as mentioned in a gh feature request. Modified it slightly so that the image stays centered when not cropped. Appears to work and the figure properly rescales when the layout is changed. --- pptx/shapes/placeholder.py | 58 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/pptx/shapes/placeholder.py b/pptx/shapes/placeholder.py index 7311dd868..89837343c 100644 --- a/pptx/shapes/placeholder.py +++ b/pptx/shapes/placeholder.py @@ -270,6 +270,64 @@ class SlidePlaceholder(_BaseSlidePlaceholder): Placeholder shape on a slide. Inherits shape properties from its corresponding slide layout placeholder. """ + def insert_picture(self, image_file, crop=True): + """ + Return a |PlaceholderPicture| object depicting the image in + *image_file*, which may be either a path (string) or a file-like + object. The image is cropped to fill the entire space of the + placeholder. A |PlaceholderPicture| object has all the properties and + methods of a |Picture| shape except that the value of its + :attr:`~._BaseSlidePlaceholder.shape_type` property is + `MSO_SHAPE_TYPE.PLACEHOLDER` instead of `MSO_SHAPE_TYPE.PICTURE`. + """ + pic = self._new_placeholder_pic(image_file, crop) # pass new parameter "method" + self._replace_placeholder_with(pic) + return PlaceholderPicture(pic, self._parent) + + def _new_placeholder_pic(self, image_file, crop=True): + """ + Return a new `p:pic` element depicting the image in *image_file*, + suitable for use as a placeholder. In particular this means not + having an `a:xfrm` element, allowing its extents to be inherited from + its layout placeholder. + """ + rId, desc, image_size = self._get_or_add_image(image_file) + id_, name = self.shape_id, self.name + + # Cropping the image, as in the original file + if crop: + pic = CT_Picture.new_ph_pic(id_, name, desc, rId) + pic.crop_to_fit(image_size, (self.width, self.height)) + + # Adjusting image to placeholder size and replace placeholder. + else: + ph_w, ph_h = self.width, self.height + aspectPh = ph_w / ph_h + + img_w, img_h = image_size + aspectImg = img_w / img_h + + if aspectPh > aspectImg: + w = int(ph_h * aspectImg) + h = ph_h # keep the height + else: + w = ph_w # keep the width + h = int(ph_w / aspectImg) + + top = self.top + (ph_h - h) / 2 + left = self.left + (ph_w - w) / 2 + + pic = CT_Picture.new_pic(id_, name, desc, rId, self.left + (ph_w - w) / 2, self.top, w, h) + return pic + + def _get_or_add_image(self, image_file): + """ + Return an (rId, description, image_size) 3-tuple identifying the + related image part containing *image_file* and describing the image. + """ + image_part, rId = self.part.get_or_add_image_part(image_file) + desc, image_size = image_part.desc, image_part._px_size + return rId, desc, image_size class ChartPlaceholder(_BaseSlidePlaceholder): From 0c08df95a36e27a8a49cf5ec8240822ad674c2af Mon Sep 17 00:00:00 2001 From: Sean McDevitt Date: Sat, 14 Jan 2023 11:53:21 -0700 Subject: [PATCH 2/2] Create python-package.yml --- .github/workflows/python-package.yml | 40 ++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 .github/workflows/python-package.yml diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml new file mode 100644 index 000000000..4c4c87e0e --- /dev/null +++ b/.github/workflows/python-package.yml @@ -0,0 +1,40 @@ +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python + +name: Python package + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.8", "3.9", "3.10", "3.11"] + + steps: + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install flake8 pytest + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Test with pytest + run: | + pytest