Transparent background of images becomes black

 

Elgg 2.3.16 

In the past I have asked about this issue but have not received any answer. So, I found some workaround that works well for one test plugin (see the code below). 

My question is how to make this code work for the whole system - maybe by overriding some core code or a hook, etc. 

Thank you very much. 

------------------------------------------------

 

// The regular action script 

$uploaded_files = elgg_get_uploaded_files('upload'); 

if (!$uploaded_files) { 

   register_error("No file was uploaded"); 

   forward(REFERER); 

  

$uploaded_file = array_shift($uploaded_files); 

if (!$uploaded_file->isValid()) { 

   $error = elgg_get_friendly_upload_error($uploaded_file-     >getError()); 

   register_error($error); 

   forward(REFERER); 

  

$supported_mimes = [ 

   'image/jpeg', 

   'image/png', 

   'image/gif', 

]; 

  

$mime_type = ElggFile::detectMimeType($uploaded_file->getPathname(), $uploaded_file->getClientMimeType()); 

if (!in_array($mime_type, $supported_mimes)) { 

   register_error("$mime_type is not supported"); 

   forward(REFERER); 

  

//=================== 

bg_color ($uploaded_file);// My new function 

//=================== 

  

if ($uploaded_file) { 

   $entity->deleteIcon(); 

   $entity->saveIconFromUploadedFile('upload');  

  

--------------My addition ----------------------------------- 

  

function bg_color ($uploaded_file) { 

 

if (!$uploaded_file) { 

   return; 

 

$image = new Imagick(); 

$image->readimage($uploaded_file->getPathname()); 

$format = $image->getImageFormat(); 

if ($format == 'GIF') { 

   $image->setImageFormat('JPEG'); 

   $image->writeImage($uploaded_file->getPathname()); 

} elseif ($format == 'PNG') { 

   $hasTransparency = $image->getImageAlphaChannel(); 

   if($hasTransparency ) { 

      $image->setbackgroundcolor('#ffffff');// any color 

      $image->readimage($uploaded_file->getPathname()); 

      $image = $image->mergeImageLayers(Imagick::LAYERMETHOD_FLATTEN); 

      $image->writeImage($uploaded_file->getPathname()); 

    } 

  } 

 

  • Sorry - the text that is not so clear :(

  • Try use 'upload', 'file' hook.

    elgg_register_plugin_hook_handler('upload', 'file', function($hook, $type, $return, $params) {
        $uploaded_file = $params['upload'];
        return bg_color($uploaded_file);
    });

    Please test it bcz I've never used it.

    Tip: For clear the pasted code use 'Remove Format' button in the editor (the last button on the right)

  • Thank you Nikolai.

    It works well with File plugin and Embed which depends on File.

    But not with other plugins, e.g. blog_tools (it has icon upload), avatar images, and my plugins, etc.

    Only File plugin triggers the hook but not the rest (I checked with register_error that I added to the hook). 

    I tested also the hook entity:<icon_type>:prepare, <entity_type>. It is triggered by all the plugins but it does not bring an instance of Symfony’s UploadedFile which is needed in this case. it brings ElggFile.

    BTW I use the Imagick plugin which replace the default GD image handling.

    Any other idea ?

    Thank you very much.

  • Look at this: $params['upload'];

    It's a name of 'input/file' in the form.

    So for icons it will $params['avatar'];

    Or something else.

    Just check this param in the forms and create more hooks.

    Test it!

  • Sorry, but I do not understand.

    As I said, only the File plugin triggers the hook (upload, file) and it works fine.

    Other plugins do not trigger it, so I cannot check the $params['xxx'].

  • elgg_register_plugin_hook_handler
    ('upload', 'file', function($hook, $type, $return, $params) {
        $uploaded_file = $params['upload'];
        return bg_color($uploaded_file);
    });
    
    elgg_register_plugin_hook_handler
    ('upload', 'file', function($hook, $type, $return, $params) {
        $uploaded_file = $params['avatar'];
        return bg_color($uploaded_file);
    });
  • My bad.

    For icon triggers you should use these hooks:

    entity:<icon_type>:prepare, <entity_type>
    entity:<icon_type>:save, <entity_type>
    entity:<icon_type>:saved, <entity_type>

    More details in the Elgg docs.

    I've tested with entity:<icon_type>:save, <entity_type> hook :

    elgg_register_plugin_hook_handler($hook, $type, $return, $params) {
    
       if ($params['entity'] instanceof \ElggUser || $params['file'] instanceof \ElggFile) {
           return true;
       }
    
    });
    

    For objects:

    $params['entity'] instanceof \ElggEntity
  • Thank you Nikolai, I really appreciate your help and patience :)

    The problem with all the icon_type hooks is that they bring an instance of ElggFile. While I need an instance of Symfony’s UploadedFile (See examples below)

    The upload, file hook brings an instance of Symfony’s UploadedFile while I uploaded in File plugin. But it is not triggered by other plugin. Maybe because the File plugin saves the icon through $file->save() while e.g. blog_tools saves the icon through $blog->saveIconFromUploadedFile('icon');

    In the Docs of entity:<icon_type>:prepare, <entity_type> is written:

    The $return value passed to the hook is an instance of ElggFile that points to a temporary copy of the uploaded/linked file.

    If there is a way to get the address of the tmp file from the ElggFile than we have a solution.

    ----------------------------------------------------------------

    An instance of Symfony’s UploadedFile while I uploaded in File plugin:

    Symfony\Component\HttpFoundation\File\UploadedFile Object
    (
        [test:Symfony\Component\HttpFoundation\File\UploadedFile:private] => 
        [originalName:Symfony\Component\HttpFoundation\File\UploadedFile:private] => transparen-3t.gif
        [mimeType:Symfony\Component\HttpFoundation\File\UploadedFile:private] => image/gif
        [size:Symfony\Component\HttpFoundation\File\UploadedFile:private] => 1564
        [error:Symfony\Component\HttpFoundation\File\UploadedFile:private] => 0
        [pathName:SplFileInfo:private] => /tmp/phpN3v0e5
        [fileName:SplFileInfo:private] => phpN3v0e5
     
    -----------------------------------------------------------------------------------
    An instance of ElggFile while uploading from blog_tools plugin
    ElggFile Object
    (
        [filestore:ElggFile:private] => ElggDiskFilestore Object
            (
                [dir_root:ElggDiskFilestore:private] => /home/hiranyas/ramElggBook/
            )
     
        [handle:ElggFile:private] => 
        [url_override:protected] => 
        [temp_metadata:protected] => Array
            (
                [filename] => Array
                    (
                        [0] => tmp/16225762741f87b33136a7542325c55f031d1202dd.png
                    )
     
                [mimetype] => Array
                    (
                        [0] => image/png
                    )
     
                [simpletype] => Array
                    (
                        [0] => image
                    )
     
            )
     
        [temp_annotations:protected] => Array
            (
            )
     
        [temp_private_settings:protected] => Array
            (
            )
     
        [volatile:protected] => Array
            (
            )
     
        [orig_attributes:protected] => Array
            (
            )
     
        [attributes:protected] => Array
            (
                [time_created] => 
                [guid] => 
                [type] => object
                [subtype] => file
                [owner_guid] => 4021
                [container_guid] => 36
                [site_guid] => 
                [access_id] => 0
                [time_updated] => 
                [last_action] => 
                [enabled] => yes
                [title] => 
                [description] => 
            )
     
        [valid:protected] => 
        [time:ElggData:private] => 
    )
  • I don't know nothing about Blog tools but for user's avatars it's work like a charm.

    Just tested with this code snippet:

    elgg_register_plugin_hook_handler('entity:icon:save', 'user', function (\Elgg\Hook $hook) {
         $params = $hook->getParams();
    
         if ($params['entity'] instanceof \ElggUser && $params['file'] instanceof \ElggFile) {
            return true;
         }
    });
     
    As I said you can use 'object' instead of 'user' in the mentioned code to get your entity.
  • Thank you Nikolai.

    I'll  check it.