pnmtext is moved to panda

This commit is contained in:
David Rose 2003-09-09 19:30:58 +00:00
parent abb0c97f85
commit 22266d04a2
7 changed files with 15 additions and 737 deletions

View File

@ -6,7 +6,7 @@
#define TARGET indexify
#define OTHER_LIBS \
progbase pandatoolbase \
pnmimage:c pnmimagetypes:c panda:m pandaexpress:m \
pnmtext:c pnmimage:c pnmimagetypes:c panda:m pandaexpress:m \
dtool:m dtoolconfig:m \
pystub
@ -17,9 +17,7 @@
indexParameters.cxx indexParameters.h \
indexify.cxx indexify.h \
photo.cxx photo.h \
rollDirectory.cxx rollDirectory.h \
pnmTextGlyph.cxx pnmTextGlyph.h \
pnmTextMaker.cxx pnmTextMaker.h
rollDirectory.cxx rollDirectory.h
#end bin_target
@ -29,14 +27,12 @@
#define TARGET font-samples
#define OTHER_LIBS \
progbase pandatoolbase \
pnmimage:c pnmimagetypes:c panda:m pandaexpress:m \
pnmtext:c pnmimage:c pnmimagetypes:c panda:m pandaexpress:m \
dtool:m dtoolconfig:m \
pystub
#define SOURCES \
default_font.cxx default_font.h \
fontSamples.cxx fontSamples.h \
pnmTextGlyph.cxx pnmTextGlyph.h \
pnmTextMaker.cxx pnmTextMaker.h
fontSamples.cxx fontSamples.h
#end bin_target

View File

@ -181,7 +181,8 @@ post_command_line() {
}
if (_name_text_maker != (PNMTextMaker *)NULL) {
_name_text_maker->set_pixel_size(_name_height, _font_aa_factor);
_name_text_maker->set_scale_factor(_font_aa_factor);
_name_text_maker->set_pixel_size(_name_height);
} else {
_name_height = 0;
}
@ -229,7 +230,8 @@ run() {
if (!text_maker->is_valid()) {
all_ok = false;
} else {
text_maker->set_pixel_size(_sample_height, _font_aa_factor);
text_maker->set_scale_factor(_font_aa_factor);
text_maker->set_pixel_size(_sample_height);
text_maker->generate_into(_sample_text, output_image,
16, y + _sample_height);
if (_name_text_maker != (PNMTextMaker *)NULL) {
@ -243,10 +245,6 @@ run() {
delete text_maker;
}
if (!all_ok) {
exit(1);
}
snprintf(output_filename, output_filename_size,
_output_filename.c_str(), output_index);
nout << "Writing " << output_filename << "\n";
@ -254,6 +252,11 @@ run() {
nout << "Unable to write to " << output_filename << "\n";
exit(1);
}
if (!all_ok) {
nout << "Problem loading fonts.\n";
exit(1);
}
}

View File

@ -386,7 +386,8 @@ post_command_line() {
}
if (_text_maker != (PNMTextMaker *)NULL) {
_text_maker->set_pixel_size(caption_font_size, _font_aa_factor);
_text_maker->set_scale_factor(_font_aa_factor);
_text_maker->set_pixel_size(caption_font_size);
_text_maker->set_align(PNMTextMaker::A_center);
}
}

View File

@ -1,145 +0,0 @@
// Filename: pnmTextGlyph.cxx
// Created by: drose (03Apr02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "pnmTextGlyph.h"
////////////////////////////////////////////////////////////////////
// Function: PNMTextGlyph::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
PNMTextGlyph::
PNMTextGlyph(double advance) :
_advance(advance)
{
_left = 0;
_top = 0;
_int_advance = (int)floor(_advance + 0.5);
}
////////////////////////////////////////////////////////////////////
// Function: PNMTextGlyph::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
PNMTextGlyph::
~PNMTextGlyph() {
}
////////////////////////////////////////////////////////////////////
// Function: PNMTextGlyph::rescale
// Access: Public
// Description: After the image has been rendered large by FreeType,
// scales it small again for placing.
////////////////////////////////////////////////////////////////////
void PNMTextGlyph::
rescale(double scale_factor) {
if (scale_factor == 1.0) {
return;
}
nassertv(scale_factor != 0.0);
_advance /= scale_factor;
_int_advance = (int)floor(_advance + 0.5);
if (_image.is_valid()) {
int orig_x_size = _image.get_x_size();
int orig_y_size = _image.get_y_size();
int orig_left = _left;
int orig_top = _top;
// Pad the image by a few pixels all around to allow for
// antialiasing at the edges.
int extra_pad = (int)ceil(scale_factor);
orig_x_size += 2*extra_pad;
orig_y_size += 2*extra_pad;
orig_left -= extra_pad;
orig_top += extra_pad;
// Now compute the reduced size.
int new_x_size = (int)ceil(orig_x_size / scale_factor);
int new_y_size = (int)ceil(orig_y_size / scale_factor);
int new_left = (int)floor(orig_left / scale_factor);
int new_top = (int)ceil(orig_top / scale_factor);
// And scale those back up so we can determine the amount of
// additional padding we need to make the pixels remain in the
// right place after the integer reduction.
int old_x_size = (int)(new_x_size * scale_factor + 0.5);
int old_y_size = (int)(new_y_size * scale_factor + 0.5);
int old_left = (int)(new_left * scale_factor + 0.5);
int old_top = (int)(new_top * scale_factor + 0.5);
int pad_left = orig_left - old_left;
int pad_top = old_top - orig_top;
// These shouldn't go negative.
nassertv(extra_pad + pad_left >= 0 && extra_pad + pad_top >= 0);
PNMImage enlarged(old_x_size, old_y_size, 1);
enlarged.fill(1, 1, 1);
enlarged.copy_sub_image(_image, pad_left + extra_pad, pad_top + extra_pad);
_image.clear(new_x_size, new_y_size, 1);
_image.quick_filter_from(enlarged);
_left = new_left;
_top = new_top;
}
}
////////////////////////////////////////////////////////////////////
// Function: PNMTextGlyph::get_advance
// Access: Public
// Description: Returns the number of pixels by which the pen should
// be advanced after rendering this glyph.
////////////////////////////////////////////////////////////////////
int PNMTextGlyph::
get_advance() const {
return _int_advance;
}
////////////////////////////////////////////////////////////////////
// Function: PNMTextGlyph::place
// Access: Public
// Description: Copies the glyph to the indicated destination image
// at the indicated origin.
////////////////////////////////////////////////////////////////////
void PNMTextGlyph::
place(PNMImage &dest_image, int xp, int yp) {
if (!_image.is_valid()) {
// If we have no image, do nothing.
return;
}
int left = xp + _left;
int top = yp - _top;
int right = left + _image.get_x_size();
int bottom = top + _image.get_y_size();
// Clip the glyph to the destination image.
int cleft = max(left, 0);
int ctop = max(top, 0);
int cright = min(right, dest_image.get_x_size());
int cbottom = min(bottom, dest_image.get_y_size());
for (int y = ctop; y < cbottom; y++) {
for (int x = cleft; x < cright; x++) {
double gval = _image.get_gray(x - left, y - top);
dest_image.set_xel(x, y, dest_image.get_xel(x, y) * gval);
}
}
}

View File

@ -1,50 +0,0 @@
// Filename: pnmTextGlyph.h
// Created by: drose (03Apr02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef PNMTEXTGLYPH_H
#define PNMTEXTGLYPH_H
#include "pandatoolbase.h"
#include "pnmImage.h"
////////////////////////////////////////////////////////////////////
// Class : PNMTextGlyph
// Description : A single glyph in a PNMTextMaker.
////////////////////////////////////////////////////////////////////
class PNMTextGlyph {
public:
PNMTextGlyph(double advance);
~PNMTextGlyph();
void rescale(double scale_factor);
int get_advance() const;
void place(PNMImage &dest_image, int xp, int yp);
private:
PNMImage _image;
int _top;
int _left;
double _advance;
int _int_advance;
friend class PNMTextMaker;
};
#endif

View File

@ -1,444 +0,0 @@
// Filename: textMaker.cxx
// Created by: drose (03Apr02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "pnmTextMaker.h"
#include "pnmTextGlyph.h"
#include "filename.h"
#include "pnmImage.h"
FT_Library PNMTextMaker::_ft_library;
bool PNMTextMaker::_ft_initialized = false;
bool PNMTextMaker::_ft_ok = false;
////////////////////////////////////////////////////////////////////
// Function: PNMTextMaker::Constructor
// Access: Public
// Description: The constructor expects the name of some font file
// that FreeType can read, along with face_index,
// indicating which font within the file to load
// (usually 0).
////////////////////////////////////////////////////////////////////
PNMTextMaker::
PNMTextMaker(const Filename &font_filename, int face_index) {
_is_valid = false;
if (!_ft_initialized) {
initialize_ft_library();
}
if (!_ft_ok) {
nout
<< "Unable to read font " << font_filename
<< ": FreeType library not initialized properly.\n";
return;
}
Filename path(font_filename);
if (!path.exists()) {
nout << "Unable to find font file " << font_filename << "\n";
} else {
string os_specific = path.to_os_specific();
int error = FT_New_Face(_ft_library,
os_specific.c_str(),
face_index,
&_face);
if (error == FT_Err_Unknown_File_Format) {
nout << "Unable to read font " << font_filename << ": unknown file format.\n";
} else if (error) {
nout << "Unable to read font " << font_filename << ": invalid.\n";
} else {
string name = _face->family_name;
if (_face->style_name != NULL) {
name += " ";
name += _face->style_name;
}
set_name(name);
// Maybe we don't care about enforcing this. It doesn't work
// with older versions of FreeType anyway.
/*
error = FT_Select_Charmap(_face, ft_encoding_unicode);
if (error) {
error = FT_Select_Charmap(_face, ft_encoding_latin_2);
}
if (error) {
nout << "Unable to select ISO encoding for " << get_name() << ".\n";
FT_Done_Face(_face);
} else */
{
nout << "Loaded font " << get_name() << "\n";
_is_valid = true;
_scale_factor = 0.0;
}
}
}
_align = A_left;
}
////////////////////////////////////////////////////////////////////
// Function: PNMTextMaker::Constructor
// Access: Public
// Description: This constructor works as above, but it takes the
// font data from an in-memory buffer instead of from a
// named file.
////////////////////////////////////////////////////////////////////
PNMTextMaker::
PNMTextMaker(const char *font_data, int font_data_size, int face_index) {
_is_valid = false;
if (!_ft_initialized) {
initialize_ft_library();
}
if (!_ft_ok) {
nout
<< "Unable to read internal font: FreeType library not initialized properly.\n";
return;
}
int error = FT_New_Memory_Face(_ft_library,
(FT_Byte *)font_data, font_data_size,
face_index,
&_face);
if (error == FT_Err_Unknown_File_Format) {
nout << "Unable to read internal font: unknown file format.\n";
} else if (error) {
nout << "Unable to read internal font: invalid.\n";
} else {
string name = _face->family_name;
if (_face->style_name != NULL) {
name += " ";
name += _face->style_name;
}
set_name(name);
error = FT_Select_Charmap(_face, ft_encoding_unicode);
if (error) {
error = FT_Select_Charmap(_face, ft_encoding_latin_2);
}
if (error) {
nout << "Unable to select ISO encoding for " << get_name() << ".\n";
FT_Done_Face(_face);
} else {
_is_valid = true;
_scale_factor = 0.0;
}
}
_align = A_left;
}
////////////////////////////////////////////////////////////////////
// Function: PNMTextMaker::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
PNMTextMaker::
~PNMTextMaker() {
empty_cache();
if (_is_valid) {
FT_Done_Face(_face);
_is_valid = false;
}
}
////////////////////////////////////////////////////////////////////
// Function: PNMTextMaker::is_valid
// Access: Public
// Description: Returns true if the PNMTextMaker is valid and ready to
// generate text, false otherwise.
////////////////////////////////////////////////////////////////////
bool PNMTextMaker::
is_valid() const {
return _is_valid;
}
////////////////////////////////////////////////////////////////////
// Function: PNMTextMaker::set_pixel_size
// Access: Public
// Description: Specifies the pixel size of the font to use to
// generate future text. If the scale_factor is
// specified, it is the factor by which to scale up the
// font glyphs internally before reducing them to the
// final output pixel_size; this works around problems
// FreeType has with antialiasing small pixel sizes.
//
// If the font contains one or more fixed-size fonts
// instead of a scalable font, this will ignore the
// supplied scale_factor and automatically choose the
// scale_factor to produce the requested pixel_size
// output from the closest matching input size.
////////////////////////////////////////////////////////////////////
void PNMTextMaker::
set_pixel_size(int pixel_size, double scale_factor) {
nassertv(_is_valid);
reset_scale(pixel_size, scale_factor);
empty_cache();
}
////////////////////////////////////////////////////////////////////
// Function: PNMTextMaker::set_align
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
void PNMTextMaker::
set_align(PNMTextMaker::Alignment align_type) {
if (_align != align_type) {
_align = align_type;
}
}
////////////////////////////////////////////////////////////////////
// Function: PNMTextMaker::get_align
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
PNMTextMaker::Alignment PNMTextMaker::
get_align() const {
return _align;
}
////////////////////////////////////////////////////////////////////
// Function: PNMTextMaker::generate_into
// Access: Public
// Description: Generates text into the indicated image at the
// indicated position.
////////////////////////////////////////////////////////////////////
void PNMTextMaker::
generate_into(const string &text, PNMImage &dest_image, int x, int y) {
// First, measure the total width in pixels.
int width = 0;
string::const_iterator ti;
for (ti = text.begin(); ti != text.end(); ++ti) {
int ch = (unsigned char)(*ti);
PNMTextGlyph *glyph = get_glyph(ch);
width += glyph->get_advance();
}
int xp;
int yp = y;
switch (_align) {
case A_left:
xp = x;
break;
case A_center:
xp = x - (width / 2);
break;
case A_right:
xp = x - width;
break;
}
// Now place the text.
for (ti = text.begin(); ti != text.end(); ++ti) {
int ch = (unsigned char)(*ti);
PNMTextGlyph *glyph = get_glyph(ch);
glyph->place(dest_image, xp, yp);
xp += glyph->get_advance();
}
}
////////////////////////////////////////////////////////////////////
// Function: PNMTextMaker::get_glyph
// Access: Private
// Description: Returns the glyph for the indicated index, or NULL if
// it is not defined in the font.
////////////////////////////////////////////////////////////////////
PNMTextGlyph *PNMTextMaker::
get_glyph(int character) {
int glyph_index = FT_Get_Char_Index(_face, character);
Glyphs::iterator gi;
gi = _glyphs.find(glyph_index);
if (gi != _glyphs.end()) {
return (*gi).second;
}
PNMTextGlyph *glyph = make_glyph(glyph_index);
_glyphs.insert(Glyphs::value_type(glyph_index, glyph));
return glyph;
}
////////////////////////////////////////////////////////////////////
// Function: PNMTextMaker::make_glyph
// Access: Private
// Description: Creates a new PNMTextGlyph object for the indicated
// index, if possible.
////////////////////////////////////////////////////////////////////
PNMTextGlyph *PNMTextMaker::
make_glyph(int glyph_index) {
int error = FT_Load_Glyph(_face, glyph_index, FT_LOAD_RENDER);
if (error) {
nout << "Unable to render glyph " << glyph_index << "\n";
return (PNMTextGlyph *)NULL;
}
FT_GlyphSlot slot = _face->glyph;
FT_Bitmap &bitmap = slot->bitmap;
double advance = slot->advance.x / 64.0;
if (bitmap.width == 0 || bitmap.rows == 0) {
// If we got an empty bitmap, it's a special case.
PNMTextGlyph *glyph = new PNMTextGlyph(advance);
glyph->rescale(_scale_factor);
return glyph;
} else {
PNMTextGlyph *glyph = new PNMTextGlyph(advance);
PNMImage &glyph_image = glyph->_image;
glyph_image.clear(bitmap.width, bitmap.rows, 1);
if (bitmap.pixel_mode == ft_pixel_mode_mono) {
// This is a little bit more work: we have to expand the
// one-bit-per-pixel bitmap into a one-byte-per-pixel texture.
unsigned char *buffer_row = bitmap.buffer;
for (int yi = 0; yi < bitmap.rows; yi++) {
int bit = 0x80;
unsigned char *b = buffer_row;
for (int xi = 0; xi < bitmap.width; xi++) {
if (*b & bit) {
glyph_image.set_gray(xi, yi, 0.0);
} else {
glyph_image.set_gray(xi, yi, 1.0);
}
bit >>= 1;
if (bit == 0) {
++b;
bit = 0x80;
}
}
buffer_row += bitmap.pitch;
}
} else if (bitmap.pixel_mode == ft_pixel_mode_grays) {
// Here we must expand a grayscale pixmap with n levels of gray
// into our 256-level texture.
unsigned char *buffer_row = bitmap.buffer;
for (int yi = 0; yi < bitmap.rows; yi++) {
for (int xi = 0; xi < bitmap.width; xi++) {
double value =
(double)buffer_row[xi] / (double)(bitmap.num_grays - 1);
glyph_image.set_gray(xi, yi, 1.0 - value);
}
buffer_row += bitmap.pitch;
}
} else {
nout << "Unexpected pixel mode in bitmap: " << (int)bitmap.pixel_mode << "\n";
}
glyph->_top = slot->bitmap_top;
glyph->_left = slot->bitmap_left;
glyph->rescale(_scale_factor);
return glyph;
}
}
////////////////////////////////////////////////////////////////////
// Function: PNMTextMaker::reset_scale
// Access: Private
// Description: Sets the font to use the appropriate scale pixels,
// and sets _scale_factor accordingly.
////////////////////////////////////////////////////////////////////
bool PNMTextMaker::
reset_scale(int pixel_size, double scale_factor) {
_scale_factor = scale_factor;
int want_pixel_size = (int)(pixel_size * _scale_factor + 0.5);
int error = FT_Set_Pixel_Sizes(_face, want_pixel_size, want_pixel_size);
if (error) {
// If we were unable to set a particular char size, perhaps we
// have a non-scalable font. Try to figure out the closest
// available size.
int best_size = -1;
if (_face->num_fixed_sizes > 0) {
best_size = 0;
int best_diff = abs(want_pixel_size - _face->available_sizes[0].height);
for (int i = 1; i < _face->num_fixed_sizes; i++) {
int diff = abs(want_pixel_size - _face->available_sizes[i].height);
if (diff < best_diff) {
best_size = i;
best_diff = diff;
}
}
}
if (best_size >= 0) {
int pixel_height = _face->available_sizes[best_size].height;
int pixel_width = _face->available_sizes[best_size].width;
error = FT_Set_Pixel_Sizes(_face, pixel_width, pixel_height);
if (!error) {
_scale_factor = (double)pixel_height / (double)pixel_size;
}
}
}
if (error) {
nout
<< "Unable to set " << get_name()
<< " to " << pixel_size << " pixels.\n";
return false;
}
_line_height = _face->size->metrics.height / 64.0;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PNMTextMaker::empty_cache
// Access: Private
// Description: Empties the cache of previously-generated glyphs.
////////////////////////////////////////////////////////////////////
void PNMTextMaker::
empty_cache() {
Glyphs::iterator gi;
for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
PNMTextGlyph *glyph = (*gi).second;
delete glyph;
}
}
////////////////////////////////////////////////////////////////////
// Function: PNMTextMaker::initialize_ft_library
// Access: Private, Static
// Description: Should be called exactly once to initialize the
// FreeType library.
////////////////////////////////////////////////////////////////////
void PNMTextMaker::
initialize_ft_library() {
if (!_ft_initialized) {
int error = FT_Init_FreeType(&_ft_library);
_ft_initialized = true;
if (error) {
nout << "Unable to initialize FreeType.\n";
} else {
_ft_ok = true;
}
}
}

View File

@ -1,83 +0,0 @@
// Filename: pnmTextMaker.h
// Created by: drose (03Apr02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef PNMTEXTMAKER_H
#define PNMTEXTMAKER_H
#include "pandatoolbase.h"
#include "pmap.h"
#include "namable.h"
#include <ft2build.h>
#include FT_FREETYPE_H
class Filename;
class PNMImage;
class PNMTextGlyph;
////////////////////////////////////////////////////////////////////
// Class : PNMTextMaker
// Description : An object that uses Freetype to generate text at a
// fixed pixel size into a PNMImage.
////////////////////////////////////////////////////////////////////
class PNMTextMaker : public Namable {
public:
PNMTextMaker(const Filename &font_filename, int face_index);
PNMTextMaker(const char *font_data, int font_data_size, int face_index);
~PNMTextMaker();
enum Alignment {
A_left,
A_right,
A_center,
};
bool is_valid() const;
void set_pixel_size(int pixel_size, double scale_factor = 1.0);
void set_align(Alignment align_type);
Alignment get_align() const;
void generate_into(const string &text,
PNMImage &dest_image, int x, int y);
private:
PNMTextGlyph *get_glyph(int character);
PNMTextGlyph *make_glyph(int glyph_index);
bool reset_scale(int pixel_size, double scale_factor);
void empty_cache();
static void initialize_ft_library();
bool _is_valid;
typedef pmap<int, PNMTextGlyph *> Glyphs;
Glyphs _glyphs;
FT_Face _face;
double _scale_factor;
double _line_height;
Alignment _align;
static FT_Library _ft_library;
static bool _ft_initialized;
static bool _ft_ok;
};
#endif