PHPPresentation icon indicating copy to clipboard operation
PHPPresentation copied to clipboard

Adding an Image to a Slide corrupts generated PowerPoint file

Open dillanjwilding opened this issue 3 years ago • 3 comments

This is the code I've pieced together between the documentation, examples, and searching for solutions on github and stackoverflow to try to add an image to a slide:

$powerPoint = new PhpPresentation();

$masterSlide = $powerPoint->getAllMasterSlides()[0];
$slideLayout = $masterSlide->getAllSlideLayouts()[0];

$currentSlide = $powerPoint->getActiveSlide();
$currentSlide->setSlideLayout($slideLayout);

// using chromium to get base64 image stored in $image. confirmed this is correct.

$shape = (new Base64())->setData($image)->setHeight(500)->setWidth(500)->setOffsetX(50)->setOffsetY(50);
$currentSlide->addShape($shape);
// I also tried saving the image and inserting it that way
//$shape = $currentSlide->createDrawingShape('/path/to/my-image.png')->setHeight(500)->setWidth(500)->setOffsetX(50)->setOffsetY(50);

header('Content-Type: application/vnd.openxmlformats-officedocument.presentationml.presentation');
header('Content-Disposition: attachment; filename="test.pptx"');
header('Cache-Control: max-age=0');

$writer = IOFactory::createWriter($powerPoint, 'PowerPoint2007');
$writer->save('php://output');

When the file downloads and I click on it, I get this message: Screen Shot 2021-07-21 at 9 29 31 AM

When I click "Repair", I get this message: Screen Shot 2021-07-21 at 9 45 59 AM

I'm using phpoffice/phppresentation dev-master with Microsoft PowerPoint for Mac Version 16.50.

dillanjwilding avatar Jul 21 '21 14:07 dillanjwilding

Using jpeg looks like it doesn't corrupt the PowerPoint file but the image is still not visible. So the corrupt file may have something to do with png images. I'd prefer to use png but wouldn't mind using jpeg.

dillanjwilding avatar Jul 21 '21 18:07 dillanjwilding

Try this...

$presentation = new PhpPresentation();

$presentation->getLayout()->setDocumentLayout(DocumentLayout::LAYOUT_A4, true);

// $slide = $presentation->createSlide();
$slide = $presentation->getSlide(0);    // work with first slide of presentation

$file = './resources/presentation/left-side.png';  // relative path to the image
        
$shape = $slide->createDrawingShape();
$shape
    ->setPath($file)
    ->setOffsetX(Units::convert($x))
    ->setOffsetY(Units::convert($y));

Method Units::convert($mm) convert millimeters to pixels. ..class Units below

class Units
{
    const UNIT_EMU = 'emu';
    const UNIT_CENTIMETER = 'cm';
    const UNIT_INCH = 'in';
    const UNIT_MILLIMETER = 'mm';
    const UNIT_PIXEL = 'px';
    const UNIT_POINT = 'pt';


    /**
     * Convert specified value from one to another units
     *
     * @param mixed  $value     value at fromUnit units
     * @param string $fromUnit units of value (from units)
     * @param string $toUnit   result units (to units)
     *
     * @return mixed value value at toUnit units
     */
    public static function convert(
        $value,
        $fromUnit = self::UNIT_MILLIMETER,
        $toUnit = self::UNIT_PIXEL
    ) {
        if ($fromUnit === $toUnit) {
            return $value;
        }

        // Convert from $fromUnit to EMU
        switch ($fromUnit) {
        case self::UNIT_MILLIMETER:
            $value *= 36000;
            break;
        case self::UNIT_CENTIMETER:
            $value *= 360000;
            break;
        case self::UNIT_INCH:
            $value *= 914400;
            break;
        case self::UNIT_PIXEL:
            $value = Drawing::pixelsToEmu($value);
            break;
        case self::UNIT_POINT:
            $value *= 12700;
            break;
        case self::UNIT_EMU:
        default:
            // no changes
        }

        // Convert from EMU to $toUnit
        switch ($toUnit) {
        case self::UNIT_MILLIMETER:
            $value /= 36000;
            break;
        case self::UNIT_CENTIMETER:
            $value /= 360000;
            break;
        case self::UNIT_INCH:
            $value /= 914400;
            break;
        case self::UNIT_PIXEL:
            $value = Drawing::emuToPixels($value);
            break;
        case self::UNIT_POINT:
            $value /= 12700;
            break;
        case self::UNIT_EMU:
        default:
            // no changes
        }
        return $value;
    }
}

pal-software avatar Aug 25 '21 05:08 pal-software

I wrote this method which add image to specified slide:

    /**
     * Add image to slide (from file)
     *
     * @param Slide  $slide  Slide
     * @param string $file   Image file name
     * @param mixed  $x      Image x-position
     * @param mixed  $y      Image y-position
     * @param mixed  $width  Image width
     * @param mixed  $height Image height
     *
     * @return \PhpOffice\PhpPresentation\Shape\Drawing\File Image shape
     */
    public function image(
        Slide $slide,
        string $file,
        $x,
        $y,
        $width = null,
        $height = null
    ) : \PhpOffice\PhpPresentation\Shape\Drawing\File {
        $shape = $slide->createDrawingShape();
        $shape
            ->setPath($file)
            ->setOffsetX(Units::convert($x))
            ->setOffsetY(Units::convert($y));

        $uWidth = null;
        $uHeight = null;

        if ($width !== null) {
            $uWidth = Units::convert($width);
            $shape->setWidth($uWidth);
        }
        if ($height !== null) {
            $uHeight = Units::convert($height);
            $shape->setHeight($uHeight);
        }

        if ($shape->getWidth() > $uWidth) {
            $shape->setWidth($uWidth);
        }
        return $shape;
    }

Usage example:

        $file = './resources/presentation/left-side.png';
        $this->image($slide, $file, 10, 0, 70, 210);

pal-software avatar Aug 25 '21 05:08 pal-software