Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Missing chartXX.xml files in generated PPTX #841

Open
dsferruzza opened this issue Jan 9, 2025 · 2 comments
Open

Missing chartXX.xml files in generated PPTX #841

dsferruzza opened this issue Jan 9, 2025 · 2 comments

Comments

@dsferruzza
Copy link

Hi!

When building a presentation that contains many charts, sometimes the generated PPTX file does not open in PowerPoint (version 2411 from Office 365).
PowerPoint asks to repair the document, but fails to do so.
Opening the same file with LibreOffice Impress (24.8.4.2) works, but at least one chart is missing (it is listed under the slide in the object navigator, but appears completely blank).

I could not find a minimal way to reproduce this issue yet, but this is definitely related to dynamic data because most of the time the same code works well and generates a valid PPTX file.
While investigating, I discovered that, when opening the PPTX as a ZIP file, a least one ppt/charts/chartXX.xml file is missing; for example, both ppt/charts/chart12.xml and ppt/charts/chart14.xml are there, but no ppt/charts/chart13.xml.
If I put a ppt/charts/chart13.xml file in the ZIP (for example by duplicating another XML chart file), it works well: PowerPoint stops complaining and both PowerPoint and LibreOffice display the presentation correctly (except that the missing chart is now a duplicate of another chart, of course).

I tried to dig deeper, but I am not familiar enough with this lib's internals so I figured it could be a good idea to ask for help/pointers.
At some point I had the intuition the issue might be caused by the way charts are gathered in a hash table (maybe multiple charts are identical or similar from the hash's perspective and this results by only generating one of these chart files), but I am not sure...

Do you have any idea on how to solve or investigate further this issue?


I am using the latest commit from master (6e9da89 at the moment of writing) and PHP 8.3.
This may be the same issue as #695 but I am not sure.

@Progi1984
Copy link
Member

@dsferruzza Have you got a sample code ?

@dsferruzza
Copy link
Author

dsferruzza commented Jan 12, 2025

@Progi1984 I managed to reproduce the issue with the following code (I ran it from the CLI but this does not really matter):

<?php

// In composer.json, the following is required:
// "phpoffice/phppresentation": "dev-master#6e9da8968e8afe79ffa6415d8294b9864b703060",
require 'vendor/autoload.php';

use PhpOffice\PhpPresentation\DocumentLayout;
use PhpOffice\PhpPresentation\IOFactory;
use PhpOffice\PhpPresentation\PhpPresentation;
use PhpOffice\PhpPresentation\Shape\Chart\Series;
use PhpOffice\PhpPresentation\Shape\Chart\Type\Pie;
use PhpOffice\PhpPresentation\Style\Alignment;
use PhpOffice\PhpPresentation\Style\Color;
use PhpOffice\PhpPresentation\Style\Fill;

const FONT_NAME = 'Helvetica';

const COLORS = [
    '3c4596',
    'a5e6fa',
    '90c8ee',
    '367ca1',
];

$presentation = new PhpPresentation();
$presentation->getLayout()->setDocumentLayout(DocumentLayout::LAYOUT_SCREEN_16X9);

$titleSlide = $presentation->getActiveSlide();
$titleShape = $titleSlide->createRichTextShape()
    ->setHeight(300)
    ->setWidth(900)
    ->setOffsetX(30)
    ->setOffsetY(100)
;
$titleShape->getActiveParagraph()->getAlignment()
    ->setHorizontal(Alignment::HORIZONTAL_CENTER)
;
$titleTextRun = $titleShape->createTextRun('Issue #841');
$titleTextRun->getFont()->setBold(true)
    ->setSize(60)
    ->setColor(new Color(Color::COLOR_BLACK))
    ->setName(FONT_NAME)
    ->setName(FONT_NAME)
;

///////////////////////////////////////

for ($slideNumber = 1; $slideNumber <= 2; $slideNumber++) {
    echo 'Creating slide #'.$slideNumber."\n";
    $slide = $presentation->createSlide();

    $data = [
        'Duration 1 (1h)' => 60,
        'Duration 2 (1h30)' => 90,
        'Duration 3 (2h)' => 120,
        'Duration 4 (0h30)' => 30,
    ];

    $colors = [
        0 => new Color('ff'.COLORS[0]),
        1 => new Color('ff'.COLORS[1]),
        2 => new Color('ff'.COLORS[2]),
        4 => new Color('ff'.COLORS[3]),
    ];

    $series1 = new Series('Durations', $data);
    $series1->setLabelPosition(Series::LABEL_OUTSIDEEND);
    $series1->setShowValue(false);
    $series1->setShowPercentage(false);
    $series1->setShowCategoryName(true);
    $series1->getFont()->setName(FONT_NAME)->setSize(8);
    foreach ($colors as $i => $color) {
        $series1->getDataPointFill($i)
            ->setFillType(Fill::FILL_SOLID)
            ->setStartColor($color)
        ;
    }
    $series2 = new Series('Durations', $data);
    $series2->setLabelPosition(Series::LABEL_OUTSIDEEND);
    $series2->setShowValue(false);
    $series2->setShowPercentage(false);
    $series2->setShowCategoryName(true);
    $series2->getFont()->setName(FONT_NAME)->setSize(8);
    foreach ($colors as $i => $color) {
        $series2->getDataPointFill($i)
            ->setFillType(Fill::FILL_SOLID)
            ->setStartColor($color)
        ;
    }

    $pieChart1 = new Pie();
    $pieChart1->addSeries($series1);

    $pieChart2 = new Pie();
    $pieChart2->addSeries($series2);

    $titleShape = $slide->createRichTextShape()
        ->setHeight(300)
        ->setWidth(900)
        ->setOffsetX(30)
        ->setOffsetY(20)
    ;
    $titleShape->getActiveParagraph()->getAlignment()
        ->setHorizontal(Alignment::HORIZONTAL_CENTER)
    ;
    $titleTextRun = $titleShape->createTextRun('Charts');
    $titleTextRun->getFont()->setBold(true)
        ->setSize(60)
        ->setColor(new Color(Color::COLOR_BLACK))
        ->setName(FONT_NAME)
    ;

    $chart1Shape = $slide->createChartShape()
        ->setWidth(400)
        ->setHeight(400)
        ->setOffsetX(50)
        ->setOffsetY(125)
    ;
    $chart1Shape->getTitle()->setText('Chart 1'); // @phpstan-ignore-line
    $chart1Shape->getPlotArea()->setType($pieChart1); // @phpstan-ignore-line
    $chart1Shape->getLegend()->setVisible(false); // @phpstan-ignore-line

    $chart2Shape = $slide->createChartShape()
        ->setWidth(400)
        ->setHeight(400)
        ->setOffsetX(500)
        ->setOffsetY(125)
    ;
    $chart2Shape->getTitle()->setText('Chart 2'); // @phpstan-ignore-line
    $chart2Shape->getPlotArea()->setType($pieChart2); // @phpstan-ignore-line
    $chart2Shape->getLegend()->setVisible(false); // @phpstan-ignore-line
}

///////////////////////////////////////

$writer = IOFactory::createWriter($presentation, 'PowerPoint2007');
$writer->save('issue-841.pptx');

This produces the following PPTX file: issue-841.pptx

As you can see, there are only two charts in the PPTX:

❯ zipinfo -l issue-841.pptx
Archive:  issue-841.pptx
Zip file size: 14374 bytes, number of entries: 23
-rw-rw-rw-  6.3 unx     2677 b-      473 defX 25-Jan-12 14:13 [Content_Types].xml
-rw-rw-rw-  6.3 unx     1064 b-      418 defX 25-Jan-12 14:13 docProps/app.xml
-rw-rw-rw-  6.3 unx      875 b-      399 defX 25-Jan-12 14:13 docProps/core.xml
-rw-rw-rw-  6.3 unx      230 b-      149 defX 25-Jan-12 14:13 docProps/custom.xml
-rw-rw-rw-  6.3 unx     5145 b-     1074 defX 25-Jan-12 14:13 ppt/charts/chart1.xml
-rw-rw-rw-  6.3 unx     5145 b-     1074 defX 25-Jan-12 14:13 ppt/charts/chart2.xml
-rw-rw-rw-  6.3 unx      736 b-      353 defX 25-Jan-12 14:13 ppt/presProps.xml
-rw-rw-rw-  6.3 unx     3728 b-      580 defX 25-Jan-12 14:13 ppt/presentation.xml
-rw-rw-rw-  6.3 unx      315 b-      184 defX 25-Jan-12 14:13 ppt/slideLayouts/_rels/slideLayout1.xml.rels
-rw-rw-rw-  6.3 unx      743 b-      318 defX 25-Jan-12 14:13 ppt/slideLayouts/slideLayout1.xml
-rw-rw-rw-  6.3 unx      453 b-      206 defX 25-Jan-12 14:13 ppt/slideMasters/_rels/slideMaster1.xml.rels
-rw-rw-rw-  6.3 unx     1907 b-      617 defX 25-Jan-12 14:13 ppt/slideMasters/slideMaster1.xml
-rw-rw-rw-  6.3 unx      315 b-      184 defX 25-Jan-12 14:13 ppt/slides/_rels/slide1.xml.rels
-rw-rw-rw-  6.3 unx     2249 b-      745 defX 25-Jan-12 14:13 ppt/slides/slide1.xml
-rw-rw-rw-  6.3 unx      593 b-      214 defX 25-Jan-12 14:13 ppt/slides/_rels/slide2.xml.rels
-rw-rw-rw-  6.3 unx     3564 b-      886 defX 25-Jan-12 14:13 ppt/slides/slide2.xml
-rw-rw-rw-  6.3 unx      593 b-      215 defX 25-Jan-12 14:13 ppt/slides/_rels/slide3.xml.rels
-rw-rw-rw-  6.3 unx     3564 b-      886 defX 25-Jan-12 14:13 ppt/slides/slide3.xml
-rw-rw-rw-  6.3 unx      182 b-      164 defX 25-Jan-12 14:13 ppt/tableStyles.xml
-rw-rw-rw-  6.3 unx    10040 b-     1551 defX 25-Jan-12 14:13 ppt/theme/theme1.xml
-rw-rw-rw-  6.3 unx      576 b-      267 defX 25-Jan-12 14:13 ppt/viewProps.xml
-rw-rw-rw-  6.3 unx      753 b-      251 defX 25-Jan-12 14:13 _rels/.rels
-rw-rw-rw-  6.3 unx     1267 b-      274 defX 25-Jan-12 14:13 ppt/_rels/presentation.xml.rels
23 files, 46714 bytes uncompressed, 11482 bytes compressed:  75.4%

Opening this in LibreOffice shows that both charts in the last slide are supposed to be displayed but do not show up (probably because ppt/charts/chart3.xml and ppt/charts/chart4.xml do not exist):

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants