Index: wp-admin/css/wp-admin.dev.css
===================================================================
--- wp-admin/css/wp-admin.dev.css	(revision 20163)
+++ wp-admin/css/wp-admin.dev.css	(working copy)
@@ -4852,7 +4852,26 @@
 	vertical-align: middle;
 }
 
+.options-general-php img.favicon {
+	vertical-align:middle;
+	
+	-moz-box-shadow:    1px 1px 3px 0px #aaa;
+	-webkit-box-shadow: 1px 1px 3px 0px #aaa;
+	box-shadow:         1px 1px 3px 0px #aaa;
+}
 
+#remove-favicon-button {
+	margin-left:5px;
+}
+
+/* Favicon upload error messages */
+#favicon-invalid-filetype-error {
+	display:none;
+	color:red;
+	font-style: italic;
+}
+
+
 /*------------------------------------------------------------------------------
   21.0 - Admin Footer
 ------------------------------------------------------------------------------*/
Index: wp-admin/favicon-upload.php
===================================================================
--- wp-admin/favicon-upload.php	(revision 0)
+++ wp-admin/favicon-upload.php	(working copy)
@@ -0,0 +1,1363 @@
+<?php
+/**
+ * Handles the uploading, cropping and scaling of favicons.
+ * 
+ * @package WordPress
+ * @subpackage Administration
+ * @since 3.4.1
+ */
+
+// Bootstrap admin and all its goodies
+require_once( 'admin.php' );
+
+define( 'DEFAULT_FAVICON_SIZE', 32 ); // Width (and height) of the favicon (in pixels). Use 'favicon_size' filter to over-ride this value
+
+if (! current_user_can('manage_options') )
+    wp_die( __( 'Cheatin&#8217; eh?' ) );
+
+check_admin_referer( 'favicon_upload-options' );
+
+$title = __( 'Crop Favicon' );
+$parent_file = 'options-general.php';
+
+// Main workflow
+// Favicon removal
+if ( isset( $_REQUEST['REMOVE_FAVICON'] ) ) {
+	remove_favicon();
+	wp_redirect( admin_url( $parent_file ) );
+	exit;
+}
+
+// Process crop operation
+if ( isset( $_POST['CROP_AND_SAVE'] ) ) {
+	if ( isset( $_POST['attachment_id'] ) && is_numeric( $_POST['attachment_id'] ) ){
+		$favicon_image_res = process_crop_thumbnail( $_POST['attachment_id'] );
+		if (! is_wp_error( $favicon_image_res ) ){
+			if (! is_wp_error( generate_favicon_formats( $favicon_image_res, $_POST['attachment_id'] ) ) ){
+				// And save the basename out to options.
+				update_option( 'sitefavicon', basename( generate_favicon_basename( $_POST['attachment_id'] ) ) );
+				// We're done.
+				wp_redirect( admin_url( $parent_file ) );
+				exit;
+			} else {
+				_show_favicon_error_page( __( 'Error generating favicon files.' ) );
+			}
+		} else {
+			_show_favicon_error_page( $image_basename->get_error_message() );
+		}
+	} else {
+		_show_favicon_error_page();
+	}
+} 
+// Process image upload
+else {
+	$upload_results = process_thumbnail_upload();
+	
+	if (! is_wp_error( $upload_results ) ){
+		// Does it need to be scaled / cropped?
+		if ( $upload_results['width'] > 32 || $upload_results['height'] > 32 ){
+			display_crop_form( $upload_results );
+		} else {
+			// Short-circuit the crop operation and just save the raw unscaled image
+			if (! is_wp_error( generate_favicon_formats( load_favicon_image( $upload_results['file'] ), $upload_results['attachment_id'] ) ) ){
+				// And save the basename out to options.
+				update_option( 'sitefavicon', basename( generate_favicon_basename( $upload_results['attachment_id'] ) ) );
+				wp_redirect( admin_url( $parent_file ) );
+				exit;
+			} else {
+				_show_favicon_error_page( __( 'Error generating favicon files.' ) );
+			}
+		}
+	} else {
+		// Some kind of upload error
+		_show_favicon_error_page( $upload_results->get_error_message() );
+	}
+}
+
+
+/**
+ * Generic utility function to display a general error message within the options page structure.
+ * 
+ * @param string $message optional. A specific message describing the error condition for the end user.
+ * @param string $title optional. The heading for this error.
+ */
+function _show_favicon_error_page( $message = '', $title = '' ){
+	if ( empty( $message ) ) $message = __( 'Image upload failed. Please try again.' );
+	if ( empty( $title ) ) $title = __( 'Favicon upload error' );
+	
+	include_once('./admin-header.php');
+		echo '<div class="wrap favicon-error">';
+			echo "<h2>{$title}</h2>";
+			echo "<p>{$message}</p>";
+			echo '<p><a href="' . admin_url( $parent_file ) . '">&laquo;' . __( 'Back to Settings &gt; General' ) . '</a></p>';
+		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.
+ * Image results will return an array consisting of:
+ *		'attachment_id' => ID of the attachment DB record
+ *		'src' => URL of the img src
+ *		'width' => width ( = height )
+ *		'type' => the image type
+ *		'attr' => other attributes
+ *		'file' => the uploaded file path
+ * 
+ * @uses apply_filters( 'wp_favicon_max_crop_size' ) to set the maximum display size of the image in the crop form
+ * 
+ * @return mixed WP_Error | $image_info array 
+ */
+function process_thumbnail_upload(){
+	$file = wp_handle_upload( $_FILES['avatarfile'], array( 'action' => 'update') );
+	if ( isset($file['error']) ) die( $file['error'] );
+	
+	$url = $file['url'];
+	$file = $file['file'];
+	
+	// Check image file format
+	$image_type = exif_imagetype( $file );
+	if (! in_array( $image_type, array( IMAGETYPE_PNG, IMAGETYPE_JPEG, IMAGETYPE_GIF, IMAGETYPE_ICO ) ) )
+		return new WP_Error( 'bad_file_format', __( 'Please only use PNG (.png), JPEG (.jpg), GIF (.gif) or ICO (.ico) image files for favicons.' ) );
+	
+	$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( $width, $height, $type, $attr ) = getimagesize( $file );
+
+	return array( 
+		'attachment_id' => $id,
+		'src' => $url,
+		'width' => $width,
+		'height' => $height,
+		'type' => $type,
+		'attr' => $attr,
+		'file' => $file
+	);
+}
+
+
+function load_favicon_image( $file ){
+	$file_info = pathinfo( $file );
+	if ( strtolower( $file_info['extension'] ) == 'ico' ){
+		return imageCreateFromIco( $file, ICO_MAX_COLOR, ICO_MAX_SIZE );
+	} else {
+		return wp_load_image( $file );
+	}
+}
+
+
+/**
+ * Displays the form for cropping the thumbnail. Leverages the jcrop javascript library.
+ * 
+ * @uses wp_create_thumbnail()
+ * 
+ * @param array $image_info Array of properties as output by {@link process_thumbnail_upload()}
+ */
+function display_crop_form( $image_info ){
+	// Do we need to scale down the image so we can display it nicely in the interactive Crop tool?
+	$max_crop_display_size = apply_filters( 'wp_favicon_max_crop_size', 600 );
+	if ( $image_info['width'] > $max_crop_display_size || $image_info['height'] > $max_crop_display_size ) {
+		// Create and save a new thumbnail file at the new size
+		$image = wp_create_thumbnail( $image_info['file'], $max_crop_display_size );
+		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 = $image_info['width'] / $width;
+	} else {
+		// No scaling required; just copy original values.
+		$width = $image_info['width'];
+		$height = $image_info['height'];
+		$scaling = 1;
+	}
+	
+	/**
+	 * Display the crop form, leveraging the jcrop library.
+	 */
+	
+	// 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);
+	
+	include_once('./admin-header.php');
+
+	echo '<div class="wrap">';
+		// Now we can hook in our javascript and provide the width/height of our image as the default crop size
+		$crop_size = min( $width, $height ); //because it's gotta be square...
+		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
+        settings_fields( 'favicon_upload' );	
+		?>
+			<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="<?php echo $image_info['attachment_id']?>" />
+			<input type="hidden" name="scaling_factor" id="scaling_factor" value="<?php echo $scaling ?>" />
+		<?php
+		
+			echo '<img src="' . $image_info['src'] . '" id="upload" width="' . $width . '" height="' . $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');
+}
+
+/**
+ * Create PNG and BMP image resources based on the form submission of the cropped thumbnail.
+ * 
+ * @uses apply_filters( 'favicon_size' ) to set the favicon size in pixels.
+ * 
+ * @param int $attachment_id The ID of the original attachment's post record.
+ * @return mixed WP_Error | scaled and cropped image resource
+ */
+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 = apply_filters( 'favicon_size', DEFAULT_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 );
+
+	return $dst_image;
+}
+
+/**
+ * Generate the base filename. The .png and .ico versions will be this base name + the appropriate 3 letter extension (tla)
+ * This will be in the form of "filename-32x32" where '32' in this case is replaced by the actual icon dimensions
+ * 
+ * @param int $attachment_id The uploaded (and possibly cropped) attachment ID
+ * @returns string the base name of the favicon thumbnail, stripped of any file extension
+ */
+function generate_favicon_basename( $attachment_id ) {
+	/** @TODO rename and move this to image.php and refactor image_resize() to use this function so we're not duplicating efforts */
+	$src_file = get_attached_file( $attachment_id );
+	
+	list ( $width, $height ) = getimagesize( $src_file );
+
+	$file_info = pathinfo( $src_file );
+	$src_basename = basename( $src_file, '.' . $file_info['extension'] );
+	$dst_filename = str_replace( $src_basename, $src_basename . '-' . $width . 'x' . $height, $src_file );
+	// Strip the TLA from the filename (shouldn't be there anymore, but you can't be too careful...)
+	$dst_filename = preg_replace( '/\\.[^\\.]+$/', '', $dst_filename );
+	
+	return $dst_filename;
+}
+
+/**
+ * Creates and saves out the PNG and the ICO version of the thumbnail, when provided with the source resource.
+ * Also creates an attachment record for each.
+ * 
+ * @uses save_thumbnail_attachment();
+ * 
+ * @param type $source_image_resource
+ * @param type $file_basename
+ * @return \WP_Error 
+ */
+function generate_favicon_formats( $source_image_resource, $attachment_id ) {
+	if (! is_resource( $source_image_resource ) ) die( 'No resource provided. Cannot generate favicon files.' );
+
+	$file_basename = generate_favicon_basename( $attachment_id );
+	
+	// Save out the PNG
+	$png_filename = $file_basename . '.png';
+	if (! imagepng( $source_image_resource, $png_filename, 0 ) )
+		return new WP_Error( 'png_write_error', 'Error writing PNG favicon file.' );
+	save_thumbnail_attachment( $png_filename, $attachment_id );
+	
+	//Save out the ICO
+	$ico_filename = $file_basename . '.ico';
+	imageIco( $source_image_resource, $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.' );
+		save_thumbnail_attachment( $ico_filename, $attachment_id );
+
+	imagedestroy( $dst_image );
+}
+
+/**
+ * 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(
+		'post_title' => basename( $file_name ),
+		'post_mime_type' => $mimes[ $file_info['extension'] ],
+		'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? */
+}
+
+
+/**
+ * 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/}
+}
+
+/**
+ * Output the JavaScript that drives the jcrop cropping process.
+ * 
+ * @uses apply_filters( 'favicon_size' ) to set the favicon size in pixels
+ */
+function cropping_js(){
+	// Purely for coding convenience and legibility
+	$favicon_size = apply_filters( 'favicon_size', DEFAULT_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;
+
+}
+
+
+
+
+
+
+/**
+ * @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,14 @@
+(function($){
+    $('#faviconfile').change(function(){ 
+        // check the file extension
+        if ( $.inArray( $(this).val().split('.').pop().toLowerCase(), ['ico', 'png', 'bmp', 'jpg', 'jpeg'] ) < 0 ) {
+            $('#favicon-invalid-filetype-error').show();
+			$('#faviconupload')[0].reset();
+		}
+        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 20163)
+++ 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">
+    <?php settings_fields('favicon_upload') ?>
+	<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="35" />
+					<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>
+					<span id="favicon-invalid-filetype-error"><?php _e( 'Please only upload files in the following formats: .ico, .png, .bmp, .jpg' ) ?></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 20163)
+++ wp-includes/functions.php	(working copy)
@@ -1773,7 +1773,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 20163)
+++ wp-includes/general-template.php	(working copy)
@@ -1587,6 +1587,137 @@
 }
 
 /**
+ * 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() {
+	$favicon_uri = get_site_favicon_uri();
+	$ie_favicon_uri = get_site_favicon_uri( 'ico' );
+
+	$content = "";
+	if (! empty( $favicon_uri ) ){
+		$content .= "\n\n<!--favicon (via 'wp_head' action) -->\n";
+
+		if (! empty( $ie_favicon_uri )) $content .= <<<IE_FAVICON_1
+<!--[if IE]>
+	<link rel="shortcut icon" href="{$ie_favicon_uri}" />
+<![endif]-->
+<!--[if !IE]>-->\n
+IE_FAVICON_1;
+
+		$content .= "\t<link href=\"{$favicon_uri}\" rel=\"icon\" type=\"image/png\" />\n";
+		
+		if (! empty( $ie_favicon_uri )) $content .= "<!--<![endif]-->";
+		$content .= "\n<!-- /favicon -->\n\n";
+    }
+	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 ) ) {
+		$file = get_attached_file( $favicon_attachment->ID );
+		if ( file_exists( $file ) ) return $file;
+		else return new WP_Error( 'file_missing', __( 'Favicon image file missing.' ) );
+	} 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(){
+	return ( get_option ( 'sitefavicon' ) && ! is_wp_error( get_site_favicon_file() ) );
+}
+
+/**
+ * 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 . '" class="favicon" 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 20163)
+++ 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 );
