PDA

View Full Version : Semi-Automate new Theme Generation



Bryan
19 Oct 2007, 8:43 AM
inspired by madrabaz.

Seeing the nice theme work performed by madrabaz (http://extjs.com/forum/showthread.php?t=15505), I decided to 'semi-automate' the process of creating the 'colorized' images.

Photoshop CS3 Extended 10.0 is javascript scriptable, so I created a script to open the files of the theme, apply a hue/saturation/light, and save them into a new location.

You have to change the hue, saturation, light values yourself manually in the imageParser.jsx file.

Steps.
Save the javascript file as imageParser.jsx.
Open extjs/resources/images/default/panel/tool-sprites.gif in Photoshop
Adjust the hue/saturation/light values. Make sure the colorize checkbox is checked.
Record the values. You will need them later.
Close tool-sprites.gif
Open imageParser.jsx in a text editor.
Change the variables h, s, and l to the values recorded above
Save the file.
Create a new folder for the output of this script. I use extjs/resources/images/NEWFOLDERNAME
In photoshop, File>Scripts>Browse...
Select imageParser.jsx
Select the inputFolder: I use extjs/resources/images/default
Select the outputFolder: I use the one created above: extjs/resources/images/NEWFOLDERNAME
Click ok.
Watch the fun.CSS Modifications
Open the extjs/resources/css/ext-all.css file.
find and replace all instances of default/ with NEWFOLDERNAME/
save as extjs/resources/css/xtheme-NEWFOLDERNAME.cssNote: you will have to change the #RRGGBB colors specified in the new css file, but your sprites have been changed

include the new theme in your html file with
<link rel="stylesheet" type="text/css" href="extjs/resources/css/xtheme-NEWFOLDERNAME.css" />

tada. you have a new theme.

Note: This script only creates a colorized version of the existing files. Any changes to the look-and-feel (other than color) is outside the scope of this post.
Note: Use at your own risk. Any script that automatically modifies your files should be validated prior to running, not just this one. In other words, don't just run this script (or any other) on your system, prior to reading the code "to find out what it really does".
Note: This file was created on an intranet, and retyped here with my fat-fingers...Please excuse typos.


imageParser.jsx



// written for Adobe Photoshop CS3 Extended 10.0 - may not work with your version
// ExtJs Theme Modifier

#target photoshop
app.bringToFront(); // bring top
$.localize = true; // Enable ZString localization

//
// Change the hue/saturation/light values
//
// These values are easily determined by opening a file in photoshop
// altering the h/s/l and recording the values.
// -- colorize was turned on for me
//
// h = 0, s = 25, l = 0 is a nice bronzish color
// h = 113, s = 38, l = -1 is a greenish color
//
var h = 0; // hue
var s = 25; // saturation
var l = 0; // light (this is the letter L, not the number 1)

// debug settings
var debug = true;
var debugFile = '~/Desktop/image-parser.log';
var debugFh, linefeed; // don't modify these. debug file handle and linefeed char

// files to skip during the hue/saturation/light step
var exclude = {
'':{ // top level dir
's.gif':true,
'shadow-c.png':true,
'shadow-lr.png':true,
'shadow.png':true
},
dd:{
'drop-add.gif':true,
'drop-no.gif':true,
'drop-yes.gif':true
},
editor:{
'tb-sprite.gif':true
},
form:{
'error-tip-corners.gif':true,
'exclamation.gif':true
},
grid:{
'arrow-left-white.gif':true,
'arrow-right-white.gif':true,
'columns.gif':true,
'dirty.gif':true,
'done.gif':true,
'drop-no.gif':true,
'drop-yes.gif':true,
'grid-loading.gif':true,
'group-by.gif':true,
'hd-pop.gif':true,
'hmenu-asc.gif':true,
'hmenu-desc.gif':true,
'hmenu-lock.gif':true,
'hmenu-lock.png':true,
'hmenu-unlock.gif':true,
'hmenu-unlock.png':true,
'invalid_line.gif':true,
'loading.gif':true,
'nowait.gif':true,
'page-first-disabled.gif':true,
'page-last-disabled.gif':true,
'page-next-disabled.gif':true,
'page-prev-disabled.gif':true,
'refresh.gif':true,
'wait.gif':true
},
layout:{
'mini-bottom.gif':true,
'mini-left.gif':true,
'mini-right.gif':true,
'mini-top.gif':true
},
shared:{
'blue-loading.gif':true,
'calendar.gif':true,
'large-loading.gif':true,
'warning.gif':true
},
tabs:{
'tab-strip-bg.png':true // empty image??
},
tree:{
'drop-add.gif':true,
'drop-between.gif':true,
'drop-no.gif':true,
'drop-over.gif':true,
'drop-under.gif':true,
'drop-yes.gif':true,
'folder.gif':true,
'folder-open.gif':true,
'leaf.gif':true,
'loading.gif':true,
's.gif':true
},
window:{
'icon-error.gif':true,
'icon-info.gif':true,
'icon-question.gif':true,
'icon-warning.gif':true
}
};

// modify nothing beneath this line

// hue/saturation/light function gotten off of the internets
function hueSaturationLight(hue, saturation, light){
var aDesc = new ActionDescriptor();
var userInput = new ActionDescriptor();
var aList = new ActionList();

with(userInput){
putInteger(charIDToTypeID("H "), hue);
putInteger(charIDToTypeID("Strt"), saturation);
putInteger(charIDToTypeID("Lght"), light);
}

aDesc.putBoolean(charIDToTypeID("Clrz"), true);
aList.putObject(charIDToTypeID("Hst2"), userInput);
aDesc.putList(charIDToTypeID("Adjs"), aList);
executeAction(charIDToTypeID("HStr"), aDesc, DialogModes.NO);
}

// save the current preferences
var startDisplayDialogs = app.displayDialogs;

// set no dialogs
app.displayDialogs = DialogModes.NO;

// ask the user for the input folder
var inputFolder = Folder.selectDialog("Select a folder for the input files. Example: extjs/resources/images/default");

// ask the user for the output folder
var outputFolder = Folder.selectDialog("Select a folder for the input files. Example: extjs/resources/images/bronze");

function log(string){
if (!debug)return;
if (!debugFile)return;
if (!linefeed){
if ($.os.search(/windows/i) != -1){
linefeed = "windows";
} else {
linefeed = "macintosh";
}
}

if (!debugFh) {
// create a reference to the logfile
debugFh = new File(debugFile);
debugFh.lineFeed = linefeed;
debugFh.open('w', "TEXT", "????");
debugFh.write('Debug Report for imageParser.jsx: '+ new Date() + '\n');
}

if (debugFh){
// write the string to the file
var string = string || '';
debugFh.write(string+'\n');
}
}

function processFiles(args){
var folder = args.folder;
var f = folder.getFiles();
if (f && f.length > 0){
for (var i = 0; i < f.length; i++){
if (f[i] instanceof Folder) {
// traverse into this folder
log(f[i].name+' is a Folder.. traverse');
processFiles({folder:f[i]});
} else {
log(f[i]+' ... checking');

var processFile = true;

// exclude index files
if ( -1 != f[i].fsName.indexOf('Thumbs.db'))continue;
if ( -1 != f[i].fsName.indexOf('.DS_Store'))continue;
if ( -1 != f[i].fsName.indexOf('.psd'))continue;

// only process files that contain a .gif, .png, or .jpg
if ( ! (f[i].fsName.indexOf('.gif') > -1 ||
f[i].fsName.indexOf('.png') > -1 ||
f[i].fsName.indexOf('jpg') > -1 ) ) {
log(' ... not a gif, png, or jpg');
processFile = false;
}

// check to see if the current folder is the top-level one
var pName = (f[i].parent.name === inputFolder.name) ? '' : f[i].parent.name;

// don't process this file if it is in our 'exclude' list
if (exclude[pName] && exclude[pName][f[i].name]){
log(' ... is in the exclude list');
processFile = false;
}

var doc = app.open(File(f[i]));
if (doc){
if (processFile){
log(' ... performing hue/sat/light');
hueSaturationLight(h,s,l); // vars set at teh top of the file
}

// Determine which file save settings to use.
// I couldn't find an image filetype parameter so i'm parsing the filename
// This of course, is easily broken by funky filenames

var saveOptions;
if (f[i].fsName.indexOf('.gif') > -1){
saveOptions = new GIFSaveOptions();
saveOptions.transparency = true;
} else if (f[i].fsName.indexOf('.png') > -1){
saveOptions = new PNGSaveOptions();
} else if (f[i].fsName.indexOf('.jpg') > -1){
saveOptions = new JPEGSaveOptions();
} else {
// not one of the three types
}
log(' ... setting save options');

if (saveOptions){
// save the file to the folder/subfolder requested by the user
var sFile = outputFolder+'/';
if (pName) {
sFile += pName +'/';
}
sFile += f[i].name;

if (pName){ // if not the top-level folder
var tFolder = new Folder(outputFolder+'/'+pName);
if (!tFolder.exists){
tFolder.create();
}
}
doc.saveAs(new File(sFile), saveOptions);
log(' ... saved: '+sFile);
}

// close orig file. do not save changes
doc.close(SaveOptions.DONOTSAVECHANGES);
}
}
}
}
log(); // blank line for readability
}

// work with the folders selected by the user
if (inputFolder !== null && outputFolder !== null){
log(); // blank line for readability
log('Input Folder: '+inputFolder);
log('Output Folder: '+outputFolder);
log(); // blank line for readability

// if the input folder isn't the output folder
// try to play nicely.. not overwrite the source file
if (inputFolder !== outputFolder){
processFiles({folder:inputFolder});
} else {
log('Input and Output folders are the same');
alert('Sorry. Input and output folders can not be the same folder.');
}
}

function cleanup(){
// nullify var and close file handles
if (debugFh){
debugFh.close();
alert('Log file saved to: '+debugFile);
}

// restore settings
if (startDisplayDialogs){
app.displayDialogs = startDisplayDialogs;
}
}

cleanup();

madrabaz
19 Oct 2007, 9:11 AM
This very nice,

Notice; if you apply same hue/saturation/brightness values to tool images, they do not seem properly on the panel or window header

Bryan
19 Oct 2007, 10:20 AM
Notice; if you apply same hue/saturation/brightness values to tool images, they do not seem properly on the panel or window header

I don't think I understand this response. Is this a problem with the CSS or the color of the tool images?

madrabaz
19 Oct 2007, 10:52 AM
Color of the tool image, its borders are dimmed if you apply same values which are applied to header background images

maquina
1 Jun 2008, 6:49 PM
any feedback?

McCornic
27 Oct 2008, 6:54 AM
Thank for your scipt. It was very useful for me.
Just replace the !== with != and === with == on photoshop CS2.

harley.333
27 Oct 2008, 7:19 AM
very cool work - i hope someone takes your work to the web-server and make a theme generator

Condor
27 Oct 2008, 7:30 AM
It would be even nicer if you could specify a scale (e.g. 120% for larger fonts).

(I know that this is a lot harder to do, because for each height and width you need to determine how much of it is fixed size and how much is determined by the font size)

anthony-apd
16 Dec 2008, 8:33 PM
any way to make so you can supply specific color values?

viccyz
25 Dec 2008, 11:58 PM
after this Select the outputFolder: I use the one created above: extjs/resources/images/NEWFOLDERNAME step, it show me error 1220: illegal argument Line 119: -> putInteger(charIDToTypeID("H "), hue); :-?:-?
can any1 help me?
thanks!

Kango_V
1 Jun 2009, 12:49 PM
Hmm, very nice. I wonder though, if this could pe done easier with ImageMagick on Linux?
I might have to try that.