topbanner_forum
  *

avatar image

Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length
  • Thursday December 12, 2024, 12:32 am
  • Proudly celebrating 15+ years online.
  • Donate now to become a lifetime supporting member of the site and get a non-expiring license key for all of our programs.
  • donate

Author Topic: How can I batch decompile icon files?  (Read 10984 times)

kunkel321

  • Supporting Member
  • Joined in 2009
  • **
  • Posts: 602
    • View Profile
    • Donate to Member
How can I batch decompile icon files?
« on: October 14, 2012, 12:45 PM »
It seems I've become obsessed with collecting Windows Icons (and icon sets).  I guess it's a hobby. 
There are some pretty cool free sets out there on the web...  This weekend I realized that the motherload of icons is right inside my own Windows operating system...

I use Total Commander (not free)to filter out all the DLLs in my C: Drive, then one of the user-created TC plugins (free) lets me filter out the DLLs that have icons in them. 
I use Nirsoft IconsExtract (free) to extract the icons.  There were nearly 8000 of them, and many are quite nice! 
I then use another TC plugin to group the icons by whether or not they have hi-rez components (1167 do, lots of duplicates, though).

What I'd like to do now is make them so that they all have the same components:  32 bit, 256x256, down to 16x16, and get rid of the ugly low-bit ones. 
I'm finding that Windows has a hard time displaying them in a consistent way....  If I open a window in large thumbnail view, some of the icons will appear large, but others are small.  I can only assume that Windose is preferring a smaller 32 bit over a larger 8 or 4 bit (?).  Anyway, I found that IcoFX (free old version) will let me bulk convert images to ICOs.  AND... It will let me "convert" from ICO to ICO.  Since it lets you decide your own bit depth and sizes, I'm able to make my set uniform.  UNFORTUNATELY IcoFX seems to do this by taking the largest embedded PNG and re-sizing it to the different dimensions. 

Note how the top (pre-conversion) one is sharper than the bottom.  This is especially noticeable on the 16px one, were the original actually has a separate, low-detail version of the artwork, but the bottom one is an anti aliased smear of the larger image.

So the question:  How do I get all of those ugly 4 and 8 bit sub-cons out of there?

OR... Is there any software (think "free") that will actually convert like IcoFX does, but use the original size for the conversion?  (e.g. use the original 16x16 if there is one, otherwise, shrink the larger one).
Does that make sense?

mouser

  • First Author
  • Administrator
  • Joined in 2005
  • *****
  • Posts: 40,914
    • View Profile
    • Mouser's Software Zone on DonationCoder.com
    • Read more about this member.
    • Donate to Member
Re: How can I batch decompile icon files?
« Reply #1 on: October 14, 2012, 03:25 PM »
I wouldn't mind hearing about a tool that could batch cleanup .ico files as well (removing icons above or below a certain resolution).

Curt

  • Supporting Member
  • Joined in 2006
  • **
  • Posts: 7,566
    • View Profile
    • Donate to Member
Re: How can I batch decompile icon files?
« Reply #2 on: October 14, 2012, 05:36 PM »
Quite a number of the "icons" on Windows Vista, 7 and 8 are in fact PNG images, not ICO icons - hence maybe your differing results. For this reason you may be better off trying something special like RealWorld Icon Editor which fully supports PNG icons:

http://www.rw-design...m/3D_icon_editor.php

The software author is a member here at DC.

PhilB66

  • Supporting Member
  • Joined in 2007
  • **
  • Posts: 1,522
    • View Profile
    • Donate to Member

Edvard

  • Coding Snacks Author
  • Charter Honorary Member
  • Joined in 2005
  • ***
  • Posts: 3,022
    • View Profile
    • Donate to Member
Re: How can I batch decompile icon files?
« Reply #4 on: October 15, 2012, 02:03 AM »
If you've got access to a Linux box, try the icoutils:
http://www.nongnu.org/icoutils/

I've used them very successfully extracting png's from Windows icons.
Perhaps this weekend I'll try compiling on Cygwin to make Windows binaries for icotool:
The icotool program converts icon and cursor files into a set of PNG images. (Each icon/cursor file may contain multiple images, usually of different sizes and with different number of colors.) Icotool can also create icon/cursor files from PNG images.
Sound like what you need?

vlastimil

  • Honorary Member
  • Joined in 2006
  • **
  • Posts: 308
    • View Profile
    • Donate to Member
Re: How can I batch decompile icon files?
« Reply #5 on: October 15, 2012, 04:21 AM »
Here is a script for Mouser that cleans up icons. To use it, go to the Batch pate in RWIconEditor, select "Custom operation #1" or #2 in the "Batch operation" combo-box, then click on Load button and select the file attached to this post after unzipping it.

Then drag and drop icons on the window. As soon as you do that, a window will pop-up, where you can select what sizes and color depths to keep in the .ico file. All other images will be deleted. The result will then be accessible in the lower part of the window. The window will appear each time something is dropped on the application window - if you want multiple icons processed at once, drag and drop them together or drag and drop a folder.

There is a bit of JavaScript in the operation that you can access using the "Configure" button, but unfortunately it does not work correctly on 64-bit editions of Windows (the window nesting depth problem), so don't touch that if you are on 64-bit OS.

Modifying the script to also create images if they are not present in the .ico would not be too hard, but since kunkel321 asked for a free solution, I will not do that right now and get back to playing XCOM  :-*

kunkel321

  • Supporting Member
  • Joined in 2009
  • **
  • Posts: 602
    • View Profile
    • Donate to Member
Re: How can I batch decompile icon files?
« Reply #6 on: October 15, 2012, 05:14 PM »
Thanks Everyone, for the excellent recommendations!

For those who don't know the connection, Vlastimil is the creator of RW Icon Editor (referenced by Curt, above).
As it turns out...  A couple years ago Vlastimil was feeling particularly generous and donated several copies of his Icon Editor here on the DC forums. . . . And I was one of the lucky recipients!  I put several hours into it back then, but got overwhelmed because it is such a powerful tool that it blew my mind a bit, so I haven't even looked at it in quite a long time.  So again, the solution was right under my nose!  I did try the Clean-up icon script as explained above and it works like a charm!  Thanks so much!  Is this something you just scripted?  Modifying the script to make conversions for missing sizes would be awesome!  I'd recommend only converting down though.  For example a 64x64 could be used to make a 32x32, but not a 128x128.  It would need to check each individual ICO to see if there are any of the defined sizes missing.  Obviously writing-over an existing image wouldn’t be desirable. 

Note that if an ICO contains only low-bit images, RW will save the empty icon file just the same (as one would expect).  One of my file managers choked on the empties, but the other two file managers didn’t have a problem.   For a supplemental script like this, it probably doesn’t matter, but if you integrate this “icon cleaning” into the main application you might want to have an info message popup about it. 

===
I also checked out the “Icons from File” tool from vlsoftware.  It’s pretty cool.  I really like the way it can locate resources that contain icons and filter out ones that have <n icons.  This makes it unique.  The problem is that when you save the extracted items as icons, Icons from File only seems to save the 32x32, and none of the other sizes…  The help file does say that it doesn’t change the icons in any way when it extracts them…  Maybe it’s just a bug in my system—I don’t know.

===
Unfortunately I don’t have a Linux machine…
Vlastimil’s solution seems to be the one that does what I was wanting.
Thanks again everyone!

vlastimil

  • Honorary Member
  • Joined in 2006
  • **
  • Posts: 308
    • View Profile
    • Donate to Member
Re: How can I batch decompile icon files?
« Reply #7 on: October 16, 2012, 06:40 AM »
Oh, since you already have the software, here is an updated version of the script. Now it not only deletes extra images, but also create missing images. When creating new image, the source image is the one with the highest color depth and the biggest size, with one exception. If there is an image, that is exactly 2x, 3x, or 4x larger, it is selected as a source image. So for example, if an icon contains 32x32 and 48x48 images and you want it to also have 16x16 and 24x24 images, the 16x16 is created from the 32x32 one and the 24x24 from the 48x48. Image quality tends to be better when the scaling factor is a small integral number.

kunkel321

  • Supporting Member
  • Joined in 2009
  • **
  • Posts: 602
    • View Profile
    • Donate to Member
Re: How can I batch decompile icon files?
« Reply #8 on: October 21, 2012, 11:50 AM »
I just wanted to log on to this thread and say, "Thanks again!" to Vlastimil.
The "Normalize icon" script works beautifully!  Good thinking with the point about scaling from images who's dimensions are a multiple of the to-be-made images.  

I've been putting some time into reacquainting myself with Real World Icon Editor.  It's a pretty amazing application, and an incredibly versatile tool for icon creation.  I have some questions about setting up batch jobs and also some questions about Unicorn work....  Do you find it easier to discuss these topics as threads here at  the DonCod forums, or over at the RealWorld forums though?

Edit:  Actually...  One more question that is relevant to this particular thread:
Is it difficult to set the Normalize script to only scale down
What I mean is that I'd still specify the desired icon sizes, but missing sizes would only get created from larger ones... 

I thought I'd be clever an suggest how the logic might work...  Mostly it just hurts my brain.





« Last Edit: October 21, 2012, 01:07 PM by kunkel321 »

mouser

  • First Author
  • Administrator
  • Joined in 2005
  • *****
  • Posts: 40,914
    • View Profile
    • Mouser's Software Zone on DonationCoder.com
    • Read more about this member.
    • Donate to Member
Re: How can I batch decompile icon files?
« Reply #9 on: October 21, 2012, 12:56 PM »
Very very very nice.  :up:

vlastimil

  • Honorary Member
  • Joined in 2006
  • **
  • Posts: 308
    • View Profile
    • Donate to Member
Re: How can I batch decompile icon files?
« Reply #10 on: October 22, 2012, 08:41 AM »
Modifying the operation to only downscale is not too hard, but maybe I should explain how it works instead of posting these black-boxes (Normalize icon 2 is still attached) so that people may customize the behavior as they need. The "Normalize icon" contains this piece of JavaScript (I said it before, but let's mention it again: the configuration window does not work correctly on 64-bit Windows in the current version of the application. Other may access it by pressing the Configure button):

Code: Javascript [Select]
  1. var sizesTx = Configuration.GetValue("sizes");
  2. var depthsTx = Configuration.GetValue("depths");
  3. var sizes = sizesTx.split(',');
  4. var depths = depthsTx.split(',');
  5.  
  6. var icon = Document.Icon;
  7. var formats = icon.FormatIDs;
  8.  
  9. // add missing images
  10. for (var s = 0; s < sizes.length; ++s)
  11. {
  12.         var size = parseInt(sizes[s]);
  13.         for (var d = 0; d < depths.length; ++d)
  14.         {
  15.                 var depth = parseInt(depths[d]);
  16.  
  17.                 // is image missing?
  18.                 var present = false;
  19.                 for (var i = 0; !present && i < formats.length; ++i)
  20.                 {
  21.                         var format = formats[i];
  22.                         present = format.SizeX == size && format.SizeY == size && format.ColorDepth == depth;
  23.                 }
  24.                 if (present)
  25.                         continue;
  26.  
  27.                 // find best source format
  28.                 var oldFormat = null;
  29.                 var bestScore = -1;
  30.                 for (var i = 0; i < formats.length; ++i)
  31.                 {
  32.                         var format = formats[i];
  33.                         var score = 0;
  34.                         score += format.ColorDepth*1000;
  35.                         if (format.SizeX == format.SizeY)
  36.                         {
  37.                                 if (format.SizeX == 2*size)
  38.                                         score += 950;
  39.                                 else if (format.SizeX == 3*size)
  40.                                         score += 900;
  41.                                 else if (format.SizeX == 4*size)
  42.                                         score += 850;
  43.                                 else
  44.                                         score += format.SizeX;
  45.                         }
  46.                         if (score > bestScore)
  47.                         {
  48.                                 bestScore = score;
  49.                                 oldFormat = format;
  50.                         }
  51.                 }
  52.  
  53.                 // create new image
  54.                 var newFormat = icon.CreateFormatID(size, size, depth);
  55.                 icon.InsertImage(newFormat);
  56.                 // copy data
  57.                 var oldImage = Blender.CreateCanvas(oldFormat.SizeX, oldFormat.SizeY, 0);
  58.                 Blender.Compose(oldImage, 0, 0, oldFormat.SizeX, oldFormat.SizeY, icon.GetImage(oldFormat), 0, 0, 0, Blender.OpSrc);
  59.                 var resample = Operation.Create("Raster Image - Resample");
  60.                 resample.Mode = 1;
  61.                 resample.SizeXAbs = size;
  62.                 resample.SizeYAbs = size;
  63.                 Operation.Execute(resample, oldImage);
  64.                 Blender.Compose(icon.GetImage(newFormat), 0, 0, size, size, oldImage, 0, 0, 0, Blender.OpSrc);
  65.         }
  66. }
  67.  
  68. // delete other images
  69. for (var i = 0; i < formats.length; ++i)
  70. {
  71.         var format = formats[i];
  72.         var sizeOK = format.SizeX != format.SizeY;
  73.         for (var j = 0; !sizeOK && j < sizes.length; ++j)
  74.         {
  75.                 var size = parseInt(sizes[j]);
  76.                 sizeOK = size == format.SizeX;
  77.         }
  78.         var depthOK = false;
  79.         for (var j = 0; !depthOK && j < depths.length; ++j)
  80.         {
  81.                 var depth = parseInt(depths[j]);
  82.                 depthOK = depth == format.ColorDepth;
  83.         }
  84.         if (!sizeOK || !depthOK)
  85.                 icon.DeleteImage(format);
  86. }

The section with the "Find best source format" needs to be changed to only consider images larger than the one that is being added. And if no suitable source image is found, the new image is not added. After the modification, it may look like this:

Code: Javascript [Select]
  1. ...
  2.  
  3.                 // find best source format
  4.                 var oldFormat = null;
  5.                 var bestScore = -1;
  6.                 for (var i = 0; i < formats.length; ++i)
  7.                 {
  8.                         var format = formats[i];
  9.                         if (format.SizeX < size || format.SizeY < size)
  10.                                 continue;
  11.                         var score = 0;
  12.                         score += format.ColorDepth*1000;
  13.                         if (format.SizeX == format.SizeY)
  14.                         {
  15.                                 if (format.SizeX == 2*size)
  16.                                         score += 950;
  17.                                 else if (format.SizeX == 3*size)
  18.                                         score += 900;
  19.                                 else if (format.SizeX == 4*size)
  20.                                         score += 850;
  21.                                 else
  22.                                         score += format.SizeX;
  23.                         }
  24.                         if (score > bestScore)
  25.                         {
  26.                                 bestScore = score;
  27.                                 oldFormat = format;
  28.                         }
  29.                 }
  30.                 if (bestScore == -1)
  31.                         continue;
  32.  
  33. ...

I have added just 4 lines - there is one condition within the cycle that is looking for best source image. Smaller image are now skipped. At the end of the cycle, the script checks if a suitable source image was found and if not, the image is not added.

If you have questions related to the 3D part of the editor, asking them on my forum may be better as they will surely be pretty specific and likely not interesting to other DC members.