Comments (5)
The problem is that you're only getting the metrics of the root GlyphID. What you need to do is get the metrics of each component (potentially) all the way down the tree.
I ended up taking a different approach which I like much better: Instead of passing the metric structure around, I simply implemented a GetGlyphMetric method that internally traverses the glyph tree to find the GlyphID which will supply the metric. Since it doesn't need to traverse the whole tree it's actually pretty efficient. It goes something like this:
function TRedacted.GetGlyphMetric(GlyphIndex: Word): TTrueTypeGlyphMetric;
var
GlyphDataTable: TTrueTypeFontGlyphDataTable;
procedure DoGetGlyphMetric(GlyphIndex: Word; var MetricIndex: Word);
var
Glyph: TCustomTrueTypeFontGlyphData;
i: integer;
CompositeGlyphData: TTrueTypeFontCompositeGlyphData;
ComponentGlyphMetric: TTrueTypeGlyphMetric;
begin
Glyph := GlyphDataTable.GlyphData[GlyphIndex];
// If glyph is a simple glyph then we will just use its index as the metric index.
if (Glyph is TTrueTypeFontSimpleGlyphData) then
// The default MetricIndex value has already been set by the caller.
exit;
// If glyph is a composite glyph, then we will either use its index or one of
// its components index as the metric index.
if Glyph is TTrueTypeFontCompositeGlyphData then
begin
// The default MetricIndex value has already been set by the caller.
CompositeGlyphData := TTrueTypeFontCompositeGlyphData(Glyph);
// Recursively process composite glyph components
for i := 0 to CompositeGlyphData.GlyphCount-1 do
if (CompositeGlyphData.Glyph[i].Flags and TRedactedCompositeGlyph.GLYF_USE_MY_METRICS <> 0) then
begin
// We will use the index of the component. Set MetricIndex and recurse.
MetricIndex := CompositeGlyphData.Glyph[i].GlyphIndex;
DoGetGlyphMetric(CompositeGlyphData.Glyph[i].GlyphIndex, MetricIndex);
// In theory multiple components could set USE_MY_METRICS but we
// ignore that as it doesn't make sense.
exit;
end;
end;
end;
var
MetricIndex: Word;
VerticalMetricsTable: TRedactedVerticalMetricsTable;
begin
Result := Default(TTrueTypeGlyphMetric);
GlyphDataTable := TTrueTypeFontGlyphDataTable(GetTableByTableName('glyf'));
if (GlyphDataTable = nil) then
exit;
MetricIndex := GlyphIndex;
DoGetGlyphMetric(GlyphIndex, MetricIndex);
Result.HorizontalMetric := FHorizontalMetrics.HorizontalMetric[MetricIndex];
VerticalMetricsTable := TRedactedVerticalMetricsTable(GetTableByTableType(TRedactedVerticalMetricsTable.GetTableType));
if (VerticalMetricsTable <> nil) then
Result.VerticalMetric := VerticalMetricsTable.VerticalMetric[MetricIndex];
end;
Regarding implementing point-to-point positioning and hmtx and vmtx
Point-to-point position is pretty easy and the documentation is clear on how it's done. Unfortunately, a key part of that feature is "phantom points" and the details of those seem to be completely undocumented. I know what they represent (the four "corners" of the glyph), but apart from that it's pretty much guesswork.
I have also been unable to find any glyphs that actually use this feature so I'm concentrating on more important stuff for now.
from image32.
Hopefully fixed now.
from image32.
Sorry to keep going about this but I can't see that you're doing anything at all with the hmtx struct.
Its journey starts in GetGlyphMetricsInternal
where you get the metrics for the "root" glyph...
Lines 2001 to 2005 in 20a2ec6
...and pass it on to GetGlyphPaths
:
Line 2009 in 20a2ec6
In GetGlyphPaths
you pass it on to GetCompositeGlyph
:
Line 1592 in 20a2ec6
And GetCompositeGlyph
copies it to a local temporary and passes that recursively on to GetGlyphPaths
, etc., etc.
Lines 1880 to 1881 in 20a2ec6
In GetCompositeGlyph
, once GetGlyphPaths
returns, you examine the composite flag and if USE_MY_METRICS
is set you copy it back from the local:
Lines 1887 to 1888 in 20a2ec6
Now, in none of the above is the metrics actually updated. The structure remains unmodified from start to end.
The problem is that you're only getting the metrics of the root GlyphID. What you need to do is get the metrics of each component (potentially) all the way down the tree.
For example, move the call to GetGlyphHorzMetrics
from GetGlyphMetricsInternal
into GetGlyphPaths
so you're getting the metrics for the glyph component and have GetCompositeGlyph
update the caller's metrics if the USE_MY_METRICS
flag is set. You're almost doing it and it's as if this was your meaning all along.
function TFontReader.GetCompositeGlyph(var tbl_glyf: TFontTable_Glyf;
var tbl_hmtx: TFontTable_Hmtx): TPathsEx;
...
component_tbl_hmtx := Default(TFontTable_Hmtx);
componentPaths := GetGlyphPaths(glyphIndex, component_tbl_hmtx, component_tbl_glyf);
...
if (flag and USE_MY_METRICS <> 0) then
tbl_hmtx := component_tbl_hmtx; //(#24)
from image32.
Btw, I believe the vmtx values should be copied as well. Sorry :-)
If you're planning on implementing point-to-point positioning (ARGS_ARE_XY_VALUES
flag not set) at some time it might be easier to just pass the hmtx and vmtx values as "phantom-points" since you will need those for that anyway.
from image32.
Thanks again Anders for your valuable feedback.
It's been quite a while since I've closely looked at this stuff so I'm rather rusty about this now. I might look at this more closely soonish, but at the moment I'm occupied with other things, including improving the vectorization and color quantization code here.
Regarding implementing point-to-point positioning and hmtx and vmtx: if you can provide code that implements these, or links to where these are implemented elsewhere, I would of course fix this more quickly 😁🤞.
from image32.
Related Issues (20)
- Refresh Bug - Layer 301 example HOT 4
- Glitch when resizing TBitmap HOT 13
- rotate(270) does not adjust with and height for viewport and image when rendering HOT 1
- How to CopyFromBitmap and CopyToBitmap on Lazarus? HOT 8
- Wrong Encoding Detection when file has no BOM
- TImageFormat_QOI.SaveToStream declaration error
- Delphi 12 Packages
- Typos in Package HOT 2
- Layered images on top of a TPanel HOT 1
- SetRoundMode should be used with try/finally
- [Feature Request] A flag to enable/disable CropTransparentPixels
- SetRoundMode should not be used at all ;) HOT 13
- Issues when building Mac Os 64 Bit HOT 10
- (out of topic) Simple Sudoku HOT 2
- FR: SVG Image element HOT 7
- Png file shows only part of the SVG file HOT 4
- BicubicResample() and tiny height HOT 4
- Delphi 12.1 compilation for IOS and Android error HOT 1
- Wrong colors HOT 2
- [dcc64 Error] Unit1.pas(216): E2003 Undeclared identifier: 'InterpolatePoints' when complie Vectorize demo HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from image32.