this is fontconfig pattern
Signed-off-by: Muhammad Faiz <mfcc64@gmail.com>
... | ... |
@@ -16870,6 +16870,10 @@ use embedded font. Note that drawing with font file or embedded font is not |
16870 | 16870 |
implemented with custom @var{basefreq} and @var{endfreq}, use @var{axisfile} |
16871 | 16871 |
option instead. |
16872 | 16872 |
|
16873 |
+@item font |
|
16874 |
+Specify fontconfig pattern. This has lower priority than @var{fontfile}. |
|
16875 |
+The : in the pattern may be replaced by | to avoid unnecessary escaping. |
|
16876 |
+ |
|
16873 | 16877 |
@item fontcolor |
16874 | 16878 |
Specify font color expression. This is arithmetic expression that should return |
16875 | 16879 |
integer value 0xRRGGBB. It can contain variables: |
... | ... |
@@ -16993,6 +16997,12 @@ fontcolor='if(mod(floor(midi(f)+0.5),12), 0x0000FF, g(1))':fontfile=myfont.ttf |
16993 | 16993 |
@end example |
16994 | 16994 |
|
16995 | 16995 |
@item |
16996 |
+Custom font using fontconfig: |
|
16997 |
+@example |
|
16998 |
+font='Courier New,Monospace,mono|bold' |
|
16999 |
+@end example |
|
17000 |
+ |
|
17001 |
+@item |
|
16996 | 17002 |
Custom frequency range with custom axis using image file: |
16997 | 17003 |
@example |
16998 | 17004 |
axisfile=myaxis.png:basefreq=40:endfreq=10000 |
... | ... |
@@ -36,6 +36,10 @@ |
36 | 36 |
#include FT_FREETYPE_H |
37 | 37 |
#endif |
38 | 38 |
|
39 |
+#if CONFIG_LIBFONTCONFIG |
|
40 |
+#include <fontconfig/fontconfig.h> |
|
41 |
+#endif |
|
42 |
+ |
|
39 | 43 |
#include "avf_showcqt.h" |
40 | 44 |
|
41 | 45 |
#define BASEFREQ 20.01523126408007475 |
... | ... |
@@ -78,7 +82,8 @@ static const AVOption showcqt_options[] = { |
78 | 78 |
{ "tlength", "set tlength", OFFSET(tlength), AV_OPT_TYPE_STRING, { .str = TLENGTH }, CHAR_MIN, CHAR_MAX, FLAGS }, |
79 | 79 |
{ "count", "set transform count", OFFSET(count), AV_OPT_TYPE_INT, { .i64 = 6 }, 1, 30, FLAGS }, |
80 | 80 |
{ "fcount", "set frequency count", OFFSET(fcount), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 10, FLAGS }, |
81 |
- { "fontfile", "set axis font", OFFSET(fontfile), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, FLAGS }, |
|
81 |
+ { "fontfile", "set axis font file", OFFSET(fontfile), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, FLAGS }, |
|
82 |
+ { "font", "set axis font", OFFSET(font), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, FLAGS }, |
|
82 | 83 |
{ "fontcolor", "set font color", OFFSET(fontcolor), AV_OPT_TYPE_STRING, { .str = FONTCOLOR }, CHAR_MIN, CHAR_MAX, FLAGS }, |
83 | 84 |
{ "axisfile", "set axis image", OFFSET(axisfile), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, FLAGS }, |
84 | 85 |
{ "axis", "draw axis", OFFSET(axis), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, FLAGS }, |
... | ... |
@@ -492,7 +497,7 @@ static int init_axis_color(ShowCQTContext *s, AVFrame *tmp, int half) |
492 | 492 |
return 0; |
493 | 493 |
} |
494 | 494 |
|
495 |
-static int render_freetype(ShowCQTContext *s, AVFrame *tmp) |
|
495 |
+static int render_freetype(ShowCQTContext *s, AVFrame *tmp, char *fontfile) |
|
496 | 496 |
{ |
497 | 497 |
#if CONFIG_LIBFREETYPE |
498 | 498 |
const char *str = "EF G A BC D "; |
... | ... |
@@ -506,13 +511,13 @@ static int render_freetype(ShowCQTContext *s, AVFrame *tmp) |
506 | 506 |
int non_monospace_warning = 0; |
507 | 507 |
int x; |
508 | 508 |
|
509 |
- if (!s->fontfile) |
|
509 |
+ if (!fontfile) |
|
510 | 510 |
return AVERROR(EINVAL); |
511 | 511 |
|
512 | 512 |
if (FT_Init_FreeType(&lib)) |
513 | 513 |
goto fail; |
514 | 514 |
|
515 |
- if (FT_New_Face(lib, s->fontfile, 0, &face)) |
|
515 |
+ if (FT_New_Face(lib, fontfile, 0, &face)) |
|
516 | 516 |
goto fail; |
517 | 517 |
|
518 | 518 |
if (FT_Set_Char_Size(face, 16*64, 0, 0, 0)) |
... | ... |
@@ -565,17 +570,81 @@ static int render_freetype(ShowCQTContext *s, AVFrame *tmp) |
565 | 565 |
return 0; |
566 | 566 |
|
567 | 567 |
fail: |
568 |
- av_log(s->ctx, AV_LOG_WARNING, "error while loading freetype font, using default font instead.\n"); |
|
568 |
+ av_log(s->ctx, AV_LOG_WARNING, "error while loading freetype font.\n"); |
|
569 | 569 |
FT_Done_Face(face); |
570 | 570 |
FT_Done_FreeType(lib); |
571 | 571 |
return AVERROR(EINVAL); |
572 | 572 |
#else |
573 |
- if (s->fontfile) |
|
573 |
+ if (fontfile) |
|
574 | 574 |
av_log(s->ctx, AV_LOG_WARNING, "freetype is not available, ignoring fontfile option.\n"); |
575 | 575 |
return AVERROR(EINVAL); |
576 | 576 |
#endif |
577 | 577 |
} |
578 | 578 |
|
579 |
+static int render_fontconfig(ShowCQTContext *s, AVFrame *tmp, char* font) |
|
580 |
+{ |
|
581 |
+#if CONFIG_LIBFONTCONFIG |
|
582 |
+ FcConfig *fontconfig; |
|
583 |
+ FcPattern *pat, *best; |
|
584 |
+ FcResult result = FcResultMatch; |
|
585 |
+ char *filename; |
|
586 |
+ int i, ret; |
|
587 |
+ |
|
588 |
+ if (!font) |
|
589 |
+ return AVERROR(EINVAL); |
|
590 |
+ |
|
591 |
+ for (i = 0; font[i]; i++) { |
|
592 |
+ if (font[i] == '|') |
|
593 |
+ font[i] = ':'; |
|
594 |
+ } |
|
595 |
+ |
|
596 |
+ if (!(fontconfig = FcInitLoadConfigAndFonts())) { |
|
597 |
+ av_log(s->ctx, AV_LOG_ERROR, "impossible to init fontconfig.\n"); |
|
598 |
+ return AVERROR_UNKNOWN; |
|
599 |
+ } |
|
600 |
+ |
|
601 |
+ if (!(pat = FcNameParse((uint8_t *)font))) { |
|
602 |
+ av_log(s->ctx, AV_LOG_ERROR, "could not parse fontconfig pat.\n"); |
|
603 |
+ FcConfigDestroy(fontconfig); |
|
604 |
+ return AVERROR(EINVAL); |
|
605 |
+ } |
|
606 |
+ |
|
607 |
+ FcDefaultSubstitute(pat); |
|
608 |
+ |
|
609 |
+ if (!FcConfigSubstitute(fontconfig, pat, FcMatchPattern)) { |
|
610 |
+ av_log(s->ctx, AV_LOG_ERROR, "could not substitue fontconfig options.\n"); |
|
611 |
+ FcPatternDestroy(pat); |
|
612 |
+ FcConfigDestroy(fontconfig); |
|
613 |
+ return AVERROR(ENOMEM); |
|
614 |
+ } |
|
615 |
+ |
|
616 |
+ best = FcFontMatch(fontconfig, pat, &result); |
|
617 |
+ FcPatternDestroy(pat); |
|
618 |
+ |
|
619 |
+ ret = AVERROR(EINVAL); |
|
620 |
+ if (!best || result != FcResultMatch) { |
|
621 |
+ av_log(s->ctx, AV_LOG_ERROR, "cannot find a valid font for %s.\n", font); |
|
622 |
+ goto fail; |
|
623 |
+ } |
|
624 |
+ |
|
625 |
+ if (FcPatternGetString(best, FC_FILE, 0, (FcChar8 **)&filename) != FcResultMatch) { |
|
626 |
+ av_log(s->ctx, AV_LOG_ERROR, "no file path for %s\n", font); |
|
627 |
+ goto fail; |
|
628 |
+ } |
|
629 |
+ |
|
630 |
+ ret = render_freetype(s, tmp, filename); |
|
631 |
+ |
|
632 |
+fail: |
|
633 |
+ FcPatternDestroy(best); |
|
634 |
+ FcConfigDestroy(fontconfig); |
|
635 |
+ return ret; |
|
636 |
+#else |
|
637 |
+ if (font) |
|
638 |
+ av_log(s->ctx, AV_LOG_WARNING, "fontconfig is not available, ignoring font option.\n"); |
|
639 |
+ return AVERROR(EINVAL); |
|
640 |
+#endif |
|
641 |
+} |
|
642 |
+ |
|
579 | 643 |
static int render_default_font(AVFrame *tmp) |
580 | 644 |
{ |
581 | 645 |
const char *str = "EF G A BC D "; |
... | ... |
@@ -615,7 +684,9 @@ static int init_axis_from_font(ShowCQTContext *s) |
615 | 615 |
if (!(s->axis_frame = av_frame_alloc())) |
616 | 616 |
goto fail; |
617 | 617 |
|
618 |
- if (render_freetype(s, tmp) < 0 && (default_font = 1, ret = render_default_font(tmp)) < 0) |
|
618 |
+ if (render_freetype(s, tmp, s->fontfile) < 0 && |
|
619 |
+ render_fontconfig(s, tmp, s->font) < 0 && |
|
620 |
+ (default_font = 1, ret = render_default_font(tmp)) < 0) |
|
619 | 621 |
goto fail; |
620 | 622 |
|
621 | 623 |
if (default_font) |