Files
itgmania212121/Utils/Font generation/Text.js
T
2013-06-10 15:38:43 -04:00

359 lines
11 KiB
JavaScript

/* This file was written by Glenn Maynard, and is in the public domain.
*
* This is a Photoshop javascript to generate Kanji fonts.
*
* You'll need the plugin:
*
* http://www.adobe.com/support/downloads/detail.jsp?ftpID=1536
*
* Load this script from File->Automation->Scripts, browse. Expect it to take
* a minute or two.
*
* Minimally, you'll need to edit the directories below.
*
* Each font page in FontPages is generated for each font in Fonts.
*
* I can't figure out a way to force a font to fixed-width, so this currently
* only works with fixed-width fonts. I'm using this primarily for Japanese
* fonts, so that's OK. If we could output Unicode, we could get around this,
* by outputting each glyph in a separate layer and aligning them individually,
* though that'd take a very long time.
*/
/* Okay, this is a stupid way to pass by reference, but I don't speak JavaScript ... */
function Integer(i) { this.val = i; }
var TemplateDir = "c:/temp/stepmania/utils/Font generation/Templates/";
var OutputDir = "c:/temp/stepmania/utils/Font generation/Output/";
/* We can't send Unicode into the font ourself for some reason. So, we have to
* store prototypes for each font page. These should just be PSD files that contain
* a single text layer with the characters we want. The orientation, font, etc.
* don't matter; they'll be overridden. */
var JAFontPages = Array("main", "kanji 1", "kanji 2","kanji 3","kanji 4");
var KRFontPages = Array("jamo 1", "jamo 2", "jamo 3", "jamo 4");
var Fonts = new Array(
/* name font pages frame sz font sz AA border bold */
new FontDef("_japanese 16px", "MS-Gothic", JAFontPages, 32, 20, AntiAlias.STRONG, 2, true),
new FontDef("_japanese 24px", "MS-Gothic", JAFontPages, 32, 26, AntiAlias.SMOOTH, 2, true)
//new FontDef("_korean 16px", "ArialUnicodeMS", KRFontPages, 32, 20, AntiAlias.SMOOTH, 2, true),
//new FontDef("_korean 24px", "ArialUnicodeMS", KRFontPages, 32, 28, AntiAlias.SMOOTH, 2, true)
);
var sel, doc;
var strtRulerUnits = preferences.rulerUnits;
var strtTypeUnits = preferences.typeUnits;
preferences.rulerUnits = Units.PIXELS;
preferences.typeUnits = TypeUnits.PIXELS;
displayDialogs = DialogModes.NO;
go();
preferences.rulerUnits = strtRulerUnits;
preferences.typeUnits = strtTypeUnits;
function FontDef(Name, /* filename prefix */
Font, /* actual font name */
Pages, /* list of font pages */
FrameSize, /* frame size in pixels */
FontSize, /* font character size in pixels (horiz) */
AAMethod, /* antialiasing */
Border, /* pixels or 0 for off */
Bold /* boolean */
)
{
this.Name = Name;
this.Font = Font;
this.Pages = Pages;
this.FrameSize = FrameSize;
/* This is the width of each character, as output by the font renderer.
* Changing this changes the size of the character. */
this.HorizSize = FontSize;
/* This is the actual vertical size of characters, as output by the font renderer.
* For MS Gothic, it always seems to be 4/3 of the vertical size. */
this.VertSize = FontSize* 4 / 3;
this.AAMethod = AAMethod;
this.Border = Border;
this.Bold = Bold;
}
function go()
{
for(var f = 0; f < Fonts.length; ++f)
{
for(var i = 0; i < Fonts[f].Pages.length; ++i)
{
MakeFontPage(TemplateDir + Fonts[f].Pages[i] + " template.psd",
OutputDir + Fonts[f].Name + " [" + Fonts[f].Pages[i] + "]",
Fonts[f]);
}
}
}
function MakeFontPage(TemplatePath, OutputPath, Font)
{
/* Open the template. */
var file = new File(TemplatePath);
if(!file.open("r"))
{
alert("Couldn't open " + TemplatePath);
return;
}
open(file);
file = null;
/* Change the template to a font page. */
var frameX = new Integer;
var frameY = new Integer;
ConvertCurrentDocument(frameX, frameY, Font);
/* Save the template to the destination file and close the template. */
var Save = new PNGSaveOptions;
Save.interlaced = false;
OutputPath += " " + frameX.val + "x" + frameY.val;
OutputPath += ".png";
activeDocument.saveAs(new File(OutputPath), Save, true, Extension.LOWERCASE);
activeDocument.close(SaveOptions.DONOTSAVECHANGES);
}
function GetTextLayer(Doc)
{
/* Find a text layer. */
var TextLayer = null;
for(var i = 0; i < activeDocument.artLayers.length; ++i)
{
if(activeDocument.artLayers[i].kind != LayerKind.TEXT)
continue; /* irrelevant */
if(TextLayer != null)
{
alert("More than one text layer found. Confused.");
return null;
}
TextLayer = activeDocument.artLayers[i];
}
if(TextLayer == null)
{
alert("No text layer found. Confused.");
return null;
}
return TextLayer;
}
/* We have an open document with a single text layer. Convert it to a font
* page. The result will be a single RGB layer. */
function ConvertCurrentDocument( frameX, frameY, Font )
{
// Create a new art layer and convert it to a text layer.
// Set its contents, size and color.
if (documents.length == 0)
{
alert ("You must have at least one open document to run this script.");
return;
}
doc = activeDocument;
sel = doc.selection;
/* Find a text layer. */
var TextLayer = GetTextLayer(doc);
if(TextLayer == null) return;
/* Figure out the number of frames in each dimension, based on the line count
* and max characters/line. */
GetFrameCount(TextLayer.textItem.contents, frameX, frameY);
/* Based on the frame count and frame size, figure out the dimensions of
* the whole page. */
var PageWidth = frameX.val * Font.FrameSize;
var PageHeight = frameY.val * Font.FrameSize;
/* Resize the image down to the size required to hold the images. This prevents
* errors later when we move columns around if the image is too big. */
doc.resizeCanvas(PageWidth, PageHeight, AnchorPosition.TOPLEFT);
{
/* Using HorizSize as the vertical origin seems to align the text so that
* it's centered in the top VertSize pixels. Adjust from there to being centered
* in the frame.
*
* Add half of a pixel. This seems to help alignment a lot. */
var Dist = Font.FrameSize/2-Font.VertSize/2;
TextLayer.textItem.position = Array(0, Font.HorizSize+Dist+.5);
}
TextLayer.textItem.font = Font.Font;
TextLayer.textItem.antiAliasMethod = Font.AAMethod;
var textColor = new SolidColor;
textColor.rgb.red = 255;
textColor.rgb.green = 255;
textColor.rgb.blue = 255;
TextLayer.textItem.color = textColor;
TextLayer.textItem.useAutoLeading = 0;
TextLayer.textItem.spaceBefore = Font.FrameSize;
TextLayer.textItem.spaceAfter = 0;
TextLayer.textItem.size = Font.HorizSize;
TextLayer.textItem.fauxBold = Font.Bold;
TextLayer.textItem.fauxItalic = false;
TextLayer.rasterize(RasterizeType.ENTIRELAYER);
var CurrentSpacing = Font.HorizSize;
/* Faux bold adds half a pixel to the width of each character. */
if(Font.Bold)
CurrentSpacing += 0.5;
/* We currently have a horizontal spacing of CurrentSpacing; adjust it to
* have a vertical spacing of FrameSize. */
Adjust(Font.FrameSize, CurrentSpacing, frameX.val);
if(Font.Border != 0)
TextLayer = MakeBorder(TextLayer, doc.artLayers, Font.Border);
{
/* Resize the texture to have the largest possible frame count without going
* over a power of two. This way, when the font page grows, the frame count
* (8x8) stays constant, so we don't have to keep renaming files in CVS. */
var MaxX = power_of_two(PageWidth);
var MaxY = power_of_two(PageHeight);
while(PageWidth + Font.FrameSize <= MaxX)
PageWidth += Font.FrameSize;
while(PageHeight + Font.FrameSize <= MaxY)
PageHeight += Font.FrameSize;
/* Actually, let's force the texture to be square, too, which reduces filename
* changes even more. This eats a little texture memory. It also means that
* if the texture is reduced at runtime, it'll be reduced equally in both
* dimensions, which will probably look less weird. */
if(PageHeight < PageWidth) PageHeight = PageWidth;
else PageWidth = PageHeight;
frameX.val = PageWidth / Font.FrameSize;
frameY.val = PageHeight / Font.FrameSize;
}
doc.resizeCanvas(PageWidth, PageHeight, AnchorPosition.TOPLEFT);
}
function GetFrameCount(str, x, y)
{
/* Strip blank lines off the end. */
for(var c = str.length-1; c >= 0; --c)
{
if(c != '\r' && c != ' ')
break;
str = str.substr(0, str.length-1);
}
var NumLines = 0, MaxLength = 0, CurLength = 0;
for(var c = 0; c < str.length; ++c)
{
if(str[c] == '\r')
{
CurLength = 0;
NumLines++;
}
else
{
CurLength++;
if(CurLength > MaxLength)
MaxLength = CurLength;
}
}
if(CurLength)
NumLines++;
x.val = MaxLength;
y.val = NumLines;
}
function power_of_two(n)
{
var value = 1;
while (value < n)
value *= 2;
return value;
}
/* The current document is in columns of width NewWidth. Space it out so the columns
* are of width OldWidth. */
function Adjust(NewWidth, OldWidth, Columns)
{
// col = 7;
for(var col = Columns-1; col >= 0; --col)
{
var selBounds = Array(
Array(col*OldWidth,0),
Array((col+1)*OldWidth, 0),
Array((col+1)*OldWidth, activeDocument.height),
Array(col*OldWidth, activeDocument.height));
sel.select(selBounds);
var OldXCenter = (col + .5) * OldWidth;
var NewXCenter = (col + .5) * NewWidth;
var Distance = NewXCenter-OldXCenter;
sel.translate(Distance);
}
sel.deselect();
}
function SelectTransparencyFromCurrentLayer()
{
// Voodoo from the action recorder, since I couldn't find a way to
// do this normally.
var id15 = charIDToTypeID( "setd" );
var desc3 = new ActionDescriptor();
var id16 = charIDToTypeID( "null" );
var ref1 = new ActionReference();
var id17 = charIDToTypeID( "Chnl" );
var id18 = charIDToTypeID( "fsel" );
ref1.putProperty( id17, id18 );
desc3.putReference( id16, ref1 );
var id19 = charIDToTypeID( "T " );
var ref2 = new ActionReference();
var id20 = charIDToTypeID( "Chnl" );
var id21 = charIDToTypeID( "Chnl" );
var id22 = charIDToTypeID( "Trsp" );
ref2.putEnumerated( id20, id21, id22 );
desc3.putReference( id19, ref2 );
executeAction( id15, desc3, DialogModes.NO );
}
/* Add a border to the current layer. */
function MakeBorder(Layer, Layers, Width)
{
SelectTransparencyFromCurrentLayer();
sel.expand(Width);
var BorderLayer = Layers.add();
BorderLayer.moveAfter(Layer);
var borderColor = new SolidColor;
borderColor.rgb.red = 0;
borderColor.rgb.green = 0;
borderColor.rgb.blue = 0;
sel.fill(borderColor);
sel.deselect();
Layer.merge();
return BorderLayer;
}