# HG changeset patch # User Edouard Tisserant # Date 1617108883 -7200 # Node ID 938b55abe9469986b77050bdca40a3d245269be3 # Parent 0ddefd20ca2b3c0c71ce32ab82e8500944795173 SVGHMI: Implemented "Add Font" and "Remove Font", add font embedding in CSS at build time, tested ok with some OTF for now. diff -r 0ddefd20ca2b -r 938b55abe946 svghmi/fonts.py --- a/svghmi/fonts.py Tue Mar 30 10:05:55 2021 +0200 +++ b/svghmi/fonts.py Tue Mar 30 14:54:43 2021 +0200 @@ -17,14 +17,17 @@ """ familyname = None + uniquename = None formatname = None mimetype = None font = ttLib.TTFont(filename) # https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6name.html for name in font["name"].names: - if name.nameID==1 and name.platformID in [0,3]: + if name.nameID in [1,16] and name.platformID==3 and name.langID==1033: familyname = name.toUnicode() + if name.nameID==4 and name.platformID==3 and name.langID==1033: + uniquename = name.toUnicode() if font.flavor : # woff and woff2 @@ -32,13 +35,13 @@ mimetype = "font/" + formatname # conditions on sfntVersion was deduced from fontTools.ttLib.sfnt elif font.sfntVersion in ("\x00\x01\x00\x00", "true"): - formatname = "truetype" + formatname = "truetype" mimetype = "font/ttf" elif font.sfntVersion == "OTTO": formatname = "opentype" mimetype = "font/otf" - return familyname,formatname,mimetype + return familyname,uniquename,formatname,mimetype def DataURIFromFile(filename, mimetype): with open(filename, "rb") as fp: @@ -50,7 +53,7 @@ b64encode(data).strip()]) def GetCSSFontFaceFromFontFile(filename): - familyname, formatname, mimetype = GetFontTypeAndFamilyName(filename) + familyname, uniquename, formatname, mimetype = GetFontTypeAndFamilyName(filename) data_uri = DataURIFromFile(filename, mimetype) css_font_face = \ """ diff -r 0ddefd20ca2b -r 938b55abe946 svghmi/gen_index_xhtml.xslt --- a/svghmi/gen_index_xhtml.xslt Tue Mar 30 10:05:55 2021 +0200 +++ b/svghmi/gen_index_xhtml.xslt Tue Mar 30 14:54:43 2021 +0200 @@ -1,6 +1,6 @@ - - + + @@ -1713,7 +1713,7 @@ - + diff -r 0ddefd20ca2b -r 938b55abe946 svghmi/gen_index_xhtml.ysl2 --- a/svghmi/gen_index_xhtml.ysl2 Tue Mar 30 10:05:55 2021 +0200 +++ b/svghmi/gen_index_xhtml.ysl2 Tue Mar 30 14:54:43 2021 +0200 @@ -69,7 +69,11 @@ html xmlns="http://www.w3.org/1999/xhtml" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" { - head; + head { + style type="text/css" media="screen" { + value "ns:GetFonts()"; + } + } // prevents user selection by mouse click / touch and drag // prevents pinch zoom and other accidental panning panning with touch devices body style="margin:0;overflow:hidden;user-select:none;touch-action:none;" { diff -r 0ddefd20ca2b -r 938b55abe946 svghmi/svghmi.py --- a/svghmi/svghmi.py Tue Mar 30 10:05:55 2021 +0200 +++ b/svghmi/svghmi.py Tue Mar 30 14:54:43 2021 +0200 @@ -313,7 +313,7 @@ { "bitmap": "AddFont", "name": _("Add Font"), - "tooltip": _("Add TTF, OTH or WOFF font to be embedded in HMI"), + "tooltip": _("Add TTF, OTF or WOFF font to be embedded in HMI"), "method": "_AddFont" }, { @@ -400,6 +400,18 @@ return ret + def GetFonts(self, _context): + project_path = self.CTNPath() + fontdir = os.path.join(project_path, "fonts") + css_parts = [] + + for f in sorted(os.listdir(fontdir)): + fontfile = os.path.join(fontdir,f) + if os.path.isfile(fontfile): + css_parts.append(GetCSSFontFaceFromFontFile(fontfile)) + + return "".join(css_parts) + times_msgs = {} indent = 1 def ProgressStart(self, k, m): @@ -455,6 +467,7 @@ [("GetSVGGeometry", lambda *_ignored:self.GetSVGGeometry()), ("GetHMITree", lambda *_ignored:self.GetHMITree()), ("GetTranslations", self.GetTranslations), + ("GetFonts", self.GetFonts), ("ProgressStart", lambda _ign,k,m:self.ProgressStart(str(k),str(m))), ("ProgressEnd", lambda _ign,k:self.ProgressEnd(str(k)))]) @@ -618,10 +631,62 @@ self.GetCTRoot().logger.write_error(_("POT file does not exist, add translatable text (label starting with '_') in Inkscape first\n")) def _AddFont(self): - pass + dialog = wx.FileDialog( + self.GetCTRoot().AppFrame, + _("Choose a font"), + os.path.expanduser("~"), + "", + _("Font files (*.ttf;*.otf;*.woff;*.woff2)|*.ttf;*.otf;*.woff;*.woff2"), wx.OPEN) + + if dialog.ShowModal() == wx.ID_OK: + fontfile = dialog.GetPath() + if os.path.isfile(fontfile): + familyname, uniquename, formatname, mimetype = GetFontTypeAndFamilyName(fontfile) + else: + self.GetCTRoot().logger.write_error( + _('Selected font %s is not a readable file\n')%fontfile) + return + if familyname is None or uniquename is None or formatname is None or mimetype is None: + self.GetCTRoot().logger.write_error( + _('Selected font file %s is invalid or incompatible\n')%fontfile) + return + + project_path = self.CTNPath() + + fontfname = uniquename + "." + mimetype.split('/')[1] + fontdir = os.path.join(project_path, "fonts") + newfontfile = os.path.join(fontdir, fontfname) + + if not os.path.exists(fontdir): + os.mkdir(fontdir) + + shutil.copyfile(fontfile, newfontfile) + + self.GetCTRoot().logger.write( + _('Added font %s as %s\n')%(fontfile,newfontfile)) def _DelFont(self): - pass + project_path = self.CTNPath() + fontdir = os.path.join(project_path, "fonts") + dialog = wx.FileDialog( + self.GetCTRoot().AppFrame, + _("Choose a font to remove"), + fontdir, + "", + _("Font files (*.ttf;*.otf;*.woff;*.woff2)|*.ttf;*.otf;*.woff;*.woff2"), wx.OPEN) + if dialog.ShowModal() == wx.ID_OK: + fontfile = dialog.GetPath() + if os.path.isfile(fontfile): + if os.path.relpath(fontfile, fontdir) == os.path.basename(fontfile): + os.remove(fontfile) + self.GetCTRoot().logger.write( + _('Removed font %s\n')%fontfile) + else: + self.GetCTRoot().logger.write_error( + _("Font to remove %s is not in %s\n") % (fontfile,fontdir)) + else: + self.GetCTRoot().logger.write_error( + _("Font file does not exist: %s\n") % fontfile) def CTNGlobalInstances(self): # view_name = self.BaseParams.getName()