How can I load an external .ttf and use it within the exported application?

Hey there!

Quick question: I wanted to load a custom font from a file (just like in the “Use a custom font” skia example). But I noticed that this font file will not be copied when exporting the application. So the exported application just falls back to a default font.

Below is basically a copy of that example which just loads a .ttf that is in a subdirectory relative to the main document. Like this:

  • Font-Copying.vl
  • Geist_Font/ (folder)
    • GeistMono-Medium.ttf

Is there a way to have that font file land somewhere in the export folder so it can be used from there? Or is that just not possible at the moment? The alternative would of course be to just install the font on the target system (in which case I would have to figure out a way to use fonts that are not normal/bold/italic/bolditalic)

Thank you so much in advance!

Font-Copying.vl (11.5 KB)

Font files need to be treated like any other asset. They are not automatically copied on export. Please see Exporting Applications | vvvv gamma documentation and let us know if you need any more information.

Hey!

Thanks for your reply Joreg! That was the solution and i completely overread that part lol

Bit tedious of course to copy those files but I still prefer that over installing those fonts on that system.

Thanks again!

I have been in the same situation a lot. You simply forget to copy the folder with the static assets into the export. It might be nice to define folders it should copy on Export, but it could also get messy. More importantly it might automatically solve the file paths, so that the assets are still found by the exe. I found that depending on where you export to, now the paths in the application are not pointing to the right location. For example I export to a subfolder called “Export” next to my .vl file. In the exported application I had to now put my asset folder in the parent folder of the .exe for it to find them. If this could be made easier and more reliable, it would be a great improvement.

Maybe it just needs to be made more clear that when you export it already creates a subfolder, so if you export to a subfolder yourself, it now has 2 subfolders. I tend to never export anything into a working folder in fear that it will just dump a load of files in there.

My two cents: I always forgot to copy the GammaLauncher icon when building, so I ended up modifying the .props file to do it automatically. I added the following lines in there after the </PropertyGroup>

  <ItemGroup>
    <ContentWithTargetPath Include="$(MsBuildThisFileDirectory)ico.ico">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <TargetPath>ico.ico</TargetPath>
    </ContentWithTargetPath>
  </ItemGroup>

This basically says "when building, take the ico.ico file that lives in this directory and move it to the output dir under the name ico.ico. You can have a look at the file here.

I think I remember back then @Elias suggested a different way of doing it with the props file, but I forgot and kept this :-)

Hope this helps!

3 Likes

Ah, cool, I didn’t know there is even a mechanism for this already. It would be nice if I could for example in the export dialogue just add some files or a whole folder and it adds exactly something like this.

But I can also do it manually, but usually have a whole folder of icons, defaults, fonts, etc.

I will have a search and see if I can do it with a whole folder.

Quick ChatGPT reply seems to imply that you can also do it for a whole folder. I usually have a folder called “Settings” with a settings.xml and also all static assets for the UI and such in there. Here is what it suggested:

<ItemGroup>
  <ContentWithTargetPath Include="$(MsBuildThisFileDirectory)Settings\**\*">
    <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    <TargetPath>%(RecursiveDir)%(Filename)%(Extension)</TargetPath>
  </ContentWithTargetPath>
</ItemGroup>

I will give it a shot with the next export and report back.

1 Like

+1 :-)

Okay, I give up. I have tried with lots of different iterations, but none of them seem to work. It never copies anything.

I have tried with adding this: Copy Task - MSBuild | Microsoft Learn

<Target Name="CopyFiles">
        <ItemGroup>
            <MySourceFiles Include="c:\MySourceTree\**\*.*"/>
        </ItemGroup>

        <Copy
            SourceFiles="@(MySourceFiles)"
            DestinationFolder="c:\MyDestinationTree\%(RecursiveDir)"
        />
    </Target>

It never seems to do any copying, but also never get an error. Weird.

Maybe @tonfilm knows.

can you show us your complete .props file?

This copies some folders and also attempts to delete the src folder that is created durring export. The latter only kinda works though, while contents of the folder do get deleted the folder itself stays. Guess because it is still somehow in use by the exporter. A bit more info in the comments below.
Took me a while to figure it out (with some help from @Elias via chat) .

BTW: Make sure to only edit the props file while vvvv is not running or at least the exporter isn’t open otherwise it will overwrite your changes.

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <VLAssetBehavior>PointToOutput</VLAssetBehavior>
    <VLCleanBuildDirectory>True</VLCleanBuildDirectory>
    <VLExportPath>$(MsBuildThisFileDirectory)..\..\deployment\AudioSubProject\bin</VLExportPath>
    <VLTargetOS>Windows</VLTargetOS>
    <OutputType>WinExe</OutputType>
    <PlatformTarget>AnyCPU</PlatformTarget>
    <TargetFramework>net8.0-windows</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <!-- 

      The following works for single files but couldn't get it to work with folders:

      <ContentWithTargetPath Include="$(MSBuildThisFileDirectory)..\..\Start_Audio.bat">
        <CopyToOutputDirectory>Always</CopyToOutputDirectory>
        <TargetPath>..\..\Start_Audio.bat</TargetPath>
      </ContentWithTargetPath>

      See:
      * https://github.com/dotnet/msbuild/issues/2949#issuecomment-362823310
      * https://github.com/dotnet/msbuild/issues/2949#issuecomment-362824225

      LinkBase is "starting from" the output directory in our case for example:
      deployment\AudioSubProject\bin\src\AudioSubProject\bin\Release
      So we have to "go up" five times in the folder hierarchy to get to the root folder of a specific application.
    -->
    <None Include="$(MSBuildThisFileDirectory)..\..\assets\Audio\**\*.*" CopyToOutputDirectory="Always" LinkBase="..\..\..\..\..\Assets\Audio" />
    <None Include="$(MSBuildThisFileDirectory)..\..\assets\Common\**\*.*" CopyToOutputDirectory="Always" LinkBase="..\..\..\..\..\Assets\Common" />
    <None Include="$(MSBuildThisFileDirectory)..\..\batch-files\Start_Audio.bat" CopyToOutputDirectory="Always" LinkBase="..\..\..\..\..\" />
  </ItemGroup>
  <!-- 
      AfterTargets="Publish" seems to be something vvvv specific at least it is not listed in the MS documentation:
      https://learn.microsoft.com/en-us/visualstudio/msbuild/how-to-extend-the-visual-studio-build-process?view=vs-2022#table-of-predefined-targets
  -->
  <Target Name="RemoveSrc" AfterTargets="Publish">
    <!--  
      See: https://learn.microsoft.com/en-us/visualstudio/msbuild/removedir-task?view=vs-2022

       the following works in a way but causes errors in exporter. AfterTargets="Publish" seems to happen a little too soon.
      <RemoveDir Directories="$(MsBuildThisFileDirectory)..\..\deployment\AudioSubProject\bin\src" />   
    -->
    <!-- kinda works leaves empty folders though -->
    <Exec Command="rmdir /s /q &quot;$(MsBuildThisFileDirectory)..\..\deployment\AudioSubProject\bin\src&quot;" />
  </Target>
</Project>
1 Like

The complete file looks like this:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <VLAssetBehavior>PointToOutput</VLAssetBehavior>
    <VLCleanBuildDirectory>True</VLCleanBuildDirectory>
    <VLExportPath>$(MsBuildThisFileDirectory)</VLExportPath>
    <VLTargetOS>Windows</VLTargetOS>
    <OutputType>WinExe</OutputType>
    <PlatformTarget>AnyCPU</PlatformTarget>
    <TargetFramework>net8.0-windows</TargetFramework>
    <ApplicationIcon>$(MsBuildThisFileDirectory)Settings\sm.ico</ApplicationIcon>
  </PropertyGroup>
  <ItemGroup>
    <None Include="$(MSBuildThisFileDirectory)..\..\Settings\**\*.*" CopyToOutputDirectory="Always" LinkBase="..\..\..\..\..\Settings" />
  </ItemGroup>
</Project>

I adjusted it as per Bjoern’s suggestion. I tried again, but it does not work.

My file structure:

The .vl file in the root is the one I am exporting. Then I am using these settings:

It’s very unclear which path is the correct one. Is there some way to debug the build process?

Actually for our other project we just created a post-export .bat file. Maybe it’s easier to do that.

You need to adapt the paths to your folder structure. Guessing from your screenshot it should be:

<None Include="$(MSBuildThisFileDirectory)Settings\**\*.*" CopyToOutputDirectory="Always" LinkBase="..\..\..\..\RealtimeAIMixer\Settings" />

$(MSBuildThisFileDirectory) is the directory where the props file resides.

LinkBase starts in RealtimeAIMixer\src\RealtimeAIMixer\bin\Release so “you have to go up four times” and then into RealtimeAIMixer\Settings.

1 Like

A build event in the IDE results in an MSBuild target in the project file. You can use any MSBuild property that is available in the target in your project file (for example, $(OutDir) or $(Configuration) ) . The MSBuild properties that are available to you in these events depend on the files implicitly or explicitly imported in a project file, such .props and .targets files, and properties set in your project file, such as in PropertyGroup elements.

Idk, might that be some help here. Seems you can check available variables in .targets and use like $(ProjectDir)?

1 Like