Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 6006701
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 23, 20262026-05-23T01:34:39+00:00 2026-05-23T01:34:39+00:00

I have a PHP image upload system which allows a user to upload various

  • 0

I have a PHP image upload system which allows a user to upload various images (JPG, GIF, PNG). Every image which is uploaded has an icon (20×20), thumbnail (150×150) and a postcard (500×500) generated for it–I call these “meta images”. If the original image dimensions are not square like the meta image, it is scaled to best fit and a transparent canvas is generated at the proper size with the meta image laid onto it. Because of this transparent canvasing, and for other purposes, all generated meta images are themselves PNGs (regardless of original image format).

For example, if a user uploads a 800px by 600px JPG image, the following ends up in the filesystem:

  1. Original *.jpg at 800 x 600
  2. Meta icon *.png with 20 x 15 copy of original image centered horizontally and vertically on 20 x 20 tansparent canvas
  3. Meta thumbail *.png with 150 x 112 copy of original image centered horizontally and vertically on 150 x 150 tansparent canvas
  4. Meta icon *.png with 500 x 375 copy of original image centered horizontally and vertically on 500 x 500 tansparent canvas

This works perfectly for JPG and GIF files–all colors are handled properly, sizes work, etc, etc, etc.

However, if I upload a PNG which has any black in it (rgb(0,0,0), #000000), the resulting 3 meta images have all black converted to transparent. Everything else is fine–dimensions, etc. And remember, transparent GIFs seem to work fine, even if there is black within.

Can someone please explain to me how I can fix this? Below is the code I wrote for this system (note there are 3 extensions of the abstract class defined beneath it):

<?php
/*
 * TODO: There is no reason for this class to be abstract except that I have not
 *       added any of the setters/getters/etc which would make it useful on its
 *       own.  As is, an instantiation of this class would not accomplish
 *       anything so I have made it abstract to avoid instantiation.  Three
 *       simple and usable extensions of this class exist below it in this file.
 */
abstract class ObjectImageRenderer
{
  const WRITE_DIR = SITE_UPLOAD_LOCATION;

  protected $iTargetWidth = 0;
  protected $iTargetHeight = 0;
  protected $iSourceWidth = 0;
  protected $iSourceHeight = 0;
  protected $iCalculatedWidth = 0;
  protected $iCalculatedHeight = 0;

  protected $sSourceLocation = '';
  protected $sSourceExt = '';
  protected $oSourceImage = null;

  protected $sTargetLocation = '';
  protected $sTargetNamePrefix = '';
  protected $oTargetImage = null;

  protected $oTransparentCanvas = null;

  protected $bNeedsCanvas = false;
  protected $bIsRendered = false;

  public function __construct( $sSourceLocation )
  {
    if( ! is_string( $sSourceLocation ) || $sSourceLocation === '' ||
        ! is_file( $sSourceLocation ) || ! is_readable( $sSourceLocation )
      )
    {
      throw new Exception( __CLASS__ . ' must be instantiated with valid path/filename of source image as first param.' );
    }
    $this->sSourceLocation = $sSourceLocation;
    $this->resolveNames();
  }

  public static function factory( $sSourceLocation, $size )
  {
    switch( $size )
    {
      case 'icon':
        return new ObjectIconRenderer( $sSourceLocation );
        break;

      case 'thumbnail':
        return new ObjectThumbnailRenderer( $sSourceLocation );
        break;

      case 'postcard':
        return new ObjectPostcardRenderer( $sSourceLocation );
        break;
    }
  }

  public static function batchRender( $Source )
  {
    if( is_string( $Source ) )
    {
      try
      {
        ObjectImageRenderer::factory( $Source, 'icon' )->render();
        ObjectImageRenderer::factory( $Source, 'thumbnail' )->render();
        ObjectImageRenderer::factory( $Source, 'postcard' )->render();
      }
      catch( Exception $exc )
      {
        LogProcessor::submit( 500, $exc->getMessage() );
      }
    }
    else if( is_array( $Source ) && count( $Source ) > 0 )
    {
      foreach( $Source as $sSourceLocation )
      {
        if( is_string( $sSourceLocation ) )
        {
          self::batchRender( $sSourceLocation );
        }
      }
    }
  }

  /**
   * loadImageGD - read image from filesystem into GD based image resource
   *
   * @access public
   * @static
   * @param STRING $sImageFilePath
   * @param STRING $sSourceExt OPTIONAL
   * @return RESOURCE
   */
  public static function loadImageGD( $sImageFilePath, $sSourceExt = null )
  {
    $oSourceImage = null;

    if( is_string( $sImageFilePath ) && $sImageFilePath !== '' &&
        is_file( $sImageFilePath ) && is_readable( $sImageFilePath )
      )
    {
      if( $sSourceExt === null )
      {
        $aPathInfo = pathinfo( $sImageFilePath );
        $sSourceExt = strtolower( (string) $aPathInfo['extension'] );
      }

      switch( $sSourceExt )
      {
        case 'jpg':
        case 'jpeg':
        case 'pjpeg':
          $oSourceImage = imagecreatefromjpeg( $sImageFilePath );
          break;

        case 'gif':
          $oSourceImage = imagecreatefromgif( $sImageFilePath );
          break;

        case 'png':
        case 'x-png':
          $oSourceImage = imagecreatefrompng( $sImageFilePath );
          break;

        default:
          break;
      }
    }

    return $oSourceImage;
  }

  protected function resolveNames()
  {
    $aPathInfo = pathinfo( $this->sSourceLocation );
    $this->sSourceExt = strtolower( (string) $aPathInfo['extension'] );
    $this->sTargetLocation = self::WRITE_DIR . $this->sTargetNamePrefix . $aPathInfo['basename'] . '.png';
  }

  protected function readSourceFileInfo()
  {
    $this->oSourceImage = self::loadImageGD( $this->sSourceLocation, $this->sSourceExt );

    if( ! is_resource( $this->oSourceImage ) )
    {
      throw new Exception( __METHOD__ . ': image read failed for ' . $this->sSourceLocation );
    }

    $this->iSourceWidth = imagesx( $this->oSourceImage );
    $this->iSourceHeight = imagesy( $this->oSourceImage );

    return $this;
  }

  protected function calculateNewDimensions()
  {
    if( $this->iSourceWidth === 0 || $this->iSourceHeight === 0 )
    {
      throw new Exception( __METHOD__ . ': source height or width is 0. Has ' . __CLASS__ . '::readSourceFileInfo() been called?' );
    }

    if( $this->iSourceWidth > $this->iTargetWidth || $this->iSourceHeight > $this->iTargetHeight )
    {
      $nDimensionRatio = ( $this->iSourceWidth / $this->iSourceHeight );

      if( $nDimensionRatio > 1 )
      {
        $this->iCalculatedWidth = $this->iTargetWidth;
        $this->iCalculatedHeight = (int) round( $this->iTargetWidth / $nDimensionRatio );
      }
      else
      {
        $this->iCalculatedWidth =  (int) round( $this->iTargetHeight * $nDimensionRatio );
        $this->iCalculatedHeight = $this->iTargetHeight;
      }
    }
    else
    {
      $this->iCalculatedWidth = $this->iSourceWidth;
      $this->iCalculatedHeight = $this->iSourceHeight;
    }

    if( $this->iCalculatedWidth < $this->iTargetWidth || $this->iCalculatedHeight < $this->iTargetHeight )
    {
      $this->bNeedsCanvas = true;
    }

    return $this;
  }

  protected function createTarget()
  {
    if( $this->iCalculatedWidth === 0 || $this->iCalculatedHeight === 0 )
    {
      throw new Exception( __METHOD__ . ': calculated height or width is 0. Has ' . __CLASS__ . '::calculateNewDimensions() been called?' );
    }

    $this->oTargetImage = imagecreatetruecolor( $this->iCalculatedWidth, $this->iCalculatedHeight );

    $aTransparentTypes = Array( 'gif', 'png', 'x-png' );
    if( in_array( $this->sSourceExt, $aTransparentTypes ) )
    {
      $oTransparentColor = imagecolorallocate( $this->oTargetImage, 0, 0, 0 );
      imagecolortransparent( $this->oTargetImage, $oTransparentColor);
      imagealphablending( $this->oTargetImage, false );
    }

    return $this;
  }

  protected function fitToMaxDimensions()
  {
    $iTargetX = (int) round( ( $this->iTargetWidth - $this->iCalculatedWidth ) / 2 );
    $iTargetY = (int) round( ( $this->iTargetHeight - $this->iCalculatedHeight ) / 2 );

    $this->oTransparentCanvas = imagecreatetruecolor( $this->iTargetWidth, $this->iTargetHeight );
    imagealphablending( $this->oTransparentCanvas, false );
    imagesavealpha( $this->oTransparentCanvas, true );
    $oTransparentColor = imagecolorallocatealpha( $this->oTransparentCanvas, 0, 0, 0, 127 );
    imagefill($this->oTransparentCanvas, 0, 0, $oTransparentColor );

    $bReturnValue = imagecopyresampled( $this->oTransparentCanvas, $this->oTargetImage, $iTargetX, $iTargetY, 0, 0, $this->iCalculatedWidth, $this->iCalculatedHeight, $this->iCalculatedWidth, $this->iCalculatedHeight );

    $this->oTargetImage = $this->oTransparentCanvas;

    return $bReturnValue;
  }

  public function render()
  {
    /*
     * TODO: If this base class is ever made instantiable, some re-working is
     *       needed such that the developer harnessing it can choose whether to
     *       write to the filesystem on render, he can ask for the
     *       image resources, determine whether cleanup needs to happen, etc.
     */
    $this
      ->readSourceFileInfo()
      ->calculateNewDimensions()
      ->createTarget();

    $this->bIsRendered = imagecopyresampled( $this->oTargetImage, $this->oSourceImage, 0, 0, 0, 0, $this->iCalculatedWidth, $this->iCalculatedHeight, $this->iSourceWidth, $this->iSourceHeight );

    if( $this->bIsRendered && $this->bNeedsCanvas )
    {
      $this->bIsRendered = $this->fitToMaxDimensions();
    }

    if( $this->bIsRendered )
    {
      imagepng( $this->oTargetImage, $this->sTargetLocation );
      @chmod( $this->sTargetLocation, 0644 );
    }

    if( ! $this->bIsRendered )
    {
      throw new Exception( __METHOD__ . ': failed to copy image' );
    }

    $this->cleanUp();
  }

  public function cleanUp()
  {
    if( is_resource( $this->oSourceImage ) )
    {
      imagedestroy( $this->oSourceImage );
    }

    if( is_resource( $this->oTargetImage ) )
    {
      imagedestroy( $this->oTargetImage );
    }

    if( is_resource( $this->oTransparentCanvas ) )
    {
      imagedestroy( $this->oTransparentCanvas );
    }
  }
}




class ObjectIconRenderer extends ObjectImageRenderer
{
  public function __construct( $sSourceLocation )
  {
    /* These Height/Width values are also coded in
     * src/php/reference/display/IconUploadHandler.inc
     * so if you edit them here, do it there too
     */
    $this->iTargetWidth = 20;
    $this->iTargetHeight = 20;
    $this->sTargetNamePrefix = 'icon_';

    parent::__construct( $sSourceLocation );
  }
}

class ObjectThumbnailRenderer extends ObjectImageRenderer
{
  public function __construct( $sSourceLocation )
  {
    /* These Height/Width values are also coded in
     * src/php/reference/display/IconUploadHandler.inc
     * so if you edit them here, do it there too
     */
    $this->iTargetWidth = 150;
    $this->iTargetHeight = 150;
    $this->sTargetNamePrefix = 'thumbnail_';

    parent::__construct( $sSourceLocation );
  }
}

class ObjectPostcardRenderer extends ObjectImageRenderer
{
  public function __construct( $sSourceLocation )
  {
    /* These Height/Width values are also coded in
     * src/php/reference/display/IconUploadHandler.inc
     * so if you edit them here, do it there too
     */
    $this->iTargetWidth = 500;
    $this->iTargetHeight = 500;
    $this->sTargetNamePrefix = 'postcard_';

    parent::__construct( $sSourceLocation );
  }
}

The code I use to run it is:

<?php
ObjectImageRenderer::batchRender( $sSourceFile );

The main issues seem to be in the createTarget() and fitToMaxDimensions() methods. In createTarget(), if I comment out the following lines:

$aTransparentTypes = Array( 'gif', 'png', 'x-png' );
if( in_array( $this->sSourceExt, $aTransparentTypes ) )
{
  $oTransparentColor = imagecolorallocate( $this->oTargetImage, 0, 0, 0 );
  imagecolortransparent( $this->oTargetImage, $oTransparentColor);
  imagealphablending( $this->oTargetImage, false );
}

I no longer lose my black, but all existing transparency becomes black.

I assume the issue is that I am using black as the transparency channel. But how do I avoid using a color which is in the image as the transparency channel?

Thanks to anyone who can help me understand the mysteries behind transparency!

Jim

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-23T01:34:40+00:00Added an answer on May 23, 2026 at 1:34 am

    You’re explictly specifying that 0,0,0 is transparent:

    $oTransparentColor = imagecolorallocatealpha( $this->oTransparentCanvas, 0, 0, 0, 127 );
    

    This will apply to ANY pixel in the image where the color triplet is 0,0,0 – in other words, all blacks, as you’re finding.

    If you want the original images to come through, you’d convert to using an alpha channel. It’d be a seperate “layer” in the image that exclusively specifies transparency/opaqueness for each pixel. That or scan the images for a color that’s not used in the original, and then specify that as the new transparent value instead of defaulting to 0,0,0.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have an upload system based on SWFUpload which calls PHP script. The problem
I have a PHP class that creates a PNG image on the fly and
I have a PHP script that can encode a PNG image to a Base64
If I have a button like the one in this image : http://www.freeimagehosting.net/image.php?4cd775814c.png how
I am looking for a really simple PHP image gallery system that allows file
I am making a PHP image uploader using the Zend Framework which will upload
I have a php system that uploads images and suffixes their files names with
I have an image upload form in my webpage and scripts(pointing to handleImage.php) so
I have been using a php sql system to manage images on my website.
I have a PHP script that initialises an image gallery. It loops through all

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.