PDA

View Full Version : بدست آوردن x و y نقاط تشکیل دهنده یک حرف در فونت



h00manb
چهارشنبه 16 فروردین 1391, 11:53 صبح
سلام
چطور می توان x و y نقاط تشکیل دهنده یک حرف در فونت ttf مورد نظر را بدست آورد؟
متشکر

h00manb
جمعه 18 فروردین 1391, 06:19 صبح
کسی اطلاع نداره؟

سعید صابری
جمعه 18 فروردین 1391, 20:33 عصر
برای چی میخوای ؟
من 9 سال پیش در پاسکال (16 بیتی)این کارو کردم یک چیزهایی یادمه

SAASTN
جمعه 18 فروردین 1391, 22:47 عصر
اگه می خوای این نقاط رو یه جا نگهداری کنی تا به فونت وابسته نباشی یه راه مضحکش این میشه:
procedure TForm1.Button3Click(Sender: TObject);
var
aRect: TRect;
Text: string;
C: Char;
I, J: Integer;
begin
Image1.Canvas.Font.Name := 'Arial';
Image1.Canvas.Font.Size := 12;
Memo1.Lines.Clear;
for C := 'a' to 'z' do
begin
Text := C;
aRect := Image1.ClientRect;
Image1.Canvas.TextRect(aRect, Text, [tfCalcRect]);
Image1.Width := aRect.Right - aRect.Left;
Image1.Height := aRect.Bottom - aRect.Top;
Image1.Canvas.TextRect(aRect, Text, [tfLeft, tfTop]);
Memo1.Lines.Add(C);
for I := 0 to aRect.Right - 1 do
for J := 0 to aRect.Bottom - 1 do
if Image1.Canvas.Pixels[I, J] <> Image1.Canvas.Brush.Color then
Memo1.Lines.Add(Format('%3d, %3d', [I, J]))
end;
end;

برای چی لازم داری؟ شاید جور دیگه بشه حلش کرد.

mbshareat
شنبه 19 فروردین 1391, 00:24 صبح
سلام
من هم یه سوال دارم ولی فکر نکنم جواب برنامه نویسی داشته باشه:
من می خوام نقطه ها در قلم تاهوما بزرگتر نمایش داده بشه.آیا راهی به غیر از استفاده از برنامه طراحی فونت هست؟

h00manb
شنبه 19 فروردین 1391, 06:43 صبح
سلام
در داخل فونت بعضی از نقاط وجود دارد که در واقع هادی منحنی هستند, در این روش که شما گفتید نقاط خام درون فونت بدست نمیاد
روش بهتری سراغ ندارید؟
(برنامه ای هست که باید یک سری افکتها و حرکتهای دو بعدی و سه بعدی روی نوشته ها انجام بشه که بدون دانستن نقاط فونت امکانش نیست)

SAASTN
شنبه 19 فروردین 1391, 09:23 صبح
در داخل فونت بعضی از نقاط وجود دارد که در واقع هادی منحنی هستند, در این روش که شما گفتید نقاط خام درون فونت بدست نمیاد
خوب وقتی شما میگی x,y نقاط معنیش این میشه که اطلاعات فونت رو بصورت رستر لازم داری. که البته اون کاری رو که می خوای انجام بدی اگه realtime نباشه با پردازش های رستر هم شدنیه. اما وقتی بحث سه بعدی مطرح میشه بهتره که کلا وکتور کار کنی.
برای بدست آوردن اطلاعات وکتور فونت باید از GetGlyphOutline با پارامتر GGO_NATIVE یا GGO_BEZIER استفاده کنی. توی راهنمای دلفی توضیحاتش هست، اینجا (http://ho.runcode.us/q/how-does-getglyphoutline-function-work-winapi) هم یه چیزایی نوشته. کد بدرد بخور پیدا نکردم که لینک بدم، خودتم یخورده بگرد شاید چیزی پیدا کردی. اگه نه که آستینا رو بزن بالا...

من می خوام نقطه ها در قلم تاهوما بزرگتر نمایش داده بشه.آیا راهی به غیر از استفاده از برنامه طراحی فونت هست؟
منم تصور نمی کنم راه برنامه نویسی داشته باشه، شاید با پردازش تصویر بتونی محل نقطه ها رو پیدا کنی و یه کارایی انجام بدی، ولی خیلی بدرد بخور نیست و زمانبر هم میشه.

h00manb
شنبه 19 فروردین 1391, 12:36 عصر
من کد زیر را پیدا کردم
var
dc: hdc;
glyph: TGlyphMetrics;
P: pointer;
Size: Word;
F: File;
const
mat2: TMat2 = (eM11: (Fract: 0; Value: 1); eM12: (fract: 0; Value: 0);
eM21: (Fract: 0; Value: 0); eM22: (fract: 0; Value: 1));

ch = 'a';
font = 'arial';

begin
dc := getdc(0);
selectobject(dc, createfont(400, 0, 0, 0, fw_Normal, 0, 0, 0, ansi_charset,
out_tt_precis, clip_tt_always, proof_quality, ff_dontcare,
font));
textout(dc, 0, 0, ch, 1);
Size := GetGlyphOutLine(dc, word(ch), ggo_native, glyph, 0, nil, mat2);
GetMem(P, Size);
GetGlyphOutLine(dc, word(ch), ggo_native, glyph, Size, P, mat2);
//............
FreeMem(P, Size);
releasedc(0, dc)
end.

اطلاعات بدست آمده از P شروع میشه با حجم Size ولی نمدانم چطوری ازش استفاده کنم, کسی بلد نیست؟

SAASTN
یک شنبه 20 فروردین 1391, 05:39 صبح
بیا برادر، یکم تغییرش دادم:
procedure TForm1.Button1Click(Sender: TObject);
const
Mat2: TMat2 = (eM11: (Fract: 0; Value: 1); eM12: (Fract: 0; Value: 0);
eM21: (Fract: 0; Value: 0); eM22: (Fract: 0; Value: 1));
Ch = '&';
FontName = 'Arial';
FontSize = 200;
var
DC: hdc;
Glyph: TGlyphMetrics;
P, P2: Pointer;
Size, Couner, CurveCounter: Word;
Header: PTTPolygonHeader;
Curve: PTTPolyCurve;
I: Integer;
Points: array of TPoint;
begin
DC := Image1.Canvas.Handle;
Image1.Canvas.Font.Size := FontSize;
Image1.Canvas.Font.Name := FontName;
Image1.Canvas.TextOut(0, 0, Ch);
Size := GetGlyphOutLine(DC, word(Ch), GGO_NATIVE, Glyph, 0, nil, Mat2);
GetMem(P, Size);
GetGlyphOutLine(DC, word(Ch), GGO_NATIVE, Glyph, Size, P, Mat2);
Couner := 0;
P2 := P;
while Couner < SIZE do
begin
Header := P2;
CurveCounter := SizeOf(TTPolygonHeader);
Inc(Couner, SizeOf(TTPolygonHeader));
Image1.Canvas.MoveTo(FontSize + Header^.pfxStart.x.value,
FontSize - Header^.pfxStart.y.value);
while CurveCounter < Header^.cb do
begin
P2 := Pointer(Integer(P) + Couner);
Curve := P2;
case Curve.wType of
TT_PRIM_LINE: ;
TT_PRIM_QSPLINE: ;
end;
for I := 0 to Curve.cpfx - 1 do
Image1.Canvas.LineTo(FontSize + Curve^.apfx[I].x.value,
FontSize - Curve^.apfx[I].Y.value);
Inc(Couner, 2 * SizeOf(Word));
Inc(Couner, SizeOf(TPointfx) * (Curve.cpfx));
P2 := Pointer(Integer(P) + Couner);
Inc(CurveCounter, 2 * SizeOf(Word));
Inc(CurveCounter, SizeOf(TPointfx) * (Curve.cpfx));
end;
Image1.Canvas.LineTo(FontSize+Header^.pfxStart.x.v alue,
FontSize - Header^.pfxStart.y.value);
end;
FreeMem(P, Size);
end;

حالا اینکه اون بالا چه خبره!
خوب احتمالا خودت خوندی که وقتی GetGlyphOutLine رو با nil فراخونی می کنی سایز اطلاعات درخواستی رو برمی گردونه و وقتی nil نباشه اون رو آدرس بافر فرض می کنه و خود اطلاعات رو توی بافر می ریزه. خطهای 22 تا 24 مربوط به این قضیه است. حالا اینکه تو اون بافر چی هست، چندتا چندضلعی یا Polygone هست. مثلا I یک پلی گون داره و i دوتا پلی گون. اما تعداد این پلی گون ها هیچ جا ذکر نمیشه و تنها راهنمای ما طول اون بافرست. یعنی اینقدر باید از بافر بخونیم تا تموم شه (خط 27).
حالا این که هر کدوم از پلی گون ها چی هستن و چجوری معرفی می شن. در ابتدای هر پلی گون اول یه TTPolygonHeader قرار داره که یه سری اطلاعات راجع به پولی گون میده، اول cb که حجم کل اطلاعات پولی گون رو مشخص می کنه، که این حجم مجموع اندازه خود هدر به علاوه بقیه مزخرفاتیه که بعد از هدر میاد هست. بعد dwType که مثلا قراره نوع پولی گون رو مشخص کنه، تو راهنما گفته این مقدار همیشه باید برابر TT_POLYGON_TYPE یا 24 باشه، من یه چندتا رو چک کردم، گوش شیطون کر همش 24 بود. برا همین منم دیگه پاپی نشدم، ولی این بیل گیتس خیر ندیده معمولا این جور چیزا رو تعریف می کنه که بعدا یه کرمی بریزه. آخرسر هم pfxStart میاد که مختصات نقطه ابتدای پولی گون رو مشخص می کنه، پس برا ترسیم اول یه MoveTo میزنیم به این نقطه (خط 32).
بعد از هدر یه تعداد منحنی های مربوط به پلی گون در قالب چندتا TTPolyCurve میاد. باز تعداد اینا مشخص نیست و باید از همون cb هدر کمک بگیریم. یعنی از شروع هدر باید به اندازه cb بخونیم بریم جلو (خط 34). حالا باز خود TTPolyCurve چیه: اول wType که نوع منحنی رو مشخص می کنه، که می تونه TT_PRIM_LINE (خط صاف) یا TT_PRIM_QSPLINE (بزیر مربعی) یا TT_PRIM_CSPLINE (بزیر مکعبی) باشه. بعدش cpfx میاد که تعیین می کنه منحنی چندتا نقطه داره (البته این جا دیگه منت سرمون گذاشتن!) و بعدش هم apfx که یه آرایه از نقاط تشکیل دهنده منحنیه.
فلذا نقاط رو می خونیم تا منحنی تموم شه، منحنی ها رو دونه دونه می خونیم تا به آخر پلی گون برسیم و پلی گون ها رو می خونیم تا کل اطلاعات یه کاراکتر رو به دست بیاریم. کل قضیه هم پوینتر بازیه دیگه، هر چی رو خوندی پوینترتو به اندازه دیتا تایپی که خوندی نسبت به ابتدای بافر می بری جلو.
فقط یه نکته داره که این عزیزان مایکروسافت برای این که خوش بحال برنامه نویسا نشه بعضا منحنی های پولی گون ها رو نمی بندن و نقطه آخر رو رو هوا ول می کنن، برا همین خودت باید نقطه آخر رو به نقطه اول که تو هدر پولی گون معرفی شده بود وصل کنی. البته این همیشگی نیست و بنده چون حس نداشتم منطقشو کشف کنم اخر همه پولی گون ها رو به اولش وصل کردم (خط 51).
همون طور هم که می بینی دیگه من بزیر مزیر نکشیدم و همه رو با LineTo رسم کردم، دیگه خودت اون بخششو ردیف کن.

در نهایت این که اول بگرد یه مقاله درست درمون راجع به TTF و ترسیم فونت توسط ویندوز پیدا کن بخونش چون فضاش یخورده مبهمه.

موفق باشی

h00manb
یک شنبه 20 فروردین 1391, 07:44 صبح
سلام
فکر میکنم منطق نقطه آخر به این صورت هست که اگر این نقطه یک نقطه معمولی باشه مستقیم به نقطه اول وصل میشه اما اگر جزو منحنی باشه با نقطه اول یک منحنی درست میکنه


شما متغیر Image1 را از نوع Tbitmap معرفی کردی؟ در قسمت design پروژه به جز botton1 چیز دیگه ای هم قرار دادی؟
متاسفنه در همان خط اول برای من پیام خطا می دهد
اگر ممکن است پروژه کامل را آپلود کنید
متشکر

mbshareat
یک شنبه 20 فروردین 1391, 09:33 صبح
سلام
من کد رو امتحان کردم به خوبی جواب داد. برای درست کار کردن کد یک دکمه و یک TImage از پالت Additional (البته تو نسخه دفی من!) روی فرم بذار و هرچی تو
TForm1.Button1Click در کد بالا اومده بریز تو رویداد کلیک دکمه. خیلی قشنگ جواب میده. چند روز پیش هم دنبال Gradient می گشتم تصادفی یه برنامه پیدا کردم که منحنی شکسته رو به منحنی نشکسته! تبدیل می کرد ولی نسخه مجانی نبود :bezier_trial!

h00manb
یک شنبه 20 فروردین 1391, 10:20 صبح
منم جواب گرفتم
از همه متشکر

برای رسم منحنی بزیر میشه از تابع زیر استفاده کرد

type
PBezierPoint = ^TBezierPoint;
TBezierPoint = record
X,Y:double; //main node
Xl,Yl:double; //left control point
Xr,Yr:double; //right control point
end;
----------------------------------------------------------------------------------------
//P1 and P2 are two TBezierPoint's, t is between 0 and 1:
//when t=0 X=P1.X, Y=P1.Y; when t=1 X=P2.X, Y=P2.Y;
procedure BezierValue(P1,P2:TBezierPoint; t:double; var X,Y:double);
var t_sq,t_cb,r1,r2,r3,r4:double;
begin
t_sq:=t*t;
t_cb:=t*t_sq;
r1:=(1-3*t+3*t_sq-t_cb)*P1.X;
r2:=(3*t-6*t_sq+3*t_cb)*P1.Xr;
r3:=(3*t_sq-3*t_cb)*P2.Xl;
r4:=(t_cb)*P2.X;
X:=r1+r2+r3+r4;
r1:=(1-3*t+3*t_sq-t_cb)*P1.Y;
r2:=(3*t-6*t_sq+3*t_cb)*P1.Yr;
r3:=(3*t_sq-3*t_cb)*P2.Yl;
r4:=(t_cb)*P2.Y;
Y:=r1+r2+r3+r4;
end;

mbshareat
یک شنبه 20 فروردین 1391, 23:21 عصر
سلام و درود
اگه لطف کنین نحوه استفاده رو هم بذارین ممنون میشم. چون من اصلا نفهمیدم این پروسیجر چه کار می کنه و این TBezierPoint چیه؟!

h00manb
دوشنبه 21 فروردین 1391, 12:11 عصر
سلام
طبق تحقیقی که کردم ماکروسافت برای رسم منحنیها در فونتها از منحنی بزیر ساده استفاده میکنه نه آنچه که در قسمت بالا نوشتم.
به عنوان مثال فرض کنید سه نقطه داریم که دو نقطه ابتدایی و پایانی نقاط ساده و نقطه وسط نقطه مشخصه منحنی باشد (نقطه ای که مشخص میکند منحنی چه شکلی می شود) برای این حالت در قسمت ضمیمه برنامه ای آورده ام که منحنی را رسم میکند (برای تغییر مکان نقاط از دکمه های q تا y و a تا h استفاده کنید. تابع بدست آوردن نقاط منحنی se_noghte_be_monhani نام دارد و بقیه توابع برای آماده سازی صفحه هستند)
حالا فرض کنید چند نقطه داریم که نقطه ابتدا و انتها معمولی و نقاط میانی مشخصه هستند, در این حالت طبق عرف باید از فرمول پیچیده بزیر استفاده کرد اما ماکرو سافت به جای این کار بین هر دو نقطه مشخصه میان یابی کرده (نقطه1 +نقطه2 تقسیم بر 2) و یک نقطه معمولی بدست می آورد که مسئله تبدیل می شود به دو نقطه معمولی با نقطه مشخصه میانی که در بالا اشاره کردم.
موفق باشید