1

tldr: How do I render a TypoScript COA Object with a GIFBUILDER image from inside a CommandController?

I'm currently developing an eCommerce platform for which I need to periodically import an excel file that holds the product catalog. After a product is created from a row of data in the excel file, a directory is searched for product images related to that item, and they are linked as FileReferences to the product. I've written an ImportCommandController that takes care of that.

This all works like a charm, with the only glaring problem being the performance of the image manipulation. The first call to a product list pages takes a good 30 seconds, the first request of a single view. I periodically need to recreate the whole catalog from scratch, and the source product images are huge files, I have no influence on that.

The product images of that catalog are being generated by a TypoScript that takes care of fitting these images inside a square white background, returning the IMG_RESOURCE url. I call that TypoScript from inside a Fluid template with the cObject ViewHelper.

I've been trying to call this bit of TypoScript from the ImportCommandController->importAction, so that the import cronjob would take care of creating these scaled images beforehand, with the same filename hash, so they're already processed when they're called by the single view. But I can't manage to do that.

The TypoScript in question ist this:

plugin.tx_productfinder_products {
    // Productfinder-Produktbilder
    // Bilder quadratisch auf weissen Hintergrund einpassen
    productimage = COA
    productimage {
        // Daten der FileReference im Regsiter ablegen
        10 = FILES
        10 {
            references.data = current
            renderObj = COA
            renderObj {
                10 = LOAD_REGISTER
                10 {
                    param = TEXT
                    param.data = file:current.uid
                }
            }
        }
        20 = IMG_RESOURCE
        20 {
            file = GIFBUILDER
            file {
                XY = 960,960
                format = jpg
                quality = 95
                backColor = #ffffff
                20 = IMAGE
                20 {
                    offset = 960-[20.w]/2,960-[20.h]/2
                    file {
                        import.data = current
                        treatIdAsReference = 1
                        maxW = 960
                        maxH = 960
                    }
                }
    //          // Text aus Daten der FileReference als Wasserzeichen ins Bild rendern
    //          30 = TEXT
    //          30 {
    //              //text.data = register:param
    //              text.data = current
    //              fontColor= #dddddd
    //              fontSize = 12
    //              offset = 20,[20.h]-20
    //              align = left
    //              antiAlias = 1
    //          }
            }
        }
    }
}

And I call these from inside the Fluid template like so:

<img class="img-responsive" src="{f:cObject(typoscriptObjectPath:'plugin.tx_productfinder_products.productpreviewimage', data:'{image.uid}')}">



What have I tried so far? Pretty much everything.

I've first tried to call the ContentObjectRenderer directly,

/** @var \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer $cObj */
$contentObject = GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\ContentObject\\ContentObjectRenderer');
$contentObject->setCurrentVal($image->getUid());
$content = $contentObject->cObjGetSingle($this->settings['productimagetest'], $this->settings['productimagetest.']);

resulting in these weird errors.

Oops, an error occurred: PHP Warning: imagejpeg(typo3temp/GB/csm_8000424600_cbbd127be3_9cb1d3c8cc.jpg): failed to open stream: No such file or directory in /html/typo3/typo3_src-7.6.16/typo3/sysext/core/Classes/Imaging/GraphicalFunctions.php line 2912

It seems that the TYPO3 Configuration regarding the Grapics Processing isn't initialized in the same way as it is for the Frontend.

Next, I tried instanciate a StandaloneFluidView to render the whole SingleItem template per item, but I cant figure that out because the Request and Context are missing and so the partials being referenced in the template aren't being rendered.

Then I tired to just create the FrontendUrls per single item and request them from the CommandController,

/** @var \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer $cObj */
$contentObject = GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\ContentObject\\ContentObjectRenderer');

$test = $contentObject->typolink_URL(array(
    'parameter' => 671,
    'additionalParams' => 
        '&tx_productfinder_products[product]='.$product->getUid().
        '&tx_productfinder_products[action]=show'.
        '&tx_productfinder_products[controller]=Product',
    'returnLast' => 'url'
));
$this->outputLine(print_r($test,true));

but the URLs generated in this way are missing the cHash.

Can anybody offer help or a different approach to this?

2
  • I currently do not have time to fletch it out, but did you try using your FileReference object to do something like this? $fileReference->getOriginalFile()->process('Image', [ 'width' => 960, 'height' => 960, 'offset' => '960-[20.w]/2,960-[20.h]/2' ]); I don't know about the offset part, but this should work without frontend context. Have a look into typo3/sysext/core/Resource/Processing Commented Oct 5, 2017 at 8:03
  • The problem with that is, that I don't know how to apply the rest of the GIFBBUILDER configuration. The images need to get fit into a white sqare regardless of aspect ratio of the source image. So, rendering the images differently than the TypoScript will result in a different process hash. Thanks for the approach, though, I'll fiddle arround with that. Commented Oct 5, 2017 at 8:26

2 Answers 2

1

Since these images are generated just once for the frontend output and are then available anyway, I don't see the advantage of generating them beforehand. The white square could be easily generated with CSS, so to me this does not even look like a use case for the GIFBUILDER.

That being said there's still something you could do: Since you are in the PHP context already, why don't you instanciate the GIFBUILDER directly or use even pure IM/GM commands instead of going for an IMG_RESOURCE which is actually meant to be output in the frontend?

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for the input, I mostly agree, but, "I don't see the advantage of generating them beforehand" - there will be a lot of fluctuation in the image folder, and the performance right now is catastrophic. I'm fine with other approaches for caching, but none worked. "this does not even look like a use case for the GIFBUILDER" - the images will later have to include a watermark, thats the main reason for GIFBUILDER. "Since you are in the PHP context already, why don't you instanciate the GIFBUILDER" - can you elaborate on that? As I said, image processing seems borked in CommandControllers.
I found another Question regarding the TYPO3\CMS\Frontend\Imaging\GifBuilder . Looks somewhat promising. I'll try to implement asap.
You might want to take a look at \TYPO3\CMS\Core\Resource\OnlineMedia\Processing\PreviewProcessing which is instatiating GifBuilder without using TypoScript IMG_RESOURCE and is implemented via a signal slot in core/ext_localconf.php - there you will find a method like \TYPO3\CMS\Core\Resource\OnlineMedia\Processing\PreviewProcessing::cropScaleImage
0

I know this is an old question, but I had the same issue and had to invest some time to debug it, so maybe this this answer is useful for someone else in the future.

The CLI uses a different working directory than the frontend, therefore the relative path to typo3temp/ directory used in the GifBuilder class cannot be resolved, which results in the above mentioned warning.

To fix the relative path resolution, you have to change your working directory to the frontend one, this can be achieved by:

class AcmeCommand extends Command
{
    protected static $cwdBackup;

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        if (Environment::isCli()) {
            static::$cwdBackup = getcwd();
            chdir(Environment::getPublicPath());
        }

        //

        if (Environment::isCli()) {
            chdir(static::$cwdBackup);
        }
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.