Index: wp-admin/favicon-upload.php
===================================================================
--- wp-admin/favicon-upload.php	(revision 0)
+++ wp-admin/favicon-upload.php	(working copy)
@@ -0,0 +1,330 @@
+<?php
+/**
+ * Handles the uploading, cropping and scaling of favicons.
+ * 
+ * @uses ico2_3.php JPEXS class for reading / writing .ICO files
+ * 
+ * @package WordPress
+ * @subpackage Administration
+ * @since 3.4.1
+ */
+
+// Bootstrap admin and all its goodies
+require_once( 'admin.php' );
+
+// Bring in the JPEXS .ICO conversion library
+require_once( ABSPATH . 'wp-admin/includes/ico2_3.php' );
+
+
+define( 'FAVICON_SIZE', 32 ); // Width (and height) of the favicon (in pixels)
+
+/*	Upload is a 2-step process:	
+ *	1. Process the uploaded file and show the crop UI
+ *	2. Manipulate the pixel data, save to PNG and ICO and write to options.
+ */
+
+if ( isset( $_POST['CROP_AND_SAVE'] ) ) {
+	if ( isset( $_POST['attachment_id'] ) && is_numeric( $_POST['attachment_id'] ) ){
+		$image_basename = process_crop_thumbnail( $_POST['attachment_id'] );
+
+		if ( is_wp_error( $image_basename ) ) {
+			include_once('./admin-header.php');
+			echo '<div class="wrap">';
+				echo '<h2>' . __( 'Image upload error' ) . '</h2>';
+				echo '<p>' . $image_basename->get_error_message() . '</p>';
+				echo '<p><a href="' . admin_url( 'options-general.php' ) . '">&laquo;' . __( 'Back to Settings &gt; General' ) . '</a></p>';
+			echo '</div><!-- .wrap -->';
+			include_once('./admin-footer.php');
+		} else {
+			foreach ( array( $image_basename . '.png', $image_basename . '.ico' ) as $image_filename )
+				save_thumbnail_attachment( $image_filename, $attachment_id );
+
+			// And save the basename out to options.
+			update_option( 'sitefavicon', basename( $image_basename ) );
+			
+			/** @TODO need to find a way to notify the user that the process has completed successfully - admin_notices? */
+			wp_redirect( admin_url( 'options-general.php' ) );
+		} 
+	} else {
+		return new WP_Error( 'attachment_id_missing', 'Form submission error.' );
+	}
+} elseif ( isset( $_REQUEST['REMOVE_FAVICON'] ) ) {
+	remove_favicon();
+} else {
+	/** @TODO make sure that we trap for someone just pressing "Upload image" but with no image attached */
+	// Enqueue the JS for the cropper...
+	add_action( 'admin_enqueue_scripts', 'enqueue_cropper' );
+	// ...and our own script for populating the crop form
+	add_action( 'admin_footer', 'cropping_js', 10,  1);
+	
+	// Process the upload and create the attachment file in the media center
+	$image_results = process_thumbnail_upload();
+	
+	include_once('./admin-header.php');
+	
+	// hack because image replication isn't fast enough. See https://wpcom.automattic.com/ticket/1294
+	sleep( 2 );
+
+	echo '<div class="wrap">';
+	
+	if ( is_wp_error( $image_results ) )  {
+		echo '<h2>' . __( 'Image upload error' ) . '</h2>';
+		echo '<p>' . $image_results->get_error_message() . '</p>';
+		echo '<p><a href="' . admin_url( 'options-general.php' ) . '">&laquo;' . __( 'Back to Settings &gt; General' ) . '</a></p>';
+	} else {
+		// Image upload successful.
+		// Now we can hook in our javascript and provide the width/height of our image as the default crop size
+		$crop_size = min( $image_results['width'], $image_results['height'] );
+		echo '<script type="text/javascript">var jcrop_starting_size = ' . $crop_size . '; // Initialize jcrop crop area starting size</script>';
+	
+		echo '<h2>' . __( 'Crop uploaded image' ) . '</h2>';
+		echo '<p>' . __( 'Choose the part of the image you want to use for your favicon.' ) . '</p>';
+		
+		echo '<form id="favicon-crop-form" method="post" action="' . $_SERVER['REQUEST_URI'] . '">'; // Point the form action back to this script
+		
+			echo <<<CROP_FORM
+			<input type="hidden" name="x1" id="x1" />
+			<input type="hidden" name="y1" id="y1" />
+			<input type="hidden" name="x2" id="x2" />
+			<input type="hidden" name="y2" id="y2" />
+			<input type="hidden" name="width" id="width" />
+			<input type="hidden" name="height" id="height" />
+			<input type="hidden" name="attachment_id" id="attachment_id" value="{$image_results['attachment_id']}" />
+			<input type="hidden" name="scaling_factor" id="scaling_factor" value="{$image_results['scaling_factor']}" />
+CROP_FORM;
+		
+			echo '<img src="' . $image_results['src'] . '" id="upload" width="' . $image_results['width'] . '" height="' . $image_results['height'] . '" />';
+		
+			echo '<p class="submit"><input type="submit" name="CROP_AND_SAVE" value="' . __( 'Crop image' ) . ' &raquo;" /></p>';
+		echo '</form>';
+	}
+	
+	echo '</div><!-- .wrap -->';
+	
+	include_once('./admin-footer.php');
+}
+
+
+/**
+ * Process the image file upload and return a WP_Error or details about the attachment image file.
+ * 
+ * @return mixed WP_Error | $image_results array 
+ */
+function process_thumbnail_upload(){
+	$file = wp_handle_upload( $_FILES['avatarfile'], array( 'action' => 'wp_upload_favicon') );
+	if ( isset($file['error']) ) die( $file['error'] );
+	
+	$url = $file['url'];
+	$file = $file['file'];
+	$filename = basename($file);
+	
+	// Construct the object array
+	$object = array(
+		'post_title' => $filename,
+		'post_content' => $url,
+		'post_mime_type' => 'import',
+		'guid' => $url
+	);
+
+	// Save the data.  Also makes replication work
+	$id = wp_insert_attachment($object, $file);
+
+	// Retrieve the image dimensions
+	list( $orig_width, $orig_height, $type, $attr ) = getimagesize( $file );
+	
+	// Do we need to scale down the image so we can display it nicely in the interactive Crop tool?
+	if ( $orig_width > 600 || $orig_height > 600 ) {
+		$image = wp_create_thumbnail( $file, 600 );
+		list( $width, $height, $type, $attr ) = getimagesize( $image );
+		
+		 // Update the attachment record to reflect the newly-scaled thumbnail image
+		$thumb = basename( $image );
+		$metadata = array( 'thumb' => $thumb );
+		wp_update_attachment_metadata( $id, $metadata );
+
+		$url = str_replace( basename( $url ), $thumb, $url );
+
+		$scaling = $orig_width / $width;
+	} else {
+		// No scaling required; just copy original values.
+		$width = $orig_width;
+		$height = $orig_height;
+		$scaling = 1;
+	}
+
+	// Check image file format
+	$image_type = exif_imagetype( get_attached_file( $id ) );
+	if (! in_array( $image_type, array( IMAGETYPE_PNG, IMAGETYPE_JPEG, IMAGETYPE_BMP ) ) )
+		$error = new WP_Error( 'bad_file_format', __( 'Please only use PNG (.png), JPEG (.jpg) or BMP (.bmp) image files for favicons. ' ) );
+	
+	// return WP_Error or the $image_results array
+	if ( $error ){
+		return $error;
+	} else {
+		return array( 
+			'attachment_id' => $id,
+			'src' => $url,
+			'width' => $width,
+			'height' => $height,
+			'scaling_factor' => $scaling
+		);
+	}
+}
+
+/**
+ * Create PNG and BMP image resources based on the form submission of the cropped thumbnail.
+ * 
+ * @param int $attachment_id The ID of the original attachment's post record.
+ * @return mixed WP_Error | Favicon file base name (ie: fully qualified file name without any TLA file extension)
+ */
+function process_crop_thumbnail( $attachment_id ){
+	$src_file = get_attached_file( $attachment_id );
+
+	// Highly unlikely, but let's check
+	if (! file_exists( $src_file ) )
+		return new WP_Error( 'file_missing', __( 'Attachment image file missing (possible save error: check space on web server).' ) );
+
+	// Make sure we're still within accepted image types
+	$image_type = exif_imagetype( $src_file );
+	if (! $image_type || ! in_array( $image_type, array( IMAGETYPE_PNG, IMAGETYPE_JPEG, IMAGETYPE_BMP ) ) )
+		return new WP_Error( 'bad_file_format', __( 'Please only use PNG (.png), JPEG (.jpg) or BMP (.bmp) image files for favicons. ' ) );
+
+	// Parse image file bytes
+	$src_image = wp_load_image( $src_file );
+	if ( !is_resource($src_image) )
+		return new WP_Error( 'is_not_resource', __( 'Error loading image. You got me: I\'m stumped.' ) ); 
+
+	// We crop from the original, not the medium sized, display-only thumbnail
+	$src_x = $_POST['x1'] * $_POST['scaling_factor'];
+	$src_y = $_POST['y1'] * $_POST['scaling_factor'];
+	$src_width = $_POST['width'] * $_POST['scaling_factor'];
+	$src_height = $_POST['height'] * $_POST['scaling_factor'];
+
+	$dst_width = $dst_height = FAVICON_SIZE;
+	// Avoid upscaling
+	if ( $src_width < $dst_width || $src_height < $dst_height ) {
+		$dst_width = $src_width;
+		$dst_height = $src_height;
+	}
+
+	$dst_image = wp_imagecreatetruecolor( $dst_width, $dst_height );
+	if ( function_exists( 'imageantialias' ) ) imageantialias( $dst_image, true );
+	imagealphablending( $dst_image, false );
+	imagesavealpha( $dst_image, true );
+	imagecopyresampled( $dst_image, $src_image, 0, 0, $src_x, $src_y, $dst_width, $dst_height, $src_width, $src_height );
+	imagedestroy( $src_image );
+
+
+	// Save the image in PNG and ICO formats
+	$file_info = pathinfo( $src_file );
+	$src_basename = basename( $src_file, '.' . $file_info['extension'] );
+	$dst_filename = str_replace( $src_basename, $src_basename . '_' . FAVICON_SIZE . 'x' . FAVICON_SIZE, $src_file );
+	// Strip the TLA from the filename
+	$dst_filename = preg_replace( '/\\.[^\\.]+$/', '', $dst_filename );
+
+	$png_filename = $dst_filename . '.png';
+	if (! imagepng( $dst_image, $png_filename, 0 ) )
+		return new WP_Error( 'png_write_error', 'Error writing PNG favicon file.' );
+	
+	$ico_filename = $dst_filename . '.ico';
+	imageIco( $dst_image, $ico_filename );
+	/** @TODO refactor the ico2_3.php library to add error checking and possibly encapsulate the class */
+	//if (! imageIco( $dst_image, $ico_filename ) )
+		//return new WP_Error( 'ico_write_error', 'Error writing ICO favicon file.' );
+
+	imagedestroy( $dst_image );
+
+	return $dst_filename;
+}
+
+/**
+ * Creates an attachment post record for a newly created thumbnail
+ * 
+ * @param string $file_name Fully qualified file name for the image asset file.
+ * @param int $parent_attachment_id The ID of the original thumbnail's attachment post record
+ * 
+ * @return int The ID of the newly-created thumbnail attachment post record
+ */
+function save_thumbnail_attachment( $file_name, $parent_attachment_id ){
+	$file_info = pathinfo( $file_name ); // So we can get the TLA later on
+	
+	$file_name = apply_filters( 'wp_create_file_in_uploads', $file_name, $parent_attachment_id ); // For replication
+
+	$parent = get_post( $parent_attachment_id );
+	$parent_url = $parent->guid;
+	
+	// Update the attachment
+	$mimes = get_allowed_mime_types();
+	$attachment_id = wp_insert_attachment( array(
+		'ID' => $attachment_id,
+		'post_title' => basename( $file_name ),
+		'post_content' => $url,
+		'post_mime_type' => $mimes[ $file_info['extension'] ],
+		'guid' => $url,
+		'context' => 'favicon'
+	), $file_name );
+	wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $file_name ) );
+	
+	return $attachment_id;
+}
+
+/**
+ * Currently, doesn't actually "remove" the favicon images. It only deletes the option
+ * that tells us there's a favicon, so the code isn't generated (or the default is used)
+ */
+function remove_favicon(){
+	update_option( 'sitefavicon', false );
+			
+	/** @TODO need to find a way to notify the user that the process has completed successfully - admin_notices? */
+	wp_redirect( admin_url( 'options-general.php' ) );
+}
+
+
+/**
+ * Called in admin_enqueue_scripts to add the cropper.js script and styles
+ */
+function enqueue_cropper(){
+	wp_enqueue_script( 'jcrop', 'jquery' );
+	wp_enqueue_style('jcrop'); // We can enqueue styles within the admin_enqueue_script action hook {@link http://wpdevel.wordpress.com/2011/12/12/use-wp_enqueue_scripts-not-wp_print_styles-to-enqueue-scripts-and-styles-for-the-frontend/}
+}
+
+function cropping_js(){
+	// Purely for coding convenience and legibility
+	$favicon_size = FAVICON_SIZE;
+	
+	echo <<<CROP_JS
+	<!-- Favicon cropping -->
+	<script type="text/javascript">
+		// Update the crop form
+		function onEndCrop( coords ) {
+			jQuery( '#x1' ).val(coords.x);
+			jQuery( '#y1' ).val(coords.y);
+			jQuery( '#x2' ).val(coords.x2);
+			jQuery( '#y2' ).val(coords.y2);
+			jQuery( '#width' ).val(coords.w);
+			jQuery( '#height' ).val(coords.h);
+		}
+
+		// with a supplied ratio
+		jQuery(function($) {
+			if (! jcrop_starting_size) jcrop_starting_size = {$favicon_size}; // jcrop_starting_size should be set in the body once the image has been processed
+
+			// Set up default values on the crop form
+			jQuery( '#x1' ).val(0);
+			jQuery( '#y1' ).val(0);
+			jQuery( '#x2' ).val(jcrop_starting_size);
+			jQuery( '#y2' ).val(jcrop_starting_size);
+			jQuery( '#width' ).val(jcrop_starting_size);
+			jQuery( '#height' ).val(jcrop_starting_size);
+
+			// Initialize Jcrop
+			$('#upload').Jcrop({
+				aspectRatio: 1,
+				setSelect: [0, 0, jcrop_starting_size, jcrop_starting_size],
+				onSelect: onEndCrop
+			});
+		});
+	</script>
+CROP_JS;
+
+}
\ No newline at end of file
Index: wp-admin/includes/ico2_3.php
===================================================================
--- wp-admin/includes/ico2_3.php	(revision 0)
+++ wp-admin/includes/ico2_3.php	(working copy)
@@ -0,0 +1,975 @@
+<?php
+/**
+ * @package com.jpexs.image.ico
+ *
+ * JPEXS ICO Image functions
+ * @version 2.3
+ * @author JPEXS
+ * @copyright (c) JPEXS 2004-2012
+ *
+ * Webpage: http://www.jpexs.com
+ * Email: jpexs@jpexs.com
+ *
+ * If you like my script, you can donate... visit my webpages or email me for more info.
+ *
+ *        Version changes:
+ *          2012-02-25 v2.3 - License changed to GNU/GPL v2 or v3
+ *          2012-02-18 v2.2 - License changed to GNU/GPL v3
+ *          2009-02-23 v2.1 - redesigned sourcecode, phpdoc included, all internal functions and global variables have prefix "jpexs_"
+ *                     v2.0 - For icons with Alpha channel now you can set background color
+ *                          - ImageCreateFromExeIco added
+ *                          - Fixed ICO_MAX_SIZE and ICO_MAX_COLOR values
+ *
+ * TODO list:
+ *      - better error handling
+ *      - better internal function handling
+ *      - class encapsulation
+ * 
+ * License:
+ *  This program 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 or version 3 of the License, or
+ *  (at your option) any later version.
+ * 
+ *  This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** TrueColor images constant  */
+define("ICO_TRUE_COLOR", 0x1000000);
+/** XPColor images constant (Alpha channel) */
+define("ICO_XP_COLOR", 4294967296);
+/** Image with maximum colors */
+define("ICO_MAX_COLOR", -2);
+/** Image with maximal size */
+define("ICO_MAX_SIZE", -2);
+
+
+/** TrueColor images constant
+ * @deprecated Deprecated since version 2.1, please use ICO_ constants
+ */
+define("TRUE_COLOR", 0x1000000);
+/** XPColor images constant (Alpha channel)
+ * @deprecated Deprecated since version 2.1, please use ICO_ constants
+ */
+define("XP_COLOR", 4294967296);
+/** Image with maximum colors
+ * @deprecated Deprecated since version 2.1, please use ICO_ constants
+ */
+define("MAX_COLOR", -2);
+/** Image with maximal size
+ * @deprecated Deprecated since version 2.1, please use ICO_ constants
+ */
+define("MAX_SIZE", -2);
+
+
+/**
+ * Reads image from a ICO file
+ *
+ * @param string $filename Target ico file to load
+ * @param int $icoColorCount Icon color count (For multiple icons ico file) - 2,16,256, ICO_TRUE_COLOR, ICO_XP_COLOR or ICO_MAX_COLOR
+ * @param int $icoSize Icon width (For multiple icons ico file) or ICO_MAX_SIZE
+ * @param int $alphaBgR Background color R value for alpha-channel images (Default is White)
+ * @param int $alphaBgG Background color G value for alpha-channel images (Default is White)
+ * @param int $alphaBgB Background color B value for alpha-channel images (Default is White)
+ * @return resource Image resource
+ */
+function imageCreateFromIco($filename,$icoColorCount=16,$icoSize=16,$alphaBgR=255,$alphaBgG=255,$alphaBgB=255)
+{
+$Ikona=jpexs_GetIconsInfo($filename);
+
+$IconID=-1;
+
+$ColMax=-1;
+$SizeMax=-1;
+
+for($p=0;$p<count($Ikona);$p++)
+{
+$Ikona[$p]["NumberOfColors"]=pow(2,$Ikona[$p]["Info"]["BitsPerPixel"]);
+};
+
+
+for($p=0;$p<count($Ikona);$p++)
+{
+
+if(($ColMax==-1)or($Ikona[$p]["NumberOfColors"]>=$Ikona[$ColMax]["NumberOfColors"]))
+if(($icoSize==$Ikona[$p]["Width"])or($icoSize==ICO_MAX_SIZE))
+ {
+  $ColMax=$p;
+ };
+
+if(($SizeMax==-1)or($Ikona[$p]["Width"]>=$Ikona[$SizeMax]["Width"]))
+if(($icoColorCount==$Ikona[$p]["NumberOfColors"])or($icoColorCount==ICO_MAX_COLOR))
+ {
+   $SizeMax=$p;
+ };
+
+
+if($Ikona[$p]["NumberOfColors"]==$icoColorCount)
+if($Ikona[$p]["Width"]==$icoSize)
+ {
+
+ $IconID=$p;
+ };
+};
+
+  if($icoColorCount==ICO_MAX_COLOR) $IconID=$ColMax;
+  if($icoSize==ICO_MAX_SIZE) $IconID=$SizeMax;
+
+$ColName=$icoColorCount;
+
+if($icoSize==ICO_MAX_SIZE) $icoSize="Max";
+if($ColName==ICO_TRUE_COLOR) $ColName="True";
+if($ColName==ICO_XP_COLOR) $ColName="XP";
+if($ColName==ICO_MAX_COLOR) $ColName="Max";
+if($IconID==-1) die("Icon with $ColName colors and $icoSize x $icoSize size doesn't exist in this file!");
+
+
+jpexs_readIcon($filename,$IconID,$Ikona);
+
+ $biBitCount=$Ikona[$IconID]["Info"]["BitsPerPixel"];
+
+
+  if($Ikona[$IconID]["Info"]["BitsPerPixel"]==0)
+  {
+  $Ikona[$IconID]["Info"]["BitsPerPixel"]=24;
+  };
+
+ $biBitCount=$Ikona[$IconID]["Info"]["BitsPerPixel"];
+ if($biBitCount==0) $biBitCount=1;
+
+
+$Ikona[$IconID]["BitCount"]=$Ikona[$IconID]["Info"]["BitsPerPixel"];
+
+
+
+if($Ikona[$IconID]["BitCount"]>=24)
+{
+$img=imagecreatetruecolor($Ikona[$IconID]["Width"],$Ikona[$IconID]["Height"]);
+if($Ikona[$IconID]["BitCount"]==32):
+  $backcolor=imagecolorallocate($img,$alphaBgR,$alphaBgG,$alphaBgB);
+  imagefilledrectangle($img,0,0,$Ikona[$IconID]["Width"]-1,$Ikona[$IconID]["Height"]-1,$backcolor);
+endif;
+for($y=0;$y<$Ikona[$IconID]["Height"];$y++)
+for($x=0;$x<$Ikona[$IconID]["Width"];$x++)
+ {
+ $R=$Ikona[$IconID]["Data"][$x][$y]["r"];
+ $G=$Ikona[$IconID]["Data"][$x][$y]["g"];
+ $B=$Ikona[$IconID]["Data"][$x][$y]["b"];
+ if($Ikona[$IconID]["BitCount"]==32)
+ {
+ $Alpha=127-round($Ikona[$IconID]["Data"][$x][$y]["alpha"]*127/255);
+ if($Ikona[$IconID]["Maska"][$x][$y]==1) $Alpha=127;
+ $color=imagecolorexactalpha($img,$R,$G,$B,$Alpha);
+ if($color==-1) $color=imagecolorallocatealpha($img,$R,$G,$B,$Alpha);
+ }
+ else
+ {
+ $color=imagecolorexact($img,$R,$G,$B);
+ if($color==-1) $color=imagecolorallocate($img,$R,$G,$B);
+ };
+
+ imagesetpixel($img,$x,$y,$color);
+
+ };
+
+}
+else
+{
+$img=imagecreate($Ikona[$IconID]["Width"],$Ikona[$IconID]["Height"]);
+for($p=0;$p<count($Ikona[$IconID]["Paleta"]);$p++)
+ $Paleta[$p]=imagecolorallocate($img,$Ikona[$IconID]["Paleta"][$p]["r"],$Ikona[$IconID]["Paleta"][$p]["g"],$Ikona[$IconID]["Paleta"][$p]["b"]);
+
+for($y=0;$y<$Ikona[$IconID]["Height"];$y++)
+for($x=0;$x<$Ikona[$IconID]["Width"];$x++)
+ {
+ imagesetpixel($img,$x,$y,$Paleta[$Ikona[$IconID]["Data"][$x][$y]]);
+ };
+};
+$IsTransparent=false;  
+for($y=0;$y<$Ikona[$IconID]["Height"];$y++)
+for($x=0;$x<$Ikona[$IconID]["Width"];$x++)
+ if($Ikona[$IconID]["Maska"][$x][$y]==1)
+  {
+   $IsTransparent=true;
+   break;
+  };
+if($Ikona[$IconID]["BitCount"]==32)
+{
+ imagealphablending($img, false);
+ if(function_exists("imagesavealpha"))
+  imagesavealpha($img,true);
+};
+
+if($IsTransparent)
+ {
+  if(($Ikona[$IconID]["BitCount"]>=24)or(imagecolorstotal($img)>=256))
+   {
+   $img2=imagecreatetruecolor(imagesx($img),imagesy($img));
+   imagecopy($img2,$img,0,0,0,0,imagesx($img),imagesy($img));
+   imagedestroy($img);
+   $img=$img2;
+   imagetruecolortopalette($img,true,255);
+
+   };
+    $Pruhledna=imagecolorallocate($img,0,0,0);
+    for($y=0;$y<$Ikona[$IconID]["Height"];$y++)
+     for($x=0;$x<$Ikona[$IconID]["Width"];$x++)
+      if($Ikona[$IconID]["Maska"][$x][$y]==1)
+       {
+        imagesetpixel($img,$x,$y,$Pruhledna);
+       };
+  imagecolortransparent($img,$Pruhledna);
+ };
+
+return $img;
+
+
+};
+
+
+
+
+function jpexs_readIcon($filename,$id,&$Ikona)
+{
+global $jpexs_currentBit;
+
+$f=fopen($filename,"rb");
+
+fseek($f,6+$id*16);
+  $Width=jpexs_freadbyte($f);
+  $Height=jpexs_freadbyte($f);
+fseek($f,6+$id*16+12);
+$OffSet=jpexs_freaddword($f);
+fseek($f,$OffSet);
+
+$p=$id;
+
+  $Ikona[$p]["Info"]["HeaderSize"]=jpexs_freadlngint($f);
+  $Ikona[$p]["Info"]["ImageWidth"]=jpexs_freadlngint($f);
+  $Ikona[$p]["Info"]["ImageHeight"]=jpexs_freadlngint($f);
+  $Ikona[$p]["Info"]["NumberOfImagePlanes"]=jpexs_freadword($f);
+  $Ikona[$p]["Info"]["BitsPerPixel"]=jpexs_freadword($f);
+  $Ikona[$p]["Info"]["CompressionMethod"]=jpexs_freadlngint($f);
+  $Ikona[$p]["Info"]["SizeOfBitmap"]=jpexs_freadlngint($f);
+  $Ikona[$p]["Info"]["HorzResolution"]=jpexs_freadlngint($f);
+  $Ikona[$p]["Info"]["VertResolution"]=jpexs_freadlngint($f);
+  $Ikona[$p]["Info"]["NumColorUsed"]=jpexs_freadlngint($f);
+  $Ikona[$p]["Info"]["NumSignificantColors"]=jpexs_freadlngint($f);
+
+
+ $biBitCount=$Ikona[$p]["Info"]["BitsPerPixel"];
+
+ if($Ikona[$p]["Info"]["BitsPerPixel"]<=8)
+  {
+
+ $barev=pow(2,$biBitCount);
+
+  for($b=0;$b<$barev;$b++)
+    {
+    $Ikona[$p]["Paleta"][$b]["b"]=jpexs_freadbyte($f);
+    $Ikona[$p]["Paleta"][$b]["g"]=jpexs_freadbyte($f);
+    $Ikona[$p]["Paleta"][$b]["r"]=jpexs_freadbyte($f);
+    jpexs_freadbyte($f);
+    };
+
+$Zbytek=(4-ceil(($Width/(8/$biBitCount)))%4)%4;
+
+
+for($y=$Height-1;$y>=0;$y--)
+    {
+     $jpexs_currentBit=0;
+     for($x=0;$x<$Width;$x++)
+      {
+         $C=jpexs_freadbits($f,$biBitCount);
+         $Ikona[$p]["Data"][$x][$y]=$C;
+      };
+
+    if($jpexs_currentBit!=0) {jpexs_freadbyte($f);};
+    for($g=0;$g<$Zbytek;$g++)
+     jpexs_freadbyte($f);
+     };
+
+}
+elseif($biBitCount==24)
+{
+ $Zbytek=$Width%4;
+
+   for($y=$Height-1;$y>=0;$y--)
+    {
+     for($x=0;$x<$Width;$x++)
+      {
+       $B=jpexs_freadbyte($f);
+       $G=jpexs_freadbyte($f);
+       $R=jpexs_freadbyte($f);
+       $Ikona[$p]["Data"][$x][$y]["r"]=$R;
+       $Ikona[$p]["Data"][$x][$y]["g"]=$G;
+       $Ikona[$p]["Data"][$x][$y]["b"]=$B;
+      }
+    for($z=0;$z<$Zbytek;$z++)
+     jpexs_freadbyte($f);
+   };
+}
+elseif($biBitCount==32)
+{
+ $Zbytek=$Width%4;
+
+   for($y=$Height-1;$y>=0;$y--)
+    {
+     for($x=0;$x<$Width;$x++)
+      {
+       $B=jpexs_freadbyte($f);
+       $G=jpexs_freadbyte($f);
+       $R=jpexs_freadbyte($f);
+       $Alpha=jpexs_freadbyte($f);
+       $Ikona[$p]["Data"][$x][$y]["r"]=$R;
+       $Ikona[$p]["Data"][$x][$y]["g"]=$G;
+       $Ikona[$p]["Data"][$x][$y]["b"]=$B;
+       $Ikona[$p]["Data"][$x][$y]["alpha"]=$Alpha;
+      }
+    for($z=0;$z<$Zbytek;$z++)
+     jpexs_freadbyte($f);
+   };
+};
+
+
+//Maska
+$Zbytek=(4-ceil(($Width/(8)))%4)%4;
+for($y=$Height-1;$y>=0;$y--)
+    {
+     $jpexs_currentBit=0;
+     for($x=0;$x<$Width;$x++)
+      {
+         $C=jpexs_freadbits($f,1);
+         $Ikona[$p]["Maska"][$x][$y]=$C;
+      };
+    if($jpexs_currentBit!=0) {jpexs_freadbyte($f);};
+    for($g=0;$g<$Zbytek;$g++)
+     jpexs_freadbyte($f);
+     };
+//--------------
+
+fclose($f);
+
+};
+
+function jpexs_GetIconsInfo($filename)
+{
+global $jpexs_currentBit;
+
+$f=fopen($filename,"rb");
+
+$Reserved=jpexs_freadword($f);
+$Type=jpexs_freadword($f);
+$Count=jpexs_freadword($f);
+for($p=0;$p<$Count;$p++)
+ {
+  $Ikona[$p]["Width"]=jpexs_freadbyte($f);
+  $Ikona[$p]["Height"]=jpexs_freadbyte($f);
+  $Ikona[$p]["ColorCount"]=jpexs_freadword($f);
+ if($Ikona[$p]["ColorCount"]==0) $Ikona[$p]["ColorCount"]=256;
+  $Ikona[$p]["Planes"]=jpexs_freadword($f);
+  $Ikona[$p]["BitCount"]=jpexs_freadword($f);
+  $Ikona[$p]["BytesInRes"]=jpexs_freaddword($f);
+  $Ikona[$p]["ImageOffset"]=jpexs_freaddword($f);
+ };
+
+if(!feof($f)):
+  for($p=0;$p<$Count;$p++)
+   {
+    fseek($f,$Ikona[$p]["ImageOffset"]+14);
+    $Ikona[$p]["Info"]["BitsPerPixel"]=jpexs_freadword($f);
+   };
+endif;
+fclose($f);
+return $Ikona;
+};
+
+
+
+
+/**
+ * Reads image from a icon in exe file
+ * @param string $filename Target exefile
+ * @param int $icoIndex Index of the icon in exefile
+ * @param int $icoColorCount Icon color count (For multiple icons ico file) - 2,16,256, ICO_TRUE_COLOR, ICO_XP_COLOR or ICO_MAX_COLOR
+ * @param int $icoSize Icon width (For multiple icons ico file) or ICO_MAX_SIZE
+ * @param int $alphaBgR Background color R value for alpha-channel images (Default is White)
+ * @param int $alphaBgG Background color G value for alpha-channel images (Default is White)
+ * @param int $alphaBgB Background color B value for alpha-channel images (Default is White)
+ * @return resource Image resource or false on error
+ */
+function imageCreateFromExeIco($filename,$icoIndex,$icoColorCount=16,$icoSize=16,$alphaBgR=255,$alphaBgG=255,$alphaBgB=255)
+{
+ $ok=saveExeIcon($filename,"icotemp.dat",$icoIndex);
+ if(!$ok):
+  $im=false;
+ else:
+   $im=imageCreateFromIco("icotemp.dat",$icoColorCount,$icoSize,$alphaBgR,$alphaBgG,$alphaBgB);
+   unlink("icotemp.dat");
+ endif;
+ return $im;
+};
+
+
+/**
+ * Saves icon(s) from the exe file
+ * @global int $jpexs_StartOfRsrc Internal reserved variable
+ * @global int $jpexs_ImageBase Internal reserved variable
+ * @global int $jpexs_ResVirtualAddress Internal reserved variable
+ * @param string $filename Target exefile
+ * @param string $icoFileNameOrPath Filename to save ico or path (Default "") Path if you want more than 1 icon. If "", the filename is "$icoIndex.ico"
+ * @param int|array $iconIndex Index(es) of the icon in exefile  (Default -1) If -1, all icons are saved, Can be an array of indexes.
+ * @return boolean True on successful save
+ */
+function saveExeIcon($filename,$icoFileNameOrPath="",$iconIndex=-1) /*-1 for all,or can be array*/
+{
+  global $jpexs_f,$jpexs_StartOfRsrc,$jpexs_ImageBase,$jpexs_ResVirtualAddress;
+  $jpexs_f=fopen($filename,"r");
+  $MZ=fread($jpexs_f,2);
+  if($MZ!="MZ") NotValidExe();
+  fseek($jpexs_f,60);
+  $OffsetToNewHeader=jpexs_freaddword($jpexs_f);
+  fseek($jpexs_f,$OffsetToNewHeader);
+  $PE=fread($jpexs_f,2);
+  if($PE!="PE") NotValidExe();
+  fread($jpexs_f,4);
+  $NumberOfSections=jpexs_freadword($jpexs_f);
+  fseek($jpexs_f,ftell($jpexs_f)+12);
+  $SizeOfOptionalHeader=jpexs_freadword($jpexs_f);
+  $PosMagic=ftell($jpexs_f)+2;
+  fseek($jpexs_f,$PosMagic+$SizeOfOptionalHeader);
+
+  for($p=0;$p<$NumberOfSections;$p++):
+    $SectionName[$p]=trim(fread($jpexs_f,8));
+    $VirtualSize[$p]=jpexs_freaddword($jpexs_f);
+    $VirtualAddress[$p]=jpexs_freaddword($jpexs_f);
+    $PhysicalSize[$p]=jpexs_freaddword($jpexs_f);
+    $PhysicalOffset[$p]=jpexs_freaddword($jpexs_f);
+    fread($jpexs_f,16);
+    if($SectionName[$p]==".rsrc"):
+      $jpexs_ResVirtualAddress=$VirtualAddress[$p];
+      fseek($jpexs_f,$PhysicalOffset[$p]);
+      $jpexs_StartOfRsrc=$PhysicalOffset[$p];
+      jpexs_readResDirectoryEntry($R,$PhysicalOffset[$p]);
+      $IconCount=null;
+      $Ikona=null;
+      while (list ($key, $val) = each ($R["Subdir"])):
+        if($key==14):
+          $r=0;
+          while (list ($key2, $val2) = each ($R["Subdir"][$key]["Subdir"])):
+             while (list ($key3, $val3) = each ($R["Subdir"][$key]["Subdir"][$key2]["Subdir"])):
+               fseek($jpexs_f,$val3["DataOffset"]);
+               $Reserved=jpexs_freadword($jpexs_f);
+               $Type=jpexs_freadword($jpexs_f);
+               $ic=jpexs_freadword($jpexs_f);
+               $IconCount[]=$ic;
+               for($s=0;$s<$ic;$s++)
+                {
+                 $Ikona[$r][$s]["Width"]=jpexs_freadbyte($jpexs_f);
+                 $Ikona[$r][$s]["Height"]=jpexs_freadbyte($jpexs_f);
+                 $Ikona[$r][$s]["ColorCount"]=jpexs_freadword($jpexs_f);
+                 $Ikona[$r][$s]["Planes"]=jpexs_freadword($jpexs_f);
+                 $Ikona[$r][$s]["BitCount"]=jpexs_freadword($jpexs_f);
+                 $Ikona[$r][$s]["BytesInRes"]=jpexs_freaddword($jpexs_f);
+                 $Ikona[$r][$s]["IconId"]=jpexs_freadword($jpexs_f);
+                };
+               fseek($jpexs_f,$val3["DataOffset"]);
+               $r++;
+             endwhile;
+          endwhile;
+        endif;
+      endwhile;
+
+      reset ($R["Subdir"]);
+
+      while (list ($key, $val) = each ($R["Subdir"])):
+        if($key==3):
+          while (list ($key2, $val2) = each ($R["Subdir"][$key]["Subdir"])):
+          for($r=0;$r<count($Ikona);$r++):
+           for($s=0;$s<count($Ikona[$r]);$s++):
+             while (list ($key3, $val3) = each ($R["Subdir"][$key]["Subdir"][$Ikona[$r][$s]["IconId"]]["Subdir"])):
+               if(($iconIndex==$r)or($iconIndex==-1)or((is_array($iconIndex))and(in_array($r,$iconIndex)))):
+                 fseek($jpexs_f,$val3["DataOffset"]);
+                 $Ikona[$r][$s]["Data"]=fread($jpexs_f,$val3["DataSize"]);
+                 $Ikona[$r][$s]["DataSize"]=$val3["DataSize"];
+               endif;
+             endwhile;
+           endfor;
+           endfor;
+          endwhile;
+        endif;
+      endwhile;
+      $ok=false;
+      for($r=0;$r<count($Ikona);$r++):
+        if(($iconIndex==$r)or($iconIndex==-1)or((is_array($iconIndex))and(in_array($r,$iconIndex)))):
+          $savefile=$icoFileNameOrPath;
+          if($icoFileNameOrPath=="")
+           {
+             $savefile="$r.ico";
+           }
+           else
+           {
+            if(($iconIndex==-1)or(is_array($iconIndex)))
+              $savefile=$icoFileNameOrPath."$r.ico";
+           };
+          $f2=fopen($savefile,"w");
+          fwrite($f2,jpexs_inttoword(0));
+          fwrite($f2,jpexs_inttoword(1));
+          fwrite($f2,jpexs_inttoword(count($Ikona[$r])));
+          $Offset=6+16*count($Ikona[$r]);
+          for($s=0;$s<count($Ikona[$r]);$s++):
+            fwrite($f2,jpexs_inttobyte($Ikona[$r][$s]["Width"]));
+            fwrite($f2,jpexs_inttobyte($Ikona[$r][$s]["Height"]));
+            fwrite($f2,jpexs_inttoword($Ikona[$r][$s]["ColorCount"]));
+            fwrite($f2,jpexs_inttoword($Ikona[$r][$s]["Planes"]));
+            fwrite($f2,jpexs_inttoword($Ikona[$r][$s]["BitCount"]));
+            fwrite($f2,jpexs_inttodword($Ikona[$r][$s]["BytesInRes"]));
+            fwrite($f2,jpexs_inttodword($Offset));
+            $Offset+=$Ikona[$r][$s]["DataSize"];
+          endfor;
+          for($s=0;$s<count($Ikona[$r]);$s++):
+            fwrite($f2,$Ikona[$r][$s]["Data"]);
+          endfor;
+          fclose($f2);
+          $ok=true;
+        endif;
+      endfor;
+      return $ok;
+    endif;
+  endfor;
+
+  fclose($jpexs_f);
+};
+
+/**
+ * Internal function for reading exe icons
+ */
+function jpexs_readResDirectoryEntry(&$parentRes,$offset)
+{
+global $jpexs_f,$jpexs_StartOfRsrc,$jpexs_ImageBase,$jpexs_ResVirtualAddress;
+$lastPos=ftell($jpexs_f);
+$Res=null;
+fseek($jpexs_f,$offset);
+//IMAGE_RESOURCE_DIRECTORY
+      $Characteristics=jpexs_freaddword($jpexs_f);
+      $TimeDateStamp=jpexs_freaddword($jpexs_f);
+      $MajorVersion=jpexs_freadword($jpexs_f);
+      $MinorVersion=jpexs_freadword($jpexs_f);
+      $NumberOfNamedEntries=jpexs_freadword($jpexs_f);
+      $NumberOfIdEntries=jpexs_freadword($jpexs_f);
+      for($q=0;$q<$NumberOfNamedEntries+$NumberOfIdEntries;$q++):
+        //IMAGE_RESOURCE_DIRECTORY_ENTRY
+        $ResName=jpexs_freaddword($jpexs_f);
+        $lastPos2=ftell($jpexs_f);
+        if($ResName>=0x80000000):
+          //String Name
+          $ResNameOffset=$ResName-0x80000000;
+          fseek($jpexs_f,$jpexs_StartOfRsrc+$ResNameOffset);
+          $StringLength=jpexs_freadword($jpexs_f);
+          $Identificator=(fread($jpexs_f,$StringLength*2));
+          fseek($jpexs_f,$lastPos2);
+        else:
+          //Integer Id
+          $Identificator=$ResName;
+        endif;
+
+        $ResOffsetToData=jpexs_freaddword($jpexs_f);
+        if($ResOffsetToData>=0x80000000):
+          $SubResOffset=$ResOffsetToData-0x80000000;
+          jpexs_readResDirectoryEntry($Res["$Identificator"],$jpexs_StartOfRsrc+$SubResOffset);
+        else:
+          $RawDataOffset=$ResOffsetToData;
+          $lastPos2=ftell($jpexs_f);
+          fseek($jpexs_f,$jpexs_StartOfRsrc+$RawDataOffset);
+          //IMAGE_RESOURCE_DATA_ENTRY
+          $OffsetToData=jpexs_freaddword($jpexs_f);
+          $Res["$Identificator"]["DataOffset"]=$jpexs_StartOfRsrc-$jpexs_ResVirtualAddress+$OffsetToData;
+          $Res["$Identificator"]["DataSize"]=jpexs_freaddword($jpexs_f);
+          $CodePage=jpexs_freaddword($jpexs_f);
+          $Reserved=jpexs_freaddword($jpexs_f);
+          fseek($jpexs_f,$lastPos2);
+        endif;
+      endfor;
+fseek($jpexs_f,$lastPos);
+$parentRes["Subdir"]=$Res;
+};
+
+/**
+ * Creates ico file from image resource(s)
+ * @param resource|array $images Target Image resource (Can be array of image resources)
+ * @param string $filename Target ico file to save icon to, If ommited or "", image is written to snadard output - use header("Content-type: image/x-icon"); */
+function imageIco($images,$filename="")
+{
+
+if(is_array($images))
+{
+$ImageCount=count($images);
+$Image=$images;
+}
+else
+{
+$Image[0]=$images;
+$ImageCount=1;
+};
+
+
+$WriteToFile=false;
+
+if($filename!="")
+{
+$WriteToFile=true;
+};
+
+
+$ret="";
+
+$ret.=jpexs_inttoword(0); //PASSWORD
+$ret.=jpexs_inttoword(1); //SOURCE
+$ret.=jpexs_inttoword($ImageCount); //ICONCOUNT
+
+
+for($q=0;$q<$ImageCount;$q++)
+{
+$img=$Image[$q];
+
+$Width=imagesx($img);
+$Height=imagesy($img);
+
+$ColorCount=imagecolorstotal($img);
+
+$Transparent=imagecolortransparent($img);
+$IsTransparent=$Transparent!=-1;
+
+
+if($IsTransparent) $ColorCount--;
+
+if($ColorCount==0) {$ColorCount=0; $BitCount=24;};
+if(($ColorCount>0)and($ColorCount<=2)) {$ColorCount=2; $BitCount=1;};
+if(($ColorCount>2)and($ColorCount<=16)) { $ColorCount=16; $BitCount=4;};
+if(($ColorCount>16)and($ColorCount<=256)) { $ColorCount=0; $BitCount=8;};
+
+
+
+
+
+//ICONINFO:
+$ret.=jpexs_inttobyte($Width);//
+$ret.=jpexs_inttobyte($Height);//
+$ret.=jpexs_inttobyte($ColorCount);//
+$ret.=jpexs_inttobyte(0);//RESERVED
+
+$Planes=0;
+if($BitCount>=8) $Planes=1;
+
+$ret.=jpexs_inttoword($f,$Planes);//PLANES
+if($BitCount>=8) $WBitCount=$BitCount;
+if($BitCount==4) $WBitCount=0;
+if($BitCount==1) $WBitCount=0;
+$ret.=jpexs_inttoword($WBitCount);//BITS
+
+$Zbytek=(4-($Width/(8/$BitCount))%4)%4;
+$ZbytekMask=(4-($Width/8)%4)%4;
+
+$PalSize=0;
+
+$Size=40+($Width/(8/$BitCount)+$Zbytek)*$Height+(($Width/8+$ZbytekMask) * $Height);
+if($BitCount<24)
+ $Size+=pow(2,$BitCount)*4;
+$IconId=1;
+$ret.=jpexs_inttodword($Size); //SIZE
+$OffSet=6+16*$ImageCount+$FullSize;
+$ret.=jpexs_inttodword(6+16*$ImageCount+$FullSize);//OFFSET
+$FullSize+=$Size;
+//-------------
+
+};
+
+
+for($q=0;$q<$ImageCount;$q++)
+{
+$img=$Image[$q];
+$Width=imagesx($img);
+$Height=imagesy($img);
+$ColorCount=imagecolorstotal($img);
+
+$Transparent=imagecolortransparent($img);
+$IsTransparent=$Transparent!=-1;
+
+if($IsTransparent) $ColorCount--;
+if($ColorCount==0) {$ColorCount=0; $BitCount=24;};
+if(($ColorCount>0)and($ColorCount<=2)) {$ColorCount=2; $BitCount=1;};
+if(($ColorCount>2)and($ColorCount<=16)) { $ColorCount=16; $BitCount=4;};
+if(($ColorCount>16)and($ColorCount<=256)) { $ColorCount=0; $BitCount=8;};
+
+
+
+//ICONS
+$ret.=jpexs_inttodword(40);//HEADSIZE
+$ret.=jpexs_inttodword($Width);//
+$ret.=jpexs_inttodword(2*$Height);//
+$ret.=jpexs_inttoword(1); //PLANES
+$ret.=jpexs_inttoword($BitCount);   //
+$ret.=jpexs_inttodword(0);//Compress method
+
+
+$ZbytekMask=($Width/8)%4;
+
+$Zbytek=($Width/(8/$BitCount))%4;
+$Size=($Width/(8/$BitCount)+$Zbytek)*$Height+(($Width/8+$ZbytekMask) * $Height);
+
+$ret.=jpexs_inttodword($Size);//SIZE
+
+$ret.=jpexs_inttodword(0);//HPIXEL_M
+$ret.=jpexs_inttodword(0);//V_PIXEL_M
+$ret.=jpexs_inttodword($ColorCount); //UCOLORS
+$ret.=jpexs_inttodword(0); //DCOLORS
+//---------------
+
+
+$CC=$ColorCount;
+if($CC==0) $CC=256;
+
+if($BitCount<24)
+{
+ $ColorTotal=imagecolorstotal($img);
+ if($IsTransparent) $ColorTotal--;
+
+ for($p=0;$p<$ColorTotal;$p++)
+  {
+   $color=imagecolorsforindex($img,$p);
+   $ret.=jpexs_inttobyte($color["blue"]);
+   $ret.=jpexs_inttobyte($color["green"]);
+   $ret.=jpexs_inttobyte($color["red"]);
+   $ret.=jpexs_inttobyte(0); //RESERVED
+  };
+
+ $CT=$ColorTotal;
+ for($p=$ColorTotal;$p<$CC;$p++)
+  {
+   $ret.=jpexs_inttobyte(0);
+   $ret.=jpexs_inttobyte(0);
+   $ret.=jpexs_inttobyte(0);
+   $ret.=jpexs_inttobyte(0); //RESERVED
+  };
+};
+
+
+
+
+
+
+if($BitCount<=8)
+{
+
+ for($y=$Height-1;$y>=0;$y--)
+ {
+  $bWrite="";
+  for($x=0;$x<$Width;$x++)
+   {
+   $color=imagecolorat($img,$x,$y);
+   if($color==$Transparent)
+    $color=imagecolorexact($img,0,0,0);
+   if($color==-1) $color=0;
+   if($color>pow(2,$BitCount)-1) $color=0;
+
+   $bWrite.=jpexs_decbinx($color,$BitCount);
+   if(strlen($bWrite)==8)
+    {
+     $ret.=jpexs_inttobyte(bindec($bWrite));
+     $bWrite="";
+    };
+   };
+
+  if((strlen($bWrite)<8)and(strlen($bWrite)!=0))
+    {
+     $sl=strlen($bWrite);
+     for($t=0;$t<8-$sl;$t++)
+      $sl.="0";
+     $ret.=jpexs_inttobyte(bindec($bWrite));
+    };
+  for($z=0;$z<$Zbytek;$z++)
+   $ret.=jpexs_inttobyte(0);
+ };
+};
+
+
+
+if($BitCount>=24)
+{
+ for($y=$Height-1;$y>=0;$y--)
+ {
+  for($x=0;$x<$Width;$x++)
+   {
+   $color=imagecolorsforindex($img,imagecolorat($img,$x,$y));
+   $ret.=jpexs_inttobyte($color["blue"]);
+   $ret.=jpexs_inttobyte($color["green"]);
+   $ret.=jpexs_inttobyte($color["red"]);
+   if($BitCount==32)
+    $ret.=jpexs_inttobyte(0);//Alpha for ICO_XP_COLORS
+   };
+  for($z=0;$z<$Zbytek;$z++)
+   $ret.=jpexs_inttobyte(0);
+ };
+};
+
+
+//MASK
+
+ for($y=$Height-1;$y>=0;$y--)
+ {
+  $byteCount=0;
+  $bOut="";
+  for($x=0;$x<$Width;$x++)
+   {
+    if(($Transparent!=-1)and(imagecolorat($img,$x,$y)==$Transparent))
+     {
+      $bOut.="1";
+     }
+     else
+     {
+      $bOut.="0";
+     };
+   };
+  for($p=0;$p<strlen($bOut);$p+=8)
+  {
+   $byte=bindec(substr($bOut,$p,8));
+   $byteCount++;
+   $ret.=jpexs_inttobyte($byte);
+  };
+ $Zbytek=$byteCount%4;
+  for($z=0;$z<$Zbytek;$z++)
+   {
+   $ret.=jpexs_inttobyte(0xff);
+   };
+ };
+
+//------------------
+
+};//q
+
+
+
+
+
+if($WriteToFile)
+{
+ $f=fopen($filename,"w");
+ fwrite($f,$ret);
+ fclose($f);
+}
+else
+{
+ echo $ret;
+};
+
+};
+
+
+
+
+/*
+* Internal functions:
+*-------------------------
+* jpexs_inttobyte($n) - returns chr(n)
+* jpexs_inttodword($n) - returns dword (n)
+* jpexs_inttoword($n) - returns word(n)
+* jpexs_freadbyte($file) - reads 1 byte from $file
+* jpexs_freadword($file) - reads 2 bytes (1 word) from $file
+* jpexs_freaddword($file) - reads 4 bytes (1 dword) from $file
+* jpexs_freadlngint($file) - same as freaddword($file)
+* jpexs_decbin8($d) - returns binary string of d zero filled to 8
+* jpexs_RetBits($byte,$start,$len) - returns bits $start->$start+$len from $byte
+* jpexs_freadbits($file,$count) - reads next $count bits from $file
+*/
+
+
+function jpexs_decbin8($d)
+{
+return jpexs_decbinx($d,8);
+};
+
+function jpexs_decbinx($d,$n)
+{
+$bin=decbin($d);
+$sbin=strlen($bin);
+for($j=0;$j<$n-$sbin;$j++)
+ $bin="0$bin";
+return $bin;
+};
+
+function jpexs_retBits($byte,$start,$len)
+{
+$bin=jpexs_decbin8($byte);
+$r=bindec(substr($bin,$start,$len));
+return $r;
+
+};
+
+
+
+$jpexs_currentBit=0;
+function jpexs_freadbits($f,$count)
+{
+ global $jpexs_currentBit,$jpexs_SMode;
+ $Byte=jpexs_freadbyte($f);
+ $LastCBit=$jpexs_currentBit;
+ $jpexs_currentBit+=$count;
+ if($jpexs_currentBit==8)
+  {
+   $jpexs_currentBit=0;
+  }
+ else
+  {
+   fseek($f,ftell($f)-1);
+  };
+ return jpexs_retBits($Byte,$LastCBit,$count);
+};
+
+
+function jpexs_freadbyte($f)
+{
+ return ord(fread($f,1));
+};
+
+function jpexs_freadword($f)
+{
+ $b1=jpexs_freadbyte($f);
+ $b2=jpexs_freadbyte($f);
+ return $b2*256+$b1;
+};
+
+
+function jpexs_freadlngint($f)
+{
+return jpexs_freaddword($f);
+};
+
+function jpexs_freaddword($f)
+{
+ $b1=jpexs_freadword($f);
+ $b2=jpexs_freadword($f);
+ return $b2*65536+$b1;
+};
+
+function jpexs_inttobyte($n)
+{
+return chr($n);
+};
+
+function jpexs_inttodword($n)
+{
+return chr($n & 255).chr(($n >> 8) & 255).chr(($n >> 16) & 255).chr(($n >> 24) & 255);
+};
+
+function jpexs_inttoword($n)
+ {
+ return chr($n & 255).chr(($n >> 8) & 255);
+ };
+
+?>
\ No newline at end of file
Index: wp-admin/js/wp-favicon.dev.js
===================================================================
--- wp-admin/js/wp-favicon.dev.js	(revision 0)
+++ wp-admin/js/wp-favicon.dev.js	(working copy)
@@ -0,0 +1,12 @@
+(function($){
+    $('#faviconfile').change(function(){
+        // check the file extention
+        if (! $.inArray( $(this).val().split('.').pop().toLowerCase() , /* valid file extentions */ ['gif','png','jpg','jpeg'] ) ) 
+            $('#favicon-invalid-filetype').show();
+        else
+        {
+            $('#faviconupload').submit();
+        }
+    });
+
+})(jQuery);
Index: wp-admin/js/wp-favicon.js
===================================================================
--- wp-admin/js/wp-favicon.js	(revision 0)
+++ wp-admin/js/wp-favicon.js	(working copy)
@@ -0,0 +1,12 @@
+(function($){
+    $('#faviconfile').change(function(){
+        // check the file extention
+        if (! $.inArray( $(this).val().split('.').pop().toLowerCase() , /* valid file extentions */ ['gif','png','jpg','jpeg'] ) ) 
+            $('#favicon-invalid-filetype').show();
+        else
+        {
+            $('#faviconupload').submit();
+        }
+    });
+
+})(jQuery);
Index: wp-admin/options-general.php
===================================================================
--- wp-admin/options-general.php	(revision 19934)
+++ wp-admin/options-general.php	(working copy)
@@ -81,6 +81,8 @@
 	'<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
 );
 
+wp_enqueue_script('wp-favicon');
+
 include('./admin-header.php');
 ?>
 
@@ -88,6 +90,30 @@
 <?php screen_icon(); ?>
 <h2><?php echo esc_html( $title ); ?></h2>
 
+<form action="<?php echo admin_url('favicon-upload.php')?>" method="post" enctype="multipart/form-data" id="faviconupload">
+	<input type="hidden" name="action" value="wp_upload_favicon" />
+
+	<table class="form-table">
+		<tr valign="top">
+			<th scope="row"><label for="sitefavicon"><?php _e('Favicon') ?></label></th>
+			<td>
+				<?php
+					// display the icon and the remove link if appropriate
+					if ( has_custom_favicon() ){
+						if ( $thumbnail = get_favicon_img() ) echo $thumbnail;
+						echo "\t" . '<input type="submit" name="REMOVE_FAVICON" value="Remove Favicon" id="remove-favicon-button" />';
+						echo ' <span class="description no-js">' . __( 'The image at right is used as your site\'s favicon. To change it, first remove this one.' ) . '</span>';
+					} else {
+				?>
+					<input class="button" name="avatarfile" type="file" id="faviconfile" size="20" />
+					<p class="submit no-js hide-if-js"><input type="submit" name="Submit" value="Upload Image &raquo;" id="faviconsubmit" /></p>
+					<span class="description no-js"><?php _e('Click to upload your own custom icon ("favicon") for your blog. You\'ll be able to crop and scale it once it\'s uploaded.') ?></span>
+				<?php } ?>
+			</td>
+		</tr>
+	</table>
+</form>
+
 <form method="post" action="options.php">
 <?php settings_fields('general'); ?>
 
Index: wp-includes/functions.php
===================================================================
--- wp-includes/functions.php	(revision 19934)
+++ wp-includes/functions.php	(working copy)
@@ -1845,7 +1845,7 @@
 		'png' => 'image/png',
 		'bmp' => 'image/bmp',
 		'tif|tiff' => 'image/tiff',
-		'ico' => 'image/x-icon',
+		'ico' => 'image/vnd.microsoft.icon',
 		'asf|asx|wax|wmv|wmx' => 'video/asf',
 		'avi' => 'video/avi',
 		'divx' => 'video/divx',
Index: wp-includes/general-template.php
===================================================================
--- wp-includes/general-template.php	(revision 19934)
+++ wp-includes/general-template.php	(working copy)
@@ -1587,6 +1587,134 @@
 }
 
 /**
+ * Convenience function that echoes the HTML for the site's favicon icon.
+ * By default, automatically included in the header via the 'wp_head' action, which can be removed by themes if a custom favicon is desired.
+ * 
+ * @uses generate_site_favicon_html() to do the actual heavy lifting
+ */
+function site_favicon(){
+	echo generate_site_favicon_html();
+}
+add_action( 'wp_head', 'site_favicon' );
+add_action( 'admin_head', 'site_favicon' );
+
+/**
+ * Return the HTML for the site's favicon icon, if such has been defined.
+ * 
+ * @uses get_site_favicon_uri();
+ * 
+ * Includes the conditional tag wrapper for an IE (.ico) version. 
+ */
+function generate_site_favicon_html() {
+	$ie_favicon_uri = get_site_favicon_uri( 'ico' );
+	$favicon_uri = get_site_favicon_uri();
+
+	$content = "";
+	if (! is_wp_error( $ie_favicon_uri ) && ! is_wp_error( $favicon_uri ) ){
+
+		$content .= <<<FAVICON_HTML
+<!--Favicon (via 'wp_head' action) -->
+<!--[if IE]>
+<link rel="shortcut icon" href="{$ie_favicon_uri}" />
+<![endif]-->
+<!--[if !IE]>-->
+<link href="{$favicon_uri}" rel="icon" type="image/png" />
+<!--<![endif]-->
+FAVICON_HTML;
+    }
+	return $content;
+}
+
+/**
+ * Get the attachment post object associated with the current site favicon, based on the 'sitefavicon' option
+ * 
+ * @param string $format Default 'png'. Format of the file we're looking for
+ * @return object If found, returns the post object; if not, a WP_Error object
+ */
+function get_site_favicon_attachment( $format = 'png' ){
+	$favicon_basename = get_option ( 'sitefavicon' ); 
+	
+	if ( ! empty( $favicon_basename ) ) {
+		$favicon_fullname = $favicon_basename . '-' . $format;
+		
+		$posts = get_posts( array( 'name' => $favicon_fullname, 'post_type' => 'attachment' ) );
+		if ( $posts[0] ){
+			return $posts[0];
+		} else {
+			return new WP_Error( 'attachment_missing', __( "No attachment for '$favicon_fullname' was found." ) );
+		}
+	} else {
+		return new WP_Error( 'not_defined', __( "No favicon file provided." ) );
+	}
+}
+
+/**
+ * Returns the URI for the site's favicon based on the option set in  Admin > Settings > General.
+ * 
+ * @param string $format png|ico default 'png'. Use 'ico' for serving up an IE-compatible ICO file
+ * @return string fully qualified URI 
+ */
+function get_site_favicon_uri( $format = 'png' ){
+	/** @TODO provide error checking for validity of $format and $size */
+	$favicon_attachment = get_site_favicon_attachment( $format );
+	
+	/** @TODO provide the ability to define a 'default' favicon that would be distributed with fresh WP installations */
+	if ( ! is_wp_error( $favicon_attachment ) ) {
+		return wp_get_attachment_url( $favicon_attachment->ID );
+	}
+	
+	// We get here because of an error condition
+	/** @TODO default to the theme's favicon **/
+	// ATM do nothing (so URI is blank, rather than a WP_Error)
+}
+
+/**
+ * Gets the path to the favicon file, or returns a WP_Error
+ * @param string $format Default 'png'
+ * @return mixed File string or WP_Error object 
+ */
+function get_site_favicon_file( $format = 'png' ){
+	$favicon_attachment = get_site_favicon_attachment( $format );
+	
+	/** @TODO provide the ability to define a 'default' favicon that would be distributed with fresh WP installations */
+	if ( ! is_wp_error( $favicon_attachment ) ) {
+		return get_attached_file( $favicon_attachment->ID );
+	} else {
+		return $favicon_attachment; // returns the WP_Error object
+	}
+}
+
+/**
+ * Returns true or false depending on whether a custom favicon has been defined in Admin
+ * @return boolean 
+ */
+function has_custom_favicon(){
+	$favicon_basename = get_option ( 'sitefavicon' ); 
+	/** @TODO more robust checking: don't just check that the option has been set: check that the file exists */
+	return ( ! empty( $favicon_basename ) );
+}
+
+/**
+ * Returns an HTML <img> tag populated with the site favicon, in the format specified (usually PNG)
+ * @param string $format Default 'png'. Valid values are 'png', 'bmp' (note 'ico' is NOT valid)
+ * @return mixed Returns HTML <img> tag or WP_Error if invalid format given. Returns nothing if the file is missing. 
+ */
+function get_favicon_img( $format = 'png' ){
+	if (in_array( strtolower( $format ), array( 'png', 'bmp' ) ) ){
+		// Does the file actually exist?
+		$file = get_site_favicon_file( $format );
+		if (! is_wp_error( $file ) && file_exists( $file ) ){
+			$src = get_site_favicon_uri( $format );
+			if (!is_wp_error( $src ) ){
+				return '<img src="' . $src . '" alt="' . _x( 'Site favicon thumbnail', 'Thumbnail image accessibility text' ) .'" />';
+			}
+		}
+	} else {
+		return new WP_Error( 'invalid_file_format', __( 'Invalid file format. Valid formats are "png", "bmp".' ) );
+	}
+}
+
+/**
  * Display the links to the general feeds.
  *
  * @since 2.8.0
Index: wp-includes/script-loader.php
===================================================================
--- wp-includes/script-loader.php	(revision 19934)
+++ wp-includes/script-loader.php	(working copy)
@@ -88,6 +88,8 @@
 
 	$scripts->add( 'wp-fullscreen', "/wp-admin/js/wp-fullscreen$suffix.js", array('jquery'), false, 1 );
 
+	$scripts->add( 'wp-favicon', "/wp-admin/js/wp-favicon$suffix.js", array('jquery'), false, 1 );
+
 	$scripts->add( 'prototype', '/wp-includes/js/prototype.js', array(), '1.6.1');
 
 	$scripts->add( 'wp-ajax-response', "/wp-includes/js/wp-ajax-response$suffix.js", array('jquery'), false, 1 );
