[Linpha-cvs] SF.net SVN: linpha: [4736] trunk/linpha2
Status: Inactive
Brought to you by:
bzrudi
From: <bz...@us...> - 2007-07-10 09:43:47
|
Revision: 4736 http://svn.sourceforge.net/linpha/?rev=4736&view=rev Author: bzrudi Date: 2007-07-10 02:43:45 -0700 (Tue, 10 Jul 2007) Log Message: ----------- minor exiftool changes and EOL M$ to Unix conversion Modified Paths: -------------- trunk/linpha2/docs/dev/external_libraries.txt trunk/linpha2/lib/classes/linpha.exiftool.class.php trunk/linpha2/lib/classes/pjmt/JPEG.php trunk/linpha2/templates/default/fragments.php Modified: trunk/linpha2/docs/dev/external_libraries.txt =================================================================== --- trunk/linpha2/docs/dev/external_libraries.txt 2007-07-06 18:31:05 UTC (rev 4735) +++ trunk/linpha2/docs/dev/external_libraries.txt 2007-07-10 09:43:45 UTC (rev 4736) @@ -23,6 +23,9 @@ CHANGES ------- + JPEG.php + line 94 removed "This probably is not a JPEG file" echo. we take care + of it ourself during import. EXIF.php - changed '<?' to '<?php' Modified: trunk/linpha2/lib/classes/linpha.exiftool.class.php =================================================================== --- trunk/linpha2/lib/classes/linpha.exiftool.class.php 2007-07-06 18:31:05 UTC (rev 4735) +++ trunk/linpha2/lib/classes/linpha.exiftool.class.php 2007-07-10 09:43:45 UTC (rev 4736) @@ -120,8 +120,8 @@ "-s " . // Print tag names instead of descr. "-t " . // Use tab \t as delimiter "-fast " . // Do not read to EOF - "-n " . // Read numbers instead of words - "-m "; //Ignore minor errors + //"-n " . // Read numbers instead of words + "-m "; // Ignore minor errors LinFilesys::linExec($this->exiftool.' '.$parameters.' "'.$filename.'"', $meta, $return); @@ -206,9 +206,9 @@ $return = ""; $meta = ""; $filename = "".$dirname."/".$filename.""; - $parameters = "-exif:datetimeoriginal " . // Get date tag - "-exif:orientation " . // Get orientation tag - "-s -n -t"; // Print tag name tab seper. + $parameters = "-exif:datetimeoriginal " . // Get date tag + "-exif:orientation " . // Get orientation tag + "-s -n -t "; // Print tag name tab seper. LinFilesys::linExec($this->exiftool.' '.$parameters.' "'.$filename.'"', $meta, $return); Modified: trunk/linpha2/lib/classes/pjmt/JPEG.php =================================================================== --- trunk/linpha2/lib/classes/pjmt/JPEG.php 2007-07-06 18:31:05 UTC (rev 4735) +++ trunk/linpha2/lib/classes/pjmt/JPEG.php 2007-07-10 09:43:45 UTC (rev 4736) @@ -1,973 +1,973 @@ -<?php - -/****************************************************************************** -* -* Filename: JPEG.php -* -* Description: Provides functions for reading and writing information to/from -* JPEG format files -* -* Author: Evan Hunter -* -* Date: 23/7/2004 -* -* Project: PHP JPEG Metadata Toolkit -* -* Revision: 1.10 -* -* Changes: 1.00 -> 1.10 : changed put_jpeg_header_data to check if the data -* being written exists -* -* URL: http://electronics.ozhiker.com -* -* Copyright: Copyright Evan Hunter 2004 -* -* License: This file is part of the PHP JPEG Metadata Toolkit. -* -* The PHP JPEG Metadata Toolkit is free software; you can -* redistribute it and/or modify it under the terms of the -* GNU General Public License as published by the Free Software -* Foundation; either version 2 of the License, or (at your -* option) any later version. -* -* The PHP JPEG Metadata Toolkit is distributed in the hope -* that it will be useful, but WITHOUT ANY WARRANTY; without -* even the implied warranty of MERCHANTABILITY or FITNESS -* FOR A PARTICULAR PURPOSE. See the GNU General Public License -* for more details. -* -* You should have received a copy of the GNU General Public -* License along with the PHP JPEG Metadata Toolkit; if not, -* write to the Free Software Foundation, Inc., 59 Temple -* Place, Suite 330, Boston, MA 02111-1307 USA -* -* If you require a different license for commercial or other -* purposes, please contact the author: ev...@oz... -* -******************************************************************************/ - - - - -/****************************************************************************** -* -* Function: get_jpeg_header_data -* -* Description: Reads all the JPEG header segments from an JPEG image file into an -* array -* -* Parameters: filename - the filename of the file to JPEG file to read -* -* Returns: headerdata - Array of JPEG header segments -* FALSE - if headers could not be read -* -******************************************************************************/ - -function get_jpeg_header_data( $filename ) -{ - - // prevent refresh from aborting file operations and hosing file - ignore_user_abort(true); - - - // Attempt to open the jpeg file - the at symbol supresses the error message about - // not being able to open files. The file_exists would have been used, but it - // does not work with files fetched over http or ftp. - $filehnd = @fopen($filename, 'rb'); - - // Check if the file opened successfully - if ( ! $filehnd ) - { - // Could't open the file - exit - echo "<p>Could not open file $filename</p>\n"; - return FALSE; - } - - - // Read the first two characters - $data = network_safe_fread( $filehnd, 2 ); - - // Check that the first two characters are 0xFF 0xDA (SOI - Start of image) - if ( $data != "\xFF\xD8" ) - { - // No SOI (FF D8) at start of file - This probably isn't a JPEG file - close file and return; - echo "<p>This probably is not a JPEG file</p>\n"; - fclose($filehnd); - return FALSE; - } - - - // Read the third character - $data = network_safe_fread( $filehnd, 2 ); - - // Check that the third character is 0xFF (Start of first segment header) - if ( $data{0} != "\xFF" ) - { - // NO FF found - close file and return - JPEG is probably corrupted - fclose($filehnd); - return FALSE; - } - - // Flag that we havent yet hit the compressed image data - $hit_compressed_image_data = FALSE; - - - // Cycle through the file until, one of: 1) an EOI (End of image) marker is hit, - // 2) we have hit the compressed image data (no more headers are allowed after data) - // 3) or end of file is hit - - while ( ( $data{1} != "\xD9" ) && (! $hit_compressed_image_data) && ( ! feof( $filehnd ) )) - { - // Found a segment to look at. - // Check that the segment marker is not a Restart marker - restart markers don't have size or data after them - if ( ( ord($data{1}) < 0xD0 ) || ( ord($data{1}) > 0xD7 ) ) - { - // Segment isn't a Restart marker - // Read the next two bytes (size) - $sizestr = network_safe_fread( $filehnd, 2 ); - - // convert the size bytes to an integer - $decodedsize = unpack ("nsize", $sizestr); - - // Save the start position of the data - $segdatastart = ftell( $filehnd ); - - // Read the segment data with length indicated by the previously read size - $segdata = network_safe_fread( $filehnd, $decodedsize['size'] - 2 ); - - - // Store the segment information in the output array - $headerdata[] = array( "SegType" => ord($data{1}), - "SegName" => $GLOBALS[ "JPEG_Segment_Names" ][ ord($data{1}) ], - "SegDesc" => $GLOBALS[ "JPEG_Segment_Descriptions" ][ ord($data{1}) ], - "SegDataStart" => $segdatastart, - "SegData" => $segdata ); - } - - // If this is a SOS (Start Of Scan) segment, then there is no more header data - the compressed image data follows - if ( $data{1} == "\xDA" ) - { - // Flag that we have hit the compressed image data - exit loop as no more headers available. - $hit_compressed_image_data = TRUE; - } - else - { - // Not an SOS - Read the next two bytes - should be the segment marker for the next segment - $data = network_safe_fread( $filehnd, 2 ); - - // Check that the first byte of the two is 0xFF as it should be for a marker - if ( $data{0} != "\xFF" ) - { - // NO FF found - close file and return - JPEG is probably corrupted - fclose($filehnd); - return FALSE; - } - } - } - - // Close File - fclose($filehnd); - // Alow the user to abort from now on - ignore_user_abort(false); - - // Return the header data retrieved - return $headerdata; -} - - -/****************************************************************************** -* End of Function: get_jpeg_header_data -******************************************************************************/ - - - - -/****************************************************************************** -* -* Function: put_jpeg_header_data -* -* Description: Writes JPEG header data into a JPEG file. Takes an array in the -* same format as from get_jpeg_header_data, and combines it with -* the image data of an existing JPEG file, to create a new JPEG file -* WARNING: As this function will replace all JPEG headers, -* including SOF etc, it is best to read the jpeg headers -* from a file, alter them, then put them back on the same -* file. If a SOF segment wer to be transfered from one -* file to another, the image could become unreadable unless -* the images were idenical size and configuration -* -* -* Parameters: old_filename - the JPEG file from which the image data will be retrieved -* new_filename - the name of the new JPEG to create (can be same as old_filename) -* jpeg_header_data - a JPEG header data array in the same format -* as from get_jpeg_header_data -* -* Returns: TRUE - on Success -* FALSE - on Failure -* -******************************************************************************/ - -function put_jpeg_header_data( $old_filename, $new_filename, $jpeg_header_data ) -{ - - // Change: added check to ensure data exists, as of revision 1.10 - // Check if the data to be written exists - if ( $jpeg_header_data == FALSE ) - { - // Data to be written not valid - abort - return FALSE; - } - - // extract the compressed image data from the old file - $compressed_image_data = get_jpeg_image_data( $old_filename ); - - // Check if the extraction worked - if ( ( $compressed_image_data === FALSE ) || ( $compressed_image_data === NULL ) ) - { - // Couldn't get image data from old file - return FALSE; - } - - - // Cycle through new headers - foreach ($jpeg_header_data as $segno => $segment) - { - // Check that this header is smaller than the maximum size - if ( strlen($segment['SegData']) > 0xfffd ) - { - // Could't open the file - exit - echo "<p>A Header is too large to fit in JPEG segment</p>\n"; - return FALSE; - } - } - - ignore_user_abort(true); ## prevent refresh from aborting file operations and hosing file - - - // Attempt to open the new jpeg file - $newfilehnd = @fopen($new_filename, 'wb'); - // Check if the file opened successfully - if ( ! $newfilehnd ) - { - // Could't open the file - exit - echo "<p>Could not open file $new_filename</p>\n"; - return FALSE; - } - - // Write SOI - fwrite( $newfilehnd, "\xFF\xD8" ); - - // Cycle through new headers, writing them to the new file - foreach ($jpeg_header_data as $segno => $segment) - { - - // Write segment marker - fwrite( $newfilehnd, sprintf( "\xFF%c", $segment['SegType'] ) ); - - // Write segment size - fwrite( $newfilehnd, pack( "n", strlen($segment['SegData']) + 2 ) ); - - // Write segment data - fwrite( $newfilehnd, $segment['SegData'] ); - } - - // Write the compressed image data - fwrite( $newfilehnd, $compressed_image_data ); - - // Write EOI - fwrite( $newfilehnd, "\xFF\xD9" ); - - // Close File - fclose($newfilehnd); - - // Alow the user to abort from now on - ignore_user_abort(false); - - - return TRUE; - -} - -/****************************************************************************** -* End of Function: put_jpeg_header_data -******************************************************************************/ - - - -/****************************************************************************** -* -* Function: get_jpeg_Comment -* -* Description: Retreives the contents of the JPEG Comment (COM = 0xFFFE) segment if one -* exists -* -* Parameters: jpeg_header_data - the JPEG header data, as retrieved -* from the get_jpeg_header_data function -* -* Returns: string - Contents of the Comment segement -* FALSE - if the comment segment couldnt be found -* -******************************************************************************/ - -function get_jpeg_Comment( $jpeg_header_data ) -{ - //Cycle through the header segments until COM is found or we run out of segments - $i = 0; - while ( ( $i < count( $jpeg_header_data) ) && ( $jpeg_header_data[$i]['SegName'] != "COM" ) ) - { - $i++; - } - - // Check if a COM segment has been found - if ( $i < count( $jpeg_header_data) ) - { - // A COM segment was found, return it's contents - return $jpeg_header_data[$i]['SegData']; - } - else - { - // No COM segment found - return FALSE; - } -} - -/****************************************************************************** -* End of Function: get_jpeg_Comment -******************************************************************************/ - - -/****************************************************************************** -* -* Function: put_jpeg_Comment -* -* Description: Creates a new JPEG Comment segment from a string, and inserts -* this segment into the supplied JPEG header array -* -* Parameters: jpeg_header_data - a JPEG header data array in the same format -* as from get_jpeg_header_data, into which the -* new Comment segment will be put -* $new_Comment - a string containing the new Comment -* -* Returns: jpeg_header_data - the JPEG header data array with the new -* JPEG Comment segment added -* -******************************************************************************/ - -function put_jpeg_Comment( $jpeg_header_data, $new_Comment ) -{ - //Cycle through the header segments - for( $i = 0; $i < count( $jpeg_header_data ); $i++ ) - { - // If we find an COM header, - if ( strcmp ( $jpeg_header_data[$i]['SegName'], "COM" ) == 0 ) - { - // Found a preexisting Comment block - Replace it with the new one and return. - $jpeg_header_data[$i]['SegData'] = $new_Comment; - return $jpeg_header_data; - } - } - - - - // No preexisting Comment block found, find where to put it by searching for the highest app segment - $i = 0; - while ( ( $i < count( $jpeg_header_data ) ) && ( $jpeg_header_data[$i]["SegType"] >= 0xE0 ) ) - { - $i++; - } - - - // insert a Comment segment new at the position found of the header data. - array_splice($jpeg_header_data, $i , 0, array( array( "SegType" => 0xFE, - "SegName" => $GLOBALS[ "JPEG_Segment_Names" ][ 0xFE ], - "SegDesc" => $GLOBALS[ "JPEG_Segment_Descriptions" ][ 0xFE ], - "SegData" => $new_Comment ) ) ); - return $jpeg_header_data; -} - -/****************************************************************************** -* End of Function: put_jpeg_Comment -******************************************************************************/ - - - - -/****************************************************************************** -* -* Function: Interpret_Comment_to_HTML -* -* Description: Generates html showing the contents of any JPEG Comment segment -* -* Parameters: jpeg_header_data - the JPEG header data, as retrieved -* from the get_jpeg_header_data function -* -* Returns: output - the HTML -* -******************************************************************************/ - -function Interpret_Comment_to_HTML( $jpeg_header_data ) -{ - // Create a string to receive the output - $output = ""; - - // read the comment segment - $comment = get_jpeg_Comment( $jpeg_header_data ); - - // Check if the comment segment was valid - if ( $comment !== FALSE ) - { - // Comment exists - add it to the output - $output .= "<h2 class=\"JPEG_Comment_Main_Heading\">JPEG Comment</h2>\n"; - $output .= "<p class=\"JPEG_Comment_Text\">$comment</p>\n"; - } - - // Return the result - return $output; -} - -/****************************************************************************** -* End of Function: Interpret_Comment_to_HTML -******************************************************************************/ - - - - -/****************************************************************************** -* -* Function: get_jpeg_intrinsic_values -* -* Description: Retreives information about the intrinsic characteristics of the -* jpeg image, such as Bits per Component, Height and Width. -* -* Parameters: jpeg_header_data - the JPEG header data, as retrieved -* from the get_jpeg_header_data function -* -* Returns: array - An array containing the intrinsic JPEG values -* FALSE - if the comment segment couldnt be found -* -******************************************************************************/ - -function get_jpeg_intrinsic_values( $jpeg_header_data ) -{ - // Create a blank array for the output - $Outputarray = array( ); - - //Cycle through the header segments until Start Of Frame (SOF) is found or we run out of segments - $i = 0; - while ( ( $i < count( $jpeg_header_data) ) && ( substr( $jpeg_header_data[$i]['SegName'], 0, 3 ) != "SOF" ) ) - { - $i++; - } - - // Check if a SOF segment has been found - if ( substr( $jpeg_header_data[$i]['SegName'], 0, 3 ) == "SOF" ) - { - // SOF segment was found, extract the information - - $data = $jpeg_header_data[$i]['SegData']; - - // First byte is Bits per component - $Outputarray['Bits per Component'] = ord( $data{0} ); - - // Second and third bytes are Image Height - $Outputarray['Image Height'] = ord( $data{ 1 } ) * 256 + ord( $data{ 2 } ); - - // Forth and fifth bytes are Image Width - $Outputarray['Image Width'] = ord( $data{ 3 } ) * 256 + ord( $data{ 4 } ); - - // Sixth byte is number of components - $numcomponents = ord( $data{ 5 } ); - - // Following this is a table containing information about the components - for( $i = 0; $i < $numcomponents; $i++ ) - { - $Outputarray['Components'][] = array ( 'Component Identifier' => ord( $data{ 6 + $i * 3 } ), - 'Horizontal Sampling Factor' => ( ord( $data{ 7 + $i * 3 } ) & 0xF0 ) / 16, - 'Vertical Sampling Factor' => ( ord( $data{ 7 + $i * 3 } ) & 0x0F ), - 'Quantization table destination selector' => ord( $data{ 8 + $i * 3 } ) ); - } - } - else - { - // Couldn't find Start Of Frame segment, hence can't retrieve info - return FALSE; - } - - return $Outputarray; -} - - -/****************************************************************************** -* End of Function: get_jpeg_intrinsic_values -******************************************************************************/ - - - - - -/****************************************************************************** -* -* Function: Interpret_intrinsic_values_to_HTML -* -* Description: Generates html showing some of the intrinsic JPEG values which -* were retrieved with the get_jpeg_intrinsic_values function -* -* Parameters: values - the JPEG intrinsic values, as read from get_jpeg_intrinsic_values -* -* Returns: OutputStr - A string containing the HTML -* -******************************************************************************/ - -function Interpret_intrinsic_values_to_HTML( $values ) -{ - // Check values are valid - if ( $values != FALSE ) - { - // Write Heading - $OutputStr = "<h2 class=\"JPEG_Intrinsic_Main_Heading\">Intrinsic JPEG Information</h2>\n"; - - // Create Table - $OutputStr .= "<table class=\"JPEG_Intrinsic_Table\" border=1>\n"; - - // Put image height and width into table - $OutputStr .= "<tr class=\"JPEG_Intrinsic_Table_Row\"><td class=\"JPEG_Intrinsic_Caption_Cell\">Image Height</td><td class=\"JPEG_Intrinsic_Value_Cell\">" . $values['Image Height'] . " pixels</td></tr>\n"; - $OutputStr .= "<tr class=\"JPEG_Intrinsic_Table_Row\"><td class=\"JPEG_Intrinsic_Caption_Cell\">Image Width</td><td class=\"JPEG_Intrinsic_Value_Cell\">" . $values['Image Width'] . " pixels</td></tr>\n"; - - // Put colour depth into table - if ( count( $values['Components'] ) == 1 ) - { - $OutputStr .= "<tr class=\"JPEG_Intrinsic_Table_Row\"><td class=\"JPEG_Intrinsic_Caption_Cell\">Colour Depth</td><td class=\"JPEG_Intrinsic_Value_Cell\">" . $values['Bits per Component'] . " bit Monochrome</td></tr>\n"; - } - else - { - $OutputStr .= "<tr class=\"JPEG_Intrinsic_Table_Row\"><td class=\"JPEG_Intrinsic_Caption_Cell\">Colour Depth</td><td class=\"JPEG_Intrinsic_Value_Cell\">" . ($values['Bits per Component'] * count( $values['Components'] ) ) . " bit</td></tr>\n"; - } - - // Close Table - $OutputStr .= "</table>\n"; - - // Return html - return $OutputStr; - } -} - -/****************************************************************************** -* End of Function: Interpret_intrinsic_values_to_HTML -******************************************************************************/ - - - - - - - -/****************************************************************************** -* -* Function: get_jpeg_image_data -* -* Description: Retrieves the compressed image data part of the JPEG file -* -* Parameters: filename - the filename of the JPEG file to read -* -* Returns: compressed_data - A string containing the compressed data -* FALSE - if retrieval failed -* -******************************************************************************/ - -function get_jpeg_image_data( $filename ) -{ - - // prevent refresh from aborting file operations and hosing file - ignore_user_abort(true); - - // Attempt to open the jpeg file - $filehnd = @fopen($filename, 'rb'); - - // Check if the file opened successfully - if ( ! $filehnd ) - { - // Could't open the file - exit - return FALSE; - } - - - // Read the first two characters - $data = network_safe_fread( $filehnd, 2 ); - - // Check that the first two characters are 0xFF 0xDA (SOI - Start of image) - if ( $data != "\xFF\xD8" ) - { - // No SOI (FF D8) at start of file - close file and return; - fclose($filehnd); - return FALSE; - } - - - - // Read the third character - $data = network_safe_fread( $filehnd, 2 ); - - // Check that the third character is 0xFF (Start of first segment header) - if ( $data{0} != "\xFF" ) - { - // NO FF found - close file and return - fclose($filehnd); - return; - } - - // Flag that we havent yet hit the compressed image data - $hit_compressed_image_data = FALSE; - - - // Cycle through the file until, one of: 1) an EOI (End of image) marker is hit, - // 2) we have hit the compressed image data (no more headers are allowed after data) - // 3) or end of file is hit - - while ( ( $data{1} != "\xD9" ) && (! $hit_compressed_image_data) && ( ! feof( $filehnd ) )) - { - // Found a segment to look at. - // Check that the segment marker is not a Restart marker - restart markers don't have size or data after them - if ( ( ord($data{1}) < 0xD0 ) || ( ord($data{1}) > 0xD7 ) ) - { - // Segment isn't a Restart marker - // Read the next two bytes (size) - $sizestr = network_safe_fread( $filehnd, 2 ); - - // convert the size bytes to an integer - $decodedsize = unpack ("nsize", $sizestr); - - // Read the segment data with length indicated by the previously read size - $segdata = network_safe_fread( $filehnd, $decodedsize['size'] - 2 ); - } - - // If this is a SOS (Start Of Scan) segment, then there is no more header data - the compressed image data follows - if ( $data{1} == "\xDA" ) - { - // Flag that we have hit the compressed image data - exit loop after reading the data - $hit_compressed_image_data = TRUE; - - // read the rest of the file in - // Can't use the filesize function to work out - // how much to read, as it won't work for files being read by http or ftp - // So instead read 1Mb at a time till EOF - - $compressed_data = ""; - do - { - $compressed_data .= network_safe_fread( $filehnd, 1048576 ); - } while( ! feof( $filehnd ) ); - - // Strip off EOI and anything after - $EOI_pos = strpos( $compressed_data, "\xFF\xD9" ); - $compressed_data = substr( $compressed_data, 0, $EOI_pos ); - } - else - { - // Not an SOS - Read the next two bytes - should be the segment marker for the next segment - $data = network_safe_fread( $filehnd, 2 ); - - // Check that the first byte of the two is 0xFF as it should be for a marker - if ( $data{0} != "\xFF" ) - { - // Problem - NO FF foundclose file and return"; - fclose($filehnd); - return; - } - } - } - - // Close File - fclose($filehnd); - - // Alow the user to abort from now on - ignore_user_abort(false); - - - // Return the compressed data if it was found - if ( $hit_compressed_image_data ) - { - return $compressed_data; - } - else - { - return FALSE; - } -} - - -/****************************************************************************** -* End of Function: get_jpeg_image_data -******************************************************************************/ - - - - - - - -/****************************************************************************** -* -* Function: Generate_JPEG_APP_Segment_HTML -* -* Description: Generates html showing information about the Application (APP) -* segments which are present in the JPEG file -* -* Parameters: jpeg_header_data - the JPEG header data, as retrieved -* from the get_jpeg_header_data function -* -* Returns: output - A string containing the HTML -* -******************************************************************************/ - -function Generate_JPEG_APP_Segment_HTML( $jpeg_header_data ) -{ - if ( $jpeg_header_data == FALSE ) - { - return ""; - } - - - // Write Heading - $output = "<h2 class=\"JPEG_APP_Segments_Main_Heading\">Application Metadata Segments</h2>\n"; - - // Create table - $output .= "<table class=\"JPEG_APP_Segments_Table\" border=1>\n"; - - - // Cycle through each segment in the array - - foreach( $jpeg_header_data as $jpeg_header ) - { - - // Check if the segment is a APP segment - - if ( ( $jpeg_header['SegType'] >= 0xE0 ) && ( $jpeg_header['SegType'] <= 0xEF ) ) - { - // This is an APP segment - - // Read APP Segment Name - a Null terminated string at the start of the segment - $seg_name = strtok($jpeg_header['SegData'], "\x00"); - - // Some Segment names are either too long or not meaningfull, so - // we should clean them up - - if ( $seg_name == "http://ns.adobe.com/xap/1.0/" ) - { - $seg_name = "XAP/RDF (\"http://ns.adobe.com/xap/1.0/\")"; - } - elseif ( $seg_name == "Photoshop 3.0" ) - { - $seg_name = "Photoshop IRB (\"Photoshop 3.0\")"; - } - elseif ( ( strncmp ( $seg_name, "[picture info]", 14) == 0 ) || - ( strncmp ( $seg_name, "\x0a\x09\x09\x09\x09[picture info]", 19) == 0 ) ) - { - $seg_name = "[picture info]"; - } - elseif ( strncmp ( $seg_name, "Type=", 5) == 0 ) - { - $seg_name = "Epson Info"; - } - elseif ( ( strncmp ( $seg_name, "HHHHHHHHHHHHHHH", 15) == 0 ) || - ( strncmp ( $seg_name, "@s33", 5) == 0 ) ) - { - $seg_name = "HP segment full of \"HHHHH\""; - } - - - // Clean the segment name so it doesn't cause problems with HTML - $seg_name = htmlentities( $seg_name ); - - // Output a Table row containing this APP segment - $output .= "<tr class=\"JPEG_APP_Segments_Table_Row\"><td class=\"JPEG_APP_Segments_Caption_Cell\">$seg_name</td><td class=\"JPEG_APP_Segments_Type_Cell\">" . $jpeg_header['SegName'] . "</td><td class=\"JPEG_APP_Segments_Size_Cell\" align=\"right\">" . strlen( $jpeg_header['SegData']). " bytes</td></tr>\n"; - } - } - - // Close the table - $output .= "</table>\n"; - - // Return the HTML - return $output; -} - - -/****************************************************************************** -* End of Function: Generate_JPEG_APP_Segment_HTML -******************************************************************************/ - - - - -/****************************************************************************** -* -* Function: network_safe_fread -* -* Description: Retrieves data from a file. This function is required since -* the fread function will not always return the requested number -* of characters when reading from a network stream or pipe -* -* Parameters: file_handle - the handle of a file to read from -* length - the number of bytes requested -* -* Returns: data - the data read from the file. may be less than the number -* requested if EOF was hit -* -******************************************************************************/ - -function network_safe_fread( $file_handle, $length ) -{ - // Create blank string to receive data - $data = ""; - - // Keep reading data from the file until either EOF occurs or we have - // retrieved the requested number of bytes - - while ( ( !feof( $file_handle ) ) && ( strlen($data) < $length ) ) - { - $data .= fread( $file_handle, $length-strlen($data) ); - } - - // return the data read - return $data; -} - -/****************************************************************************** -* End of Function: network_safe_fread -******************************************************************************/ - - - - -/****************************************************************************** -* Global Variable: JPEG_Segment_Names -* -* Contents: The names of the JPEG segment markers, indexed by their marker number -* -******************************************************************************/ - -$GLOBALS[ "JPEG_Segment_Names" ] = array( - -0xC0 => "SOF0", 0xC1 => "SOF1", 0xC2 => "SOF2", 0xC3 => "SOF4", -0xC5 => "SOF5", 0xC6 => "SOF6", 0xC7 => "SOF7", 0xC8 => "JPG", -0xC9 => "SOF9", 0xCA => "SOF10", 0xCB => "SOF11", 0xCD => "SOF13", -0xCE => "SOF14", 0xCF => "SOF15", -0xC4 => "DHT", 0xCC => "DAC", - -0xD0 => "RST0", 0xD1 => "RST1", 0xD2 => "RST2", 0xD3 => "RST3", -0xD4 => "RST4", 0xD5 => "RST5", 0xD6 => "RST6", 0xD7 => "RST7", - -0xD8 => "SOI", 0xD9 => "EOI", 0xDA => "SOS", 0xDB => "DQT", -0xDC => "DNL", 0xDD => "DRI", 0xDE => "DHP", 0xDF => "EXP", - -0xE0 => "APP0", 0xE1 => "APP1", 0xE2 => "APP2", 0xE3 => "APP3", -0xE4 => "APP4", 0xE5 => "APP5", 0xE6 => "APP6", 0xE7 => "APP7", -0xE8 => "APP8", 0xE9 => "APP9", 0xEA => "APP10", 0xEB => "APP11", -0xEC => "APP12", 0xED => "APP13", 0xEE => "APP14", 0xEF => "APP15", - - -0xF0 => "JPG0", 0xF1 => "JPG1", 0xF2 => "JPG2", 0xF3 => "JPG3", -0xF4 => "JPG4", 0xF5 => "JPG5", 0xF6 => "JPG6", 0xF7 => "JPG7", -0xF8 => "JPG8", 0xF9 => "JPG9", 0xFA => "JPG10", 0xFB => "JPG11", -0xFC => "JPG12", 0xFD => "JPG13", - -0xFE => "COM", 0x01 => "TEM", 0x02 => "RES", - -); - -/****************************************************************************** -* End of Global Variable: JPEG_Segment_Names -******************************************************************************/ - - -/****************************************************************************** -* Global Variable: JPEG_Segment_Descriptions -* -* Contents: The descriptions of the JPEG segment markers, indexed by their marker number -* -******************************************************************************/ - -$GLOBALS[ "JPEG_Segment_Descriptions" ] = array( - -/* JIF Marker byte pairs in JPEG Interchange Format sequence */ -0xC0 => "Start Of Frame (SOF) Huffman - Baseline DCT", -0xC1 => "Start Of Frame (SOF) Huffman - Extended sequential DCT", -0xC2 => "Start Of Frame Huffman - Progressive DCT (SOF2)", -0xC3 => "Start Of Frame Huffman - Spatial (sequential) lossless (SOF3)", -0xC5 => "Start Of Frame Huffman - Differential sequential DCT (SOF5)", -0xC6 => "Start Of Frame Huffman - Differential progressive DCT (SOF6)", -0xC7 => "Start Of Frame Huffman - Differential spatial (SOF7)", -0xC8 => "Start Of Frame Arithmetic - Reserved for JPEG extensions (JPG)", -0xC9 => "Start Of Frame Arithmetic - Extended sequential DCT (SOF9)", -0xCA => "Start Of Frame Arithmetic - Progressive DCT (SOF10)", -0xCB => "Start Of Frame Arithmetic - Spatial (sequential) lossless (SOF11)", -0xCD => "Start Of Frame Arithmetic - Differential sequential DCT (SOF13)", -0xCE => "Start Of Frame Arithmetic - Differential progressive DCT (SOF14)", -0xCF => "Start Of Frame Arithmetic - Differential spatial (SOF15)", -0xC4 => "Define Huffman Table(s) (DHT)", -0xCC => "Define Arithmetic coding conditioning(s) (DAC)", - -0xD0 => "Restart with modulo 8 count 0 (RST0)", -0xD1 => "Restart with modulo 8 count 1 (RST1)", -0xD2 => "Restart with modulo 8 count 2 (RST2)", -0xD3 => "Restart with modulo 8 count 3 (RST3)", -0xD4 => "Restart with modulo 8 count 4 (RST4)", -0xD5 => "Restart with modulo 8 count 5 (RST5)", -0xD6 => "Restart with modulo 8 count 6 (RST6)", -0xD7 => "Restart with modulo 8 count 7 (RST7)", - -0xD8 => "Start of Image (SOI)", -0xD9 => "End of Image (EOI)", -0xDA => "Start of Scan (SOS)", -0xDB => "Define quantization Table(s) (DQT)", -0xDC => "Define Number of Lines (DNL)", -0xDD => "Define Restart Interval (DRI)", -0xDE => "Define Hierarchical progression (DHP)", -0xDF => "Expand Reference Component(s) (EXP)", - -0xE0 => "Application Field 0 (APP0) - usually JFIF or JFXX", -0xE1 => "Application Field 1 (APP1) - usually EXIF or XMP/RDF", -0xE2 => "Application Field 2 (APP2) - usually Flashpix", -0xE3 => "Application Field 3 (APP3)", -0xE4 => "Application Field 4 (APP4)", -0xE5 => "Application Field 5 (APP5)", -0xE6 => "Application Field 6 (APP6)", -0xE7 => "Application Field 7 (APP7)", - -0xE8 => "Application Field 8 (APP8)", -0xE9 => "Application Field 9 (APP9)", -0xEA => "Application Field 10 (APP10)", -0xEB => "Application Field 11 (APP11)", -0xEC => "Application Field 12 (APP12) - usually [picture info]", -0xED => "Application Field 13 (APP13) - usually photoshop IRB / IPTC", -0xEE => "Application Field 14 (APP14)", -0xEF => "Application Field 15 (APP15)", - - -0xF0 => "Reserved for JPEG extensions (JPG0)", -0xF1 => "Reserved for JPEG extensions (JPG1)", -0xF2 => "Reserved for JPEG extensions (JPG2)", -0xF3 => "Reserved for JPEG extensions (JPG3)", -0xF4 => "Reserved for JPEG extensions (JPG4)", -0xF5 => "Reserved for JPEG extensions (JPG5)", -0xF6 => "Reserved for JPEG extensions (JPG6)", -0xF7 => "Reserved for JPEG extensions (JPG7)", -0xF8 => "Reserved for JPEG extensions (JPG8)", -0xF9 => "Reserved for JPEG extensions (JPG9)", -0xFA => "Reserved for JPEG extensions (JPG10)", -0xFB => "Reserved for JPEG extensions (JPG11)", -0xFC => "Reserved for JPEG extensions (JPG12)", -0xFD => "Reserved for JPEG extensions (JPG13)", - -0xFE => "Comment (COM)", -0x01 => "For temp private use arith code (TEM)", -0x02 => "Reserved (RES)", - -); - -/****************************************************************************** -* End of Global Variable: JPEG_Segment_Descriptions -******************************************************************************/ - - - +<?php + +/****************************************************************************** +* +* Filename: JPEG.php +* +* Description: Provides functions for reading and writing information to/from +* JPEG format files +* +* Author: Evan Hunter +* +* Date: 23/7/2004 +* +* Project: PHP JPEG Metadata Toolkit +* +* Revision: 1.10 +* +* Changes: 1.00 -> 1.10 : changed put_jpeg_header_data to check if the data +* being written exists +* +* URL: http://electronics.ozhiker.com +* +* Copyright: Copyright Evan Hunter 2004 +* +* License: This file is part of the PHP JPEG Metadata Toolkit. +* +* The PHP JPEG Metadata Toolkit is free software; you can +* redistribute it and/or modify it under the terms of the +* GNU General Public License as published by the Free Software +* Foundation; either version 2 of the License, or (at your +* option) any later version. +* +* The PHP JPEG Metadata Toolkit is distributed in the hope +* that it will be useful, but WITHOUT ANY WARRANTY; without +* even the implied warranty of MERCHANTABILITY or FITNESS +* FOR A PARTICULAR PURPOSE. See the GNU General Public License +* for more details. +* +* You should have received a copy of the GNU General Public +* License along with the PHP JPEG Metadata Toolkit; if not, +* write to the Free Software Foundation, Inc., 59 Temple +* Place, Suite 330, Boston, MA 02111-1307 USA +* +* If you require a different license for commercial or other +* purposes, please contact the author: ev...@oz... +* +******************************************************************************/ + + + + +/****************************************************************************** +* +* Function: get_jpeg_header_data +* +* Description: Reads all the JPEG header segments from an JPEG image file into an +* array +* +* Parameters: filename - the filename of the file to JPEG file to read +* +* Returns: headerdata - Array of JPEG header segments +* FALSE - if headers could not be read +* +******************************************************************************/ + +function get_jpeg_header_data( $filename ) +{ + + // prevent refresh from aborting file operations and hosing file + ignore_user_abort(true); + + + // Attempt to open the jpeg file - the at symbol supresses the error message about + // not being able to open files. The file_exists would have been used, but it + // does not work with files fetched over http or ftp. + $filehnd = @fopen($filename, 'rb'); + + // Check if the file opened successfully + if ( ! $filehnd ) + { + // Could't open the file - exit + echo "<p>Could not open file $filename</p>\n"; + return FALSE; + } + + + // Read the first two characters + $data = network_safe_fread( $filehnd, 2 ); + + // Check that the first two characters are 0xFF 0xDA (SOI - Start of image) + if ( $data != "\xFF\xD8" ) + { + // No SOI (FF D8) at start of file - This probably isn't a JPEG file - close file and return; + //echo "<p>This probably is not a JPEG file</p>\n"; + fclose($filehnd); + return FALSE; + } + + + // Read the third character + $data = network_safe_fread( $filehnd, 2 ); + + // Check that the third character is 0xFF (Start of first segment header) + if ( $data{0} != "\xFF" ) + { + // NO FF found - close file and return - JPEG is probably corrupted + fclose($filehnd); + return FALSE; + } + + // Flag that we havent yet hit the compressed image data + $hit_compressed_image_data = FALSE; + + + // Cycle through the file until, one of: 1) an EOI (End of image) marker is hit, + // 2) we have hit the compressed image data (no more headers are allowed after data) + // 3) or end of file is hit + + while ( ( $data{1} != "\xD9" ) && (! $hit_compressed_image_data) && ( ! feof( $filehnd ) )) + { + // Found a segment to look at. + // Check that the segment marker is not a Restart marker - restart markers don't have size or data after them + if ( ( ord($data{1}) < 0xD0 ) || ( ord($data{1}) > 0xD7 ) ) + { + // Segment isn't a Restart marker + // Read the next two bytes (size) + $sizestr = network_safe_fread( $filehnd, 2 ); + + // convert the size bytes to an integer + $decodedsize = unpack ("nsize", $sizestr); + + // Save the start position of the data + $segdatastart = ftell( $filehnd ); + + // Read the segment data with length indicated by the previously read size + $segdata = network_safe_fread( $filehnd, $decodedsize['size'] - 2 ); + + + // Store the segment information in the output array + $headerdata[] = array( "SegType" => ord($data{1}), + "SegName" => $GLOBALS[ "JPEG_Segment_Names" ][ ord($data{1}) ], + "SegDesc" => $GLOBALS[ "JPEG_Segment_Descriptions" ][ ord($data{1}) ], + "SegDataStart" => $segdatastart, + "SegData" => $segdata ); + } + + // If this is a SOS (Start Of Scan) segment, then there is no more header data - the compressed image data follows + if ( $data{1} == "\xDA" ) + { + // Flag that we have hit the compressed image data - exit loop as no more headers available. + $hit_compressed_image_data = TRUE; + } + else + { + // Not an SOS - Read the next two bytes - should be the segment marker for the next segment + $data = network_safe_fread( $filehnd, 2 ); + + // Check that the first byte of the two is 0xFF as it should be for a marker + if ( $data{0} != "\xFF" ) + { + // NO FF found - close file and return - JPEG is probably corrupted + fclose($filehnd); + return FALSE; + } + } + } + + // Close File + fclose($filehnd); + // Alow the user to abort from now on + ignore_user_abort(false); + + // Return the header data retrieved + return $headerdata; +} + + +/****************************************************************************** +* End of Function: get_jpeg_header_data +******************************************************************************/ + + + + +/****************************************************************************** +* +* Function: put_jpeg_header_data +* +* Description: Writes JPEG header data into a JPEG file. Takes an array in the +* same format as from get_jpeg_header_data, and combines it with +* the image data of an existing JPEG file, to create a new JPEG file +* WARNING: As this function will replace all JPEG headers, +* including SOF etc, it is best to read the jpeg headers +* from a file, alter them, then put them back on the same +* file. If a SOF segment wer to be transfered from one +* file to another, the image could become unreadable unless +* the images were idenical size and configuration +* +* +* Parameters: old_filename - the JPEG file from which the image data will be retrieved +* new_filename - the name of the new JPEG to create (can be same as old_filename) +* jpeg_header_data - a JPEG header data array in the same format +* as from get_jpeg_header_data +* +* Returns: TRUE - on Success +* FALSE - on Failure +* +******************************************************************************/ + +function put_jpeg_header_data( $old_filename, $new_filename, $jpeg_header_data ) +{ + + // Change: added check to ensure data exists, as of revision 1.10 + // Check if the data to be written exists + if ( $jpeg_header_data == FALSE ) + { + // Data to be written not valid - abort + return FALSE; + } + + // extract the compressed image data from the old file + $compressed_image_data = get_jpeg_image_data( $old_filename ); + + // Check if the extraction worked + if ( ( $compressed_image_data === FALSE ) || ( $compressed_image_data === NULL ) ) + { + // Couldn't get image data from old file + return FALSE; + } + + + // Cycle through new headers + foreach ($jpeg_header_data as $segno => $segment) + { + // Check that this header is smaller than the maximum size + if ( strlen($segment['SegData']) > 0xfffd ) + { + // Could't open the file - exit + echo "<p>A Header is too large to fit in JPEG segment</p>\n"; + return FALSE; + } + } + + ignore_user_abort(true); ## prevent refresh from aborting file operations and hosing file + + + // Attempt to open the new jpeg file + $newfilehnd = @fopen($new_filename, 'wb'); + // Check if the file opened successfully + if ( ! $newfilehnd ) + { + // Could't open the file - exit + echo "<p>Could not open file $new_filename</p>\n"; + return FALSE; + } + + // Write SOI + fwrite( $newfilehnd, "\xFF\xD8" ); + + // Cycle through new headers, writing them to the new file + foreach ($jpeg_header_data as $segno => $segment) + { + + // Write segment marker + fwrite( $newfilehnd, sprintf( "\xFF%c", $segment['SegType'] ) ); + + // Write segment size + fwrite( $newfilehnd, pack( "n", strlen($segment['SegData']) + 2 ) ); + + // Write segment data + fwrite( $newfilehnd, $segment['SegData'] ); + } + + // Write the compressed image data + fwrite( $newfilehnd, $compressed_image_data ); + + // Write EOI + fwrite( $newfilehnd, "\xFF\xD9" ); + + // Close File + fclose($newfilehnd); + + // Alow the user to abort from now on + ignore_user_abort(false); + + + return TRUE; + +} + +/****************************************************************************** +* End of Function: put_jpeg_header_data +******************************************************************************/ + + + +/****************************************************************************** +* +* Function: get_jpeg_Comment +* +* Description: Retreives the contents of the JPEG Comment (COM = 0xFFFE) segment if one +* exists +* +* Parameters: jpeg_header_data - the JPEG header data, as retrieved +* from the get_jpeg_header_data function +* +* Returns: string - Contents of the Comment segement +* FALSE - if the comment segment couldnt be found +* +******************************************************************************/ + +function get_jpeg_Comment( $jpeg_header_data ) +{ + //Cycle through the header segments until COM is found or we run out of segments + $i = 0; + while ( ( $i < count( $jpeg_header_data) ) && ( $jpeg_header_data[$i]['SegName'] != "COM" ) ) + { + $i++; + } + + // Check if a COM segment has been found + if ( $i < count( $jpeg_header_data) ) + { + // A COM segment was found, return it's contents + return $jpeg_header_data[$i]['SegData']; + } + else + { + // No COM segment found + return FALSE; + } +} + +/****************************************************************************** +* End of Function: get_jpeg_Comment +******************************************************************************/ + + +/****************************************************************************** +* +* Function: put_jpeg_Comment +* +* Description: Creates a new JPEG Comment segment from a string, and inserts +* this segment into the supplied JPEG header array +* +* Parameters: jpeg_header_data - a JPEG header data array in the same format +* as from get_jpeg_header_data, into which the +* new Comment segment will be put +* $new_Comment - a string containing the new Comment +* +* Returns: jpeg_header_data - the JPEG header data array with the new +* JPEG Comment segment added +* +******************************************************************************/ + +function put_jpeg_Comment( $jpeg_header_data, $new_Comment ) +{ + //Cycle through the header segments + for( $i = 0; $i < count( $jpeg_header_data ); $i++ ) + { + // If we find an COM header, + if ( strcmp ( $jpeg_header_data[$i]['SegName'], "COM" ) == 0 ) + { + // Found a preexisting Comment block - Replace it with the new one and return. + $jpeg_header_data[$i]['SegData'] = $new_Comment; + return $jpeg_header_data; + } + } + + + + // No preexisting Comment block found, find where to put it by searching for the highest app segment + $i = 0; + while ( ( $i < count( $jpeg_header_data ) ) && ( $jpeg_header_data[$i]["SegType"] >= 0xE0 ) ) + { + $i++; + } + + + // insert a Comment segment new at the position found of the header data. + array_splice($jpeg_header_data, $i , 0, array( array( "SegType" => 0xFE, + "SegName" => $GLOBALS[ "JPEG_Segment_Names" ][ 0xFE ], + "SegDesc" => $GLOBALS[ "JPEG_Segment_Descriptions" ][ 0xFE ], + "SegData" => $new_Comment ) ) ); + return $jpeg_header_data; +} + +/****************************************************************************** +* End of Function: put_jpeg_Comment +******************************************************************************/ + + + + +/****************************************************************************** +* +* Function: Interpret_Comment_to_HTML +* +* Description: Generates html showing the contents of any JPEG Comment segment +* +* Parameters: jpeg_header_data - the JPEG header data, as retrieved +* from the get_jpeg_header_data function +* +* Returns: output - the HTML +* +******************************************************************************/ + +function Interpret_Comment_to_HTML( $jpeg_header_data ) +{ + // Create a string to receive the output + $output = ""; + + // read the comment segment + $comment = get_jpeg_Comment( $jpeg_header_data ); + + // Check if the comment segment was valid + if ( $comment !== FALSE ) + { + // Comment exists - add it to the output + $output .= "<h2 class=\"JPEG_Comment_Main_Heading\">JPEG Comment</h2>\n"; + $output .= "<p class=\"JPEG_Comment_Text\">$comment</p>\n"; + } + + // Return the result + return $output; +} + +/****************************************************************************** +* End of Function: Interpret_Comment_to_HTML +******************************************************************************/ + + + + +/****************************************************************************** +* +* Function: get_jpeg_intrinsic_values +* +* Description: Retreives information about the intrinsic characteristics of the +* jpeg image, such as Bits per Component, Height and Width. +* +* Parameters: jpeg_header_data - the JPEG header data, as retrieved +* from the get_jpeg_header_data function +* +* Returns: array - An array containing the intrinsic JPEG values +* FALSE - if the comment segment couldnt be found +* +******************************************************************************/ + +function get_jpeg_intrinsic_values( $jpeg_header_data ) +{ + // Create a blank array for the output + $Outputarray = array( ); + + //Cycle through the header segments until Start Of Frame (SOF) is found or we run out of segments + $i = 0; + while ( ( $i < count( $jpeg_header_data) ) && ( substr( $jpeg_header_data[$i]['SegName'], 0, 3 ) != "SOF" ) ) + { + $i++; + } + + // Check if a SOF segment has been found + if ( substr( $jpeg_header_data[$i]['SegName'], 0, 3 ) == "SOF" ) + { + // SOF segment was found, extract the information + + $data = $jpeg_header_data[$i]['SegData']; + + // First byte is Bits per component + $Outputarray['Bits per Component'] = ord( $data{0} ); + + // Second and third bytes are Image Height + $Outputarray['Image Height'] = ord( $data{ 1 } ) * 256 + ord( $data{ 2 } ); + + // Forth and fifth bytes are Image Width + $Outputarray['Image Width'] = ord( $data{ 3 } ) * 256 + ord( $data{ 4 } ); + + // Sixth byte is number of components + $numcomponents = ord( $data{ 5 } ); + + // Following this is a table containing information about the components + ... [truncated message content] |