» Archive for the 'Java' Category

Font CharSet and Encoding

Wednesday, July 16th, 2008 by rubypdf

yesterday, A Chinese developer sent me WMF with Chinese character, and the FontFace name is also Chinese, he said the iTextSharp could convert the WMF to PDF correctly. so I try to debug into the source code, and find MetaFont only support ASCII.

try {
faceName = System.Text.Encoding.GetEncoding(1252).GetString(name, 0, k);
}
catch {
faceName = System.Text.ASCIIEncoding.ASCII.GetString(name, 0, k);
}

but charset of Chinese font(GB2312) is 134, so I think the source code needs to get encoding from charset, and then get the right faceName.
Finally, I get the following codes,

public enum FontCharSet : byte
{
ANSI_CHARSET = 0,// ANSI charset (Windows-1252)
DEFAULT_CHARSET = 1,
SYMBOL_CHARSET = 2,
MAC_CHARSET = 77,
SHIFTJIS_CHARSET = 128,// Shift JIS charset (Windows-932)
HANGEUL_CHARSET = 129,// Hangeul charset (Windows-949)
HANGUL_CHARSET = 129,
JOHAB_CHARSET = 130, // Johab charset (Windows-1361)
GB2312_CHARSET = 134,// GB2312 charset (Windows-936)
CHINESEBIG5_CHARSET = 136,// Chinese Big5 charset (Windows-950)
GREEK_CHARSET = 161, // Greek charset (Windows-1253)
TURKISH_CHARSET = 162,// Turkish charset (Windows-1254)
VIETNAMESE_CHARSET = 163,// Vietnamese charset (Windows-1258)
HEBREW_CHARSET = 177,// Hebrew charset (Windows-1255)
ARABIC_CHARSET = 178,// Arabic charset (Windows-1256)
BALTIC_CHARSET = 186,// Baltic charset (Windows-1257)
RUSSIAN_CHARSET = 204,// Cyrillic charset (Windows-1251)
THAI_CHARSET = 222,// Thai charset (Windows-874)
EASTEUROPE_CHARSET = 238, // Eastern european charset (Windows-1250)
OEM_CHARSET = 255,
}

and some very useful source codes( WMFUtilities.java and WMFConstants.java ) file from Apache Batik, it has implement the charset issue.

BTW, iText also has the same issue,

187 try {
188 font = BaseFont.createFont(fontName, "Cp1252", false);
189 }
190 catch (Exception e) {
191 throw new ExceptionConverter(e);
192 }

Bookbinder-A program to create a bindable book from a PDF file

Wednesday, May 21st, 2008 by rubypdf

Bookbinder is a program that will convert a PDF document into signatures suitable for traditional bookbinding.
While there are a lot of programs on the net that will create a single booklet from a small document, I couldn’t find one that would turn a 500 page novel or textbook into several signatures. So I had to write one.

The chosen PDF is split into chunks, the page order of each chunk is rearranged, then the pages are placed two to a page in a new PDF. After printing and folding, each bundle of sheets should be a correctly ordered signature, ready for binding.

For more info, please visit http://www.quantumelephant.co.uk/bookbinder/bookbinder.html

Image Combiner - combine two images into one.

Thursday, May 1st, 2008 by rubypdf

Here is a java implementation, I just get it from other website, and want to use it some day.

import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;

/**
* To use this program, first identify the two images
* you want to merge. Then run this program and give
* the two image file names on the command line. The
* program will display both images and their combination.
* To change the relative weights of the combination,
* pass both the file names and the weights on the command
* line.
*

* For example:
* java ImageCombiner photo1.jpg 0.67 photo2.jpg 0.55
*/
public class ImageCombiner extends WindowAdapter {
Image resultImage;
Image img1;
Image img2;
Image imgr;
ImageDisplay ic1;
ImageDisplay ic2;
ImageDisplay icr;
int ccnt;

public class ImageDisplay extends Canvas {
private Image i;
private Frame myframe;

public ImageDisplay(Image img, boolean makeframe) {
i = img;
if (makeframe) {
myframe = new Frame(”Image”);
myframe.add(this, BorderLayout.CENTER);
MediaTracker mt = new MediaTracker(this);
mt.addImage(i, 1);
try { mt.waitForAll(); } catch (Exception ie) { }
setSize(i.getWidth(this), i.getHeight(this));
myframe.pack();
}
else {
myframe = null;
setSize(i.getWidth(this), i.getHeight(this));
}
}
public void paint(Graphics g) {
g.drawImage(i, 0, 0, this);
}

public Frame getFrame() { return myframe; }

public void placeAndShow(int x, int y) {
if (myframe != null) {
myframe.setLocation(x,y);
myframe.show();
}
}
}

/**
* ImageMerger acts as an ImageProducer to
* generate the merger of two images.
* When created, it expects to Image objects.
* It extracts the pixels from these objects,
* and merges them using a simple weighted
* addition in RGB space. The width and height
* of the result image are each the maximum of
* the widths and heights of the input images.
* Normally, you’ll get best results when the
* images are exactly the same size.
*/
public class ImageMerger
{
protected double w1, w2;
protected Image i1;
protected Image i2;
protected ColorModel cm;

int rwid, rhgt;
protected int results[];

/**
* Create in ImageMerger object to merge two
* images. This does not perform the merger,
* that should be done by calling generate().
* This constructors sets the weights to
* 0.5 and 0.5.
*/
public ImageMerger(Image img1, Image img2) {
cm = null;
i1 = img1;
i2 = img2;
w1 = 0.5;
w2 = 0.5;
rwid = 0;
rhgt = 0;
results = null;
}

/**
* Set the relative weights of the
* two images. Usually, these should add
* up to 1.0, but they don’t have to.
*/
public void setWeights(double img1weight, double img2weight) {
w1 = img1weight;
w2 = img2weight;
}

/**
* Generate the merged image and store it
* for later hand-off to an ImageConsumer.
* The caller must supply a Component c on which
* the image will eventually be drawn.
*/
public boolean generate(Component comp) {
MediaTracker mt;
mt = new MediaTracker(comp);
mt.addImage(i1, 1);
mt.addImage(i2, 2);
try { mt.waitForAll(); } catch (Exception ie) { }

int wid1, wid2;
int hgt1, hgt2;

wid1 = i1.getWidth(comp);
wid2 = i2.getWidth(comp);
hgt1 = i1.getHeight(comp);
hgt2 = i2.getHeight(comp);

rwid = Math.max(wid1, wid2);
rhgt = Math.max(hgt1, hgt2);

results = new int[rwid * rhgt];

int [] p1 = new int[rwid * rhgt];
int [] p2 = new int[rwid * rhgt];

PixelGrabber pg1 = new PixelGrabber(i1, 0, 0, wid1, hgt1, p1, 0, rwid);
try { pg1.grabPixels(); } catch (Exception ie1) { }

PixelGrabber pg2 = new PixelGrabber(i2, 0, 0, wid2, hgt2, p2, 0, rwid);
try { pg2.grabPixels(); } catch (Exception ie2) { }

cm = ColorModel.getRGBdefault();

int y, x, rp, rpi;
int red1, red2, redr;
int green1, green2, greenr;
int blue1, blue2, bluer;
int alpha1, alpha2, alphar;
double wgt1, wgt2;

for(y = 0; y < rhgt; y++) {
for(x = 0; x < rwid; x++) {
rpi = y * rwid + x;
rp = 0;
blue1 = p1[rpi] & 0x00ff;
blue2 = p2[rpi] & 0x00ff;
green1 = (p1[rpi] >> 8) & 0×00ff;
green2 = (p2[rpi] >> 8) & 0×00ff;
red1 = (p1[rpi] >> 16) & 0×00ff;
red2 = (p2[rpi] >> 16) & 0×00ff;
alpha1 = (p1[rpi] >> 24) & 0×00ff;
alpha2 = (p2[rpi] >> 24) & 0×00ff;

// Com*****tions for combining the pixels,
// perform this any way you like!
// Here we just use simple weighted addition.
wgt1 = w1 * (alpha1 / 255.0);
wgt2 = w2 * (alpha2 / 255.0);
redr = (int)(red1 * wgt1 + red2 * wgt2);
redr = (redr < 0)?(0):((redr>255)?(255):(redr));
greenr = (int)(green1 * wgt1 + green2 * wgt2);
greenr = (greenr < 0)?(0):((greenr>255)?(255):(greenr));
bluer = (int)(blue1 * wgt1 + blue2 * wgt2);
bluer = (bluer < 0)?(0):((bluer>255)?(255):(bluer));
alphar = 255;

rp = (((((alphar << 8) + (redr & 0x0ff)) << 8) + (greenr & 0x0ff)) << 8) + (bluer & 0x0ff);

// save the pixel
results[rpi] = rp;
}
}
return true;
}

/**
* Simple approach to getting an image - just
* create one using MemoryImageSource.
*/
public Image getGeneratedImage() {
Image ret;
MemoryImageSource mis;
if (results == null) {
Frame dummy = new Frame();
generate(dummy);
dummy.dispose();
}
mis = new MemoryImageSource(rwid, rhgt, cm, results, 0, rwid);
ret = Toolkit.getDefaultToolkit().createImage(mis);
return ret;
}

/**
* Call this to free up pixel storage allocated by
* this ImageMerger object.
*/
public void dispose() {
results = null;
return;
}

}

public ImageCombiner(Image i1, double w1, Image i2, double w2) {
ccnt = 0;
img1 = i1;
img2 = i2;

ic1 = new ImageDisplay(img1, true);
ic1.getFrame().addWindowListener(this);
ic1.placeAndShow(50,50);

ic2 = new ImageDisplay(img2, true);
ic2.getFrame().addWindowListener(this);
ic2.placeAndShow(100,90);

ImageMerger imerge = new ImageMerger(i1, i2);
imerge.setWeights(w1, w2);
imerge.generate(ic2);
imgr = imerge.getGeneratedImage();
imerge.dispose();

icr = new ImageDisplay(imgr, true);
icr.getFrame().addWindowListener(this);
icr.placeAndShow(200,180);
}

public void windowClosing(WindowEvent we) {
we.getWindow().hide();
we.getWindow().dispose();
ccnt++;
if (ccnt >= 3) System.exit(0);
}

public static void main(String [] args) {
if (args.length < 2) {
System.err.println("Too few command-line arguments!");
System.err.println("Usage: java ImageCombiner imagefile1 imagefile2");
System.err.println("Usage: java ImageCombiner imagefile1 weight1 imagefile2 weight2");
System.exit(0);
}

String imgf1, imgf2;
double w1 = 0.5;
double w2 = 0.5;
if (args.length < 4) {
imgf1 = args[0];
imgf2 = args[1];
}
else {
imgf1 = args[0];
w1 = Double.parseDouble(args[1]);
imgf2 = args[2];
w2 = Double.parseDouble(args[3]);
}

Image i1 = Toolkit.getDefaultToolkit().createImage(imgf1);
Image i2 = Toolkit.getDefaultToolkit().createImage(imgf2);

if (i1 == null) {
System.err.println("Could not get image from " + imgf1);
System.exit(1);
}
if (i2 == null) {
System.err.println("Could not get image from " + imgf2);
System.exit(2);
}

ImageCombiner icom = new ImageCombiner(i1, w1, i2, w2);
}
}