<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Charlie Foxtrot</title>
    <description>The latest articles on DEV Community by Charlie Foxtrot (@charliefoxtrot).</description>
    <link>https://dev.to/charliefoxtrot</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F3236%2Fbb73102b-7588-49c3-bf03-23be20866ed9.png</url>
      <title>DEV Community: Charlie Foxtrot</title>
      <link>https://dev.to/charliefoxtrot</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/charliefoxtrot"/>
    <language>en</language>
    <item>
      <title>How to build a MAUI app in Azure Devops</title>
      <dc:creator>stfnilsson</dc:creator>
      <pubDate>Tue, 29 Oct 2024 07:50:25 +0000</pubDate>
      <link>https://dev.to/charliefoxtrot/how-to-build-a-maui-app-in-azure-devops-i48</link>
      <guid>https://dev.to/charliefoxtrot/how-to-build-a-maui-app-in-azure-devops-i48</guid>
      <description>&lt;h1&gt;
  
  
  - and how to publish it to Test Flight and Google Play Console
&lt;/h1&gt;

&lt;p&gt;You have created a .NET MAUI app but you have been building it on your laptop and now want to know how to send it to Testers or to the Store. &lt;/p&gt;

&lt;h2&gt;
  
  
  Environment
&lt;/h2&gt;

&lt;p&gt;This blog post is covering building via Azure Devops but there are many  other options, like Github.&lt;/p&gt;

&lt;p&gt;In Azure Devops you can setup your own build agent by following this guide: &lt;a href="https://learn.microsoft.com/sv-se/azure/devops/pipelines/agents/osx-agent?view=azure-devops" rel="noopener noreferrer"&gt;https://learn.microsoft.com/sv-se/azure/devops/pipelines/agents/osx-agent?view=azure-devops&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also use a hosted agent. Here are some different alternatives: &lt;a href="https://learn.microsoft.com/sv-se/azure/devops/pipelines/agents/hosted?view=azure-devops&amp;amp;tabs=yaml#software" rel="noopener noreferrer"&gt;https://learn.microsoft.com/sv-se/azure/devops/pipelines/agents/hosted?view=azure-devops&amp;amp;tabs=yaml#software&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For building a Maui app for iOS you need a Mac. In this build pipeline 'macos-14' is used.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pool:
  vmImage: 'macos-14'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Global settings
&lt;/h2&gt;

&lt;p&gt;To share settings between build pipelines or to just abstract away the settings you can use Library in Azure Devops.&lt;/p&gt;

&lt;p&gt;In this example the variable group "Svetto" is used.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkl32cueezevykfw4w15z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkl32cueezevykfw4w15z.png" alt="Image description" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You define the variable group in your build pipeline like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;variables:
  - group: Svetto
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is all the setting which is used to build both for iOS and Android, the name of the files is also specified as variables.&lt;/p&gt;

&lt;p&gt;For signing the Android app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AndroidKeyStoreAlias&lt;/li&gt;
&lt;li&gt;AndroidKeyStoreFile&lt;/li&gt;
&lt;li&gt;AndroidKeyStorePassword&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For signing the iOS app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AppleCertificate&lt;/li&gt;
&lt;li&gt;AppleSigningIdentity&lt;/li&gt;
&lt;li&gt;iOSCertPassword&lt;/li&gt;
&lt;li&gt;ProvisioningProfile&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The version (major.minor)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ApplicationDisplayVersion&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk24mzrawvmuoyn0btksz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk24mzrawvmuoyn0btksz.png" alt="Image description" width="800" height="331"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The files needed to sign the app are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;.p12 which is the Apple Certificate&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;.mobileprovision which is the Apple Provision Profile&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;.keystore which is used to sign the Android app&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5b2faublu6p7vzq5ikxe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5b2faublu6p7vzq5ikxe.png" alt="Image description" width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Version number
&lt;/h2&gt;

&lt;p&gt;A version number contains of three digits {major.minor.build}.&lt;/p&gt;

&lt;p&gt;The major and the minor are specified in the project file:&lt;br&gt;
&lt;code&gt;&amp;lt;ApplicationDisplayVersion&amp;gt;2.0&amp;lt;/ApplicationDisplayVersion&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To make the build number unique build/runner in devops is often used but it's also possible to use the date like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;ApplicationVersion&amp;gt;$([System.DateTime]::Now.ToString('yyyyMMddHH'))&amp;lt;/ApplicationVersion&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Preparing
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Select Xcode version
&lt;/h3&gt;

&lt;p&gt;If you want to use a specific version of Xcode you can use this inline script, here it's specified that Xcode 16 should be used.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- task: CmdLine@2
  displayName: 'Selects a specific version of Xcode'
  inputs:
    script: 'sudo xcode-select -switch /Applications/Xcode_16.app/Contents/Developer'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install latest .net MAUI
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- task: CmdLine@2
  displayName: 'Install Latest .NET MAUI Workload '
  inputs:
    script: 'dotnet workload install maui'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can adjust the --source to target specific versions of .NET MAUI workloads, and you can learn more about changing sources in the .NET MAUI Wiki (&lt;a href="https://github.com/dotnet/maui/wiki/#install-net-6-with-net-maui" rel="noopener noreferrer"&gt;https://github.com/dotnet/maui/wiki/#install-net-6-with-net-maui&lt;/a&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Install apple certificate and provision profile
&lt;/h3&gt;

&lt;p&gt;For iOS, you need a signing certificate and a provisioning profile. This guide walks you through how to obtain these files:(&lt;a href="https://learn.microsoft.com/sv-se/azure/devops/pipelines/apps/mobile/app-signing?view=azure-devops&amp;amp;tabs=yaml#apple" rel="noopener noreferrer"&gt;https://learn.microsoft.com/sv-se/azure/devops/pipelines/apps/mobile/app-signing?view=azure-devops&amp;amp;tabs=yaml#apple&lt;/a&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- task: InstallAppleCertificate@2
  inputs:
    certSecureFile: '$(AppleCertificate)'
    certPwd: '$(iOSCertPassword)'
    keychain: 'temp'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- task: InstallAppleProvisioningProfile@1
  displayName: 'Install app store provisioning profile'
  inputs:
    provisioningProfileLocation: 'secureFiles'
    provProfileSecureFile: '$(ProvisioningProfile)'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add Android keystore key
&lt;/h3&gt;

&lt;p&gt;For Android, you need keystore file and value of keystore password and keystore alias. This guide walks you through how to obtain these files: (&lt;a href="https://learn.microsoft.com/sv-se/azure/devops/pipelines/apps/mobile/app-signing?view=azure-devops&amp;amp;tabs=yaml#sign-your-android-app" rel="noopener noreferrer"&gt;https://learn.microsoft.com/sv-se/azure/devops/pipelines/apps/mobile/app-signing?view=azure-devops&amp;amp;tabs=yaml#sign-your-android-app&lt;/a&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- task: DownloadSecureFile@1
  name: keystore
  inputs:
    secureFile: '$(AndroidKeyStoreFile)'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Building
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Build iOS
&lt;/h3&gt;

&lt;p&gt;In .NET 8, the dotnet publish command defaults to the Release configuration. Therefore, the build configuration can be omitted from the command line. In addition, the dotnet publish command also defaults to the ios-arm64 RuntimeIdentifier. The RuntimeIdentifier can also be omitted from the command line.&lt;/p&gt;

&lt;p&gt;.NET MAUI apps produce executables for each Target Framework—these are native app packages with all dependencies/resources bundled in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- task: DotNetCoreCLI@2
  displayName: 'dotnet publish iOS'
  inputs:
    command: 'publish'
    publishWebProjects: false
    projects: '**/Svetto.sln'
    arguments: '-f net8.0-ios -c Release -p:ApplicationDisplayVersion=$(ApplicationDisplayVersion) -p:ArchiveOnBuild=true -p:EnableAssemblyILStripping=false -p:RuntimeIdentifier=ios-arm64'
    zipAfterPublish: false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Copy ipa to stage folder
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- task: CopyFiles@2
  displayName: 'Copy iOS artifact'
  inputs:
    Contents: '**/*.ipa'
    TargetFolder: '$(Build.ArtifactStagingDirectory)'
    CleanTargetFolder: true
    OverWrite: true
    flattenFolders: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Build Android
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- task: DotNetCoreCLI@2
  displayName: 'dotnet publish android'
  inputs:
    command: 'publish'
    publishWebProjects: false
    projects: '**/Svetto.sln'
    arguments: '-f net8.0-android -c Release -p:ApplicationDisplayVersion=$(ApplicationDisplayVersion) -p:AndroidKeyStore=true -p:AndroidSigningKeyStore=$(keystore.secureFilePath) -p:AndroidSigningKeyPass=$(AndroidKeyStorePassword) -p:AndroidSigningStorePass=$(AndroidKeyStorePassword) -p:AndroidSigningKeyAlias=$(AndroidKeyStoreAlias)'
    zipAfterPublish: false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Copy aab to stage folder
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- task: CopyFiles@2
  displayName: 'Copy android artifact'
  inputs:
    Contents: |
      **/*Signed.aab
    TargetFolder: '$(Build.ArtifactStagingDirectory)'
    OverWrite: true
    flattenFolders: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Publishing
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Publish staged files, connect them to the build task
&lt;/h3&gt;

&lt;p&gt;If you want to attach the ipa/abb to the build task you can use this task to publish the artifact to the task, as a zipfile called 'drop'.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- task: PublishBuildArtifacts@1
  displayName: 'Publish Artifact: drop'
  inputs:
    PathtoPublish: '$(build.artifactstagingdirectory)'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Publish to Apple TestFlight
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Prerequisites
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;In order to automate the release of app updates to the App Store, you need to have manually released at least one version of the app beforehand.&lt;/li&gt;
&lt;li&gt;The tasks install and use fastlane tools. fastlane requires Ruby 2.0.0 or above and recommends having the latest Xcode command line tools installed on the MacOS computer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Read more about the extension here:&lt;br&gt;
&lt;a href="https://github.com/microsoft/app-store-vsts-extension/tree/master" rel="noopener noreferrer"&gt;https://github.com/microsoft/app-store-vsts-extension/tree/master&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- task: AppStoreRelease@1
  displayName: 'Publish to Test Flight'
  inputs:
    serviceEndpoint: 'AppleTestFlight'
    releaseTrack: 'TestFlight'
    appIdentifier: 'xxxxxxxx'
    appType: 'iOS'
    appSpecificId: 'xxxxxxxx'
    shouldSkipWaitingForProcessing: true
    isTwoFactorAuth: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Publish to Google Play Console
&lt;/h3&gt;

&lt;p&gt;To publish a .NET MAUI Android app for Google Play distribution requires that your app package format is AAB, which is the default package format for release builds. To verify that your app's package format is set correctly:&lt;/p&gt;

&lt;p&gt;In Visual Studio's Solution Explorer right-click on your .NET MAUI app project and select Properties. Then, navigate to the Android &amp;gt; Options tab and ensure that the value of the Release field is set to bundle:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw32n8l3xrral6rhjoo4v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw32n8l3xrral6rhjoo4v.png" alt="Image description" width="800" height="324"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first time an AAB is submitted to Google Play, it must be manually uploaded through the Google Play Console. This enables Google Play to match the signature of the key on all future bundles to the original key used for the first version of the app. In order to upload the app through the Google Play Console, it must first be built and signed in Visual Studio.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- task: GooglePlayRelease@4
  inputs:
    serviceConnection: 'GooglePlayConsole'
    applicationId: 'xxxxxxxx'
    action: 'SingleBundle'
    bundleFile: '$(build.artifactstagingdirectory)/*.aab'
    track: 'internal'
    isDraftRelease: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Next year AppCenter will be deprecated so MAUI developers need to find other ways to share their app to testers and users. Publishing them to the test stores (TestFlight/Google Play Console) is the recommended way.&lt;/p&gt;

&lt;p&gt;I hope this guide will help you. Even if it doesn't cover all details about certificates, configuration and setup in the stores.&lt;/p&gt;

&lt;p&gt;Good luck!&lt;/p&gt;

</description>
      <category>maui</category>
      <category>azuredevop</category>
      <category>testflight</category>
      <category>googleplay</category>
    </item>
    <item>
      <title>Connecting Azure SQL-Database and App Service using system-assigned identity</title>
      <dc:creator>Emil Pettersson</dc:creator>
      <pubDate>Fri, 31 May 2024 08:44:01 +0000</pubDate>
      <link>https://dev.to/charliefoxtrot/connecting-azure-sql-database-and-app-service-using-system-assigned-identity-1jf</link>
      <guid>https://dev.to/charliefoxtrot/connecting-azure-sql-database-and-app-service-using-system-assigned-identity-1jf</guid>
      <description>&lt;p&gt;I had built an application using an Azure SQL-Database for storage and I wanted to upload it to Azure as an App Service to run it in the cloud. I had assumed it was going to be like connecting an App Service to BlobStorage or TableStorage in Azure, but it turns out it is a bit different for a SQL-Database. Primarily how the system-assigned identity is used to authenticate. After figuring out how to get it to work, I decided to write the short guide I myself would have wanted to find when I started googling on why I couldn’t connect to my database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the database
&lt;/h2&gt;

&lt;p&gt;To create a database we will first have to create a SQL-Server resource to host the database. When creating we will use the &lt;strong&gt;Authentication Method&lt;/strong&gt; “Use Microsoft Entra-only authentication”, and set ourselves as Admin for the server.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg2ie9zdvvr8svvhut629.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg2ie9zdvvr8svvhut629.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To allow other azure resources to access our new server we have to go to Security &amp;gt; Networking. There we select to give public network access to “Selected networks”.&lt;/p&gt;

&lt;p&gt;We then add our own IP Address to the Firewall Rules since we will want to test connecting to our SQL-Server locally. It is also needed to log in to our SQL-database in Azure Portal later.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F88rwzwd62f9xcre3a9rp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F88rwzwd62f9xcre3a9rp.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the special case that your App Service and SQL-Server will be in different Azure Subscriptions. you will have to check “Allow Azure services and resources to access this server” under Exceptions. Note that this is a big risk since it opens up your SQL-Server to EVERY Azure service and resource, even those belonging to other subscriptions and other Azure users, customers and organizations. To be secure there are solutions using virtual networks and configuring Private Access. But this is not included in the scope of this tutorial, so we will accept the shortcut of allowing this exception. This can also be a tool for troubleshooting if you suspect you have problems with connecting to the SQL-Server.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx0yf53g3doxgd21ffdvf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx0yf53g3doxgd21ffdvf.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next step is to create the SQL Database, so go to Overview and select Create Database. In the tutorial we assume the database is only for learning purposes so we want to keep costs as low as possible. So for Compute + Storage we select “Configure database” and slide the vCores and Data max Size to their lowest settings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1xonndbz7chsc48wrphp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1xonndbz7chsc48wrphp.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then for &lt;strong&gt;Backup storage redundancy&lt;/strong&gt; we select “Locally-redundant backup storage”, the weakest kind.&lt;/p&gt;

&lt;p&gt;When the resource has been created, go to &lt;strong&gt;Query editor (preview)&lt;/strong&gt; and log in with Microsoft Entra authentication. If it does not work make sure you have whitelisted your own IP.&lt;/p&gt;

&lt;p&gt;We then create a new table by running:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

CREATE TABLE animals (id INT PRIMARY KEY, name VARCHAR(100));


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This creates a very simple table called “animals” where we can list different kinds of animals. Add a few animals:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

INSERT INTO [dbo].[animals] (id, name) VALUES (1, 'Lion');
INSERT INTO [dbo].[animals] (id, name) VALUES (2, 'Fox');
INSERT INTO [dbo].[animals] (id, name) VALUES (3, 'Cat');


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can then see your animals by running:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

SELECT * FROM [dbo].[animals]


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And you can count them by running:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

SELECT COUNT(*) FROM [dbo].[animals]


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Creating the code
&lt;/h2&gt;

&lt;p&gt;We will now build a small C# program that connects to the SQL Database and runs the SQL-command for counting the animals. Create a new ASP.NET Core Empty project in Visual Studio.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqm6lfu0xyof5gvh1sh59.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqm6lfu0xyof5gvh1sh59.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This gives you a project with only a Program.cs with minimal amount of code. We will be able to write our whole program here. First thing to do is to install the NuGet Microsoft.Data.SqlClient;&lt;/p&gt;

&lt;p&gt;We then create a minimal api to connect to our SQL-database and execute the command to count our animals, and delete the auto-generated code we won’t need. This leaves us with a Program.cs like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnar53jc883w58g4th8sw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnar53jc883w58g4th8sw.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then we go to Overview in your database-resource and select “See connection strings” under &lt;strong&gt;Connect to application&lt;/strong&gt;. Take the connection string for “ADO.NET (Microsoft Entra passwordless authentication)” and put it into your appsettings of the newly created project.&lt;/p&gt;

&lt;p&gt;For me, where both SQL-Server and SQL-database are named “charlie-foxtrot-sql” it will look like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0427soz71fqiweqz2bl0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0427soz71fqiweqz2bl0.png" alt="Image description"&gt;&lt;/a&gt;&lt;br&gt;
(Note1: Treat your Connection Strings as secrets, the resources my connection string are referencing will have been deleted when this tutorial is published)&lt;br&gt;
(Note2: In the connection string you can see that we set authentication to be “Active Directory Default”. Entra ID used to be called Active Directory. This setting means that we can authenticate with our account assigned in visual studio when we run locally, and with managed identities given certain roles when we run it as an App Service)&lt;/p&gt;

&lt;p&gt;Then run your program and make a call to the /test-db endpoint. You can do this using swagger, your favorite testing tool (e.g Postman or Insomnia) or your web browser.&lt;/p&gt;

&lt;p&gt;If you get an error “Globalization Invariant Mode is not supported” you’ll have to unload your project and remove&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuam26w6oc1ndz3hcphhv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuam26w6oc1ndz3hcphhv.png" alt="Image description"&gt;&lt;/a&gt;&lt;br&gt;
from your project file (or set it to false). Then load the project again.&lt;/p&gt;

&lt;p&gt;If you get trouble with authentication, make sure you are using the same account for Azure Service Authentication in Visual Studio as you used to create the SQL-Server and database in Azure, and that the account has the proper IAM-role to access them. You can check this under Access Control (IAM) for your SQL-Server.&lt;/p&gt;

&lt;p&gt;You should then get a response that corresponds to the value you get by running the count-command directly in the Query Editor in Azure Portal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbi8mkl7ctw5jjrmoor2d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbi8mkl7ctw5jjrmoor2d.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we will create an App Service to run this code in Azure.&lt;/p&gt;
&lt;h2&gt;
  
  
  Creating the App Service
&lt;/h2&gt;

&lt;p&gt;Create a repository for the code in Github (or Azure DevOps or Bitbucket), and push your code, except for your appsettings, to it. We will deploy the code to our App Service from there.&lt;/p&gt;

&lt;p&gt;In Azure Portal, go to App Services and press Create &amp;gt; Web App and create your App Service. Then we have to connect our App Service to Github so that it knows which code to deploy. We get two options for Github Action workflow to authenticate to our App Service when deploying; the default “User-assigned identity” and “Basic authentication”. If you have sufficient permissions to use “User-assigned identity” that is recommended. You need to be able to assign role-based access to the identity. If you lack these permissions you can instead use “Basic authentication”.&lt;/p&gt;

&lt;p&gt;If you use “Basic authentication” you first have to go to Settings &amp;gt; Configuration in your App Service and put SCM Basic Auth Publishing Credentials to &lt;strong&gt;On&lt;/strong&gt; and press Save. If you use “User-assigned identity” you don’t have to do this.&lt;/p&gt;

&lt;p&gt;Then go to Deployment &amp;gt; Deployment Center and choose your Source for the code. Choose your way of authentication and press Save.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fimmv88jve7xoeq4tmxcz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fimmv88jve7xoeq4tmxcz.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Make sure that it builds. Then go to Settings &amp;gt; Environment variables and add your connection string.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0je4r0x9ww9qahkgjoue.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0je4r0x9ww9qahkgjoue.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Make sure you click Apply once after adding this applications setting, then once again to confirm you are done editing your application settings in general.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note the naming of the Application Setting and compare it to how it is in your local appsettings.json. This is how Azure deals with hierarchy in JSON;&lt;/em&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

"Level1": {
    "Level2": {
        "Level3:": "Value",
    }
},


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;em&gt;would in the Azure App Service application settings become a setting with the name&lt;br&gt;
"Level1:Level2:Level3" and the value “Value”.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Then go to Settings &amp;gt; Identity and set Status to &lt;strong&gt;On&lt;/strong&gt; for System Assigned identity. Remember to save.&lt;/p&gt;

&lt;p&gt;For most resources in Azure you would then give a role to this managed identity that let the App Service access it. This is called Role-Based Access Control (RBAC). But for Azure SQL Database we have to do it in a different way; We want to add our App Service as a user to the database and then give the user read and write permissions. So go to the Query Editor in your database and run&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

CREATE USER [&amp;lt;appservice&amp;gt;] FROM EXTERNAL PROVIDER;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;where  is the name of your App Service. Then run both&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

ALTER ROLE db_datareader ADD MEMBER [&amp;lt;appservice&amp;gt;];
ALTER ROLE db_datawriter ADD MEMBER [&amp;lt;appservice&amp;gt;];


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;to give the new role proper permissions.&lt;br&gt;
(Note: In our code we are only reading from the database, but the common case is to want both read and write permissions.)&lt;/p&gt;

&lt;p&gt;Now you can go to your App Service Overview where you will see which “Default Domain” your app has&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwfdtetcs5mp9v5digq02.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwfdtetcs5mp9v5digq02.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;go to the test-endpoint of this domain. My App Service is called charlie-foxtrot-sql so for me it is &lt;a href="https://charlie-foxtrot-sql.azurewebsites.net/test-db" rel="noopener noreferrer"&gt;https://charlie-foxtrot-sql.azurewebsites.net/test-db&lt;/a&gt;. This should now show you the number of animals in your database.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv2l7udl0cf45nx94pvzj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv2l7udl0cf45nx94pvzj.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>azure</category>
      <category>sqlserver</category>
      <category>identity</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Expedition logbook: Journey into the world of stable diffusion</title>
      <dc:creator>Malcolm Eriksson</dc:creator>
      <pubDate>Fri, 03 Nov 2023 16:56:18 +0000</pubDate>
      <link>https://dev.to/charliefoxtrot/expedition-logbook-journey-into-the-world-of-stable-diffusion-104n</link>
      <guid>https://dev.to/charliefoxtrot/expedition-logbook-journey-into-the-world-of-stable-diffusion-104n</guid>
      <description>&lt;p&gt;This will be a summarization on a high level of my experience and some related learnings from a hobby project trying to generate images with stable diffusion in the cloud.&lt;/p&gt;

&lt;h2&gt;
  
  
  Intro: Preface &amp;amp; vision
&lt;/h2&gt;

&lt;p&gt;I had previously played around a bit with generating images using Dall-E 2 and similar solutions using some free credits. My problem was this; I kept forgetting to use my free credits and thus not getting them renewed. And when I finally wanted to generate an image I ran out of credits after a few tries.&lt;/p&gt;

&lt;p&gt;The initial idea was simply to set up a scheduled generation of images that would make sure to consume all of my free points in the various offerings available and to then automatically push them to some kind of screen or digital photo frame.&lt;br&gt;
The primary images I wanted to generate would be&lt;/p&gt;

&lt;p&gt;As I eventually got started on the project I realised that the free offerings of the various resources have been cancelled. Thus  I decided to set up my own image generation using open source solutions with the goal of having it live in the cloud to make it simpler to share and to avoid needing specific local resources.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 1: Generating images
&lt;/h2&gt;

&lt;p&gt;As stated in the preface; as a lazy (efficient) developer I started my journey of finding a open source implementation of one of the Image generation models, and ended up with &lt;a href="https://github.com/Stability-AI/stablediffusion"&gt;Stabilityi-AI's Stable Diffusion setup&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After fighting my Windows installation getting all the python packages, conda installations etc. running I was finally able to generate an image.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wrb0a3Qy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ljkp2l9yt0ma748s3dee.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wrb0a3Qy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ljkp2l9yt0ma748s3dee.png" alt="First image" width="256" height="256"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Well, that did not go great. So I kept trying making more images; altering the prompt and the configurations. All of my attempts turned out similar; but why?&lt;/p&gt;

&lt;p&gt;To keep runtime low I tried generating images of 256x256 ratio. I tried altering the prompt, the steps (iterations) as well as CFG scale (multiplier of how much the prompt input should dictate the outcome).&lt;br&gt;
But it just turned into different noise; still no images that looked anything like the prompt.&lt;/p&gt;

&lt;p&gt;To ensure that my setup wasn't faulty I took a step back and tried some reference prompts and seeds and managed to generate images that looked like the prompt rather than random colourful noise.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xgtAPMpu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ig10ezguru4q0eaoywcc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xgtAPMpu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ig10ezguru4q0eaoywcc.png" alt="Image from reference prompt" width="768" height="768"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1.1 What went wrong?
&lt;/h3&gt;

&lt;p&gt;My primary problem was simply that I did not understand how diffusion models work well and what might be a good expected prompt (including config) to generate images.&lt;/p&gt;

&lt;p&gt;A simplified explanation is that (image) diffusion models are trained on a specific set of images in order to learn how to remove noise from an image in order to get closer to the original image it trained on.&lt;br&gt;
This means that a model can not generate outputs (in a controlled fashion) it's not trained on. This includes the ratio as it's part of the noise removal. Other ratios might still end up looking good; but it might also cause unexpected corruptions&lt;br&gt;
Thus in hindsight I realise that I had to low of a CFG-scale, to few iterations and an unexpected ratio as this model was trained on 528x528 images. &lt;/p&gt;

&lt;p&gt;Moving on from this I got back to trying to generate my original prompts; but now with new ratios, iterations and CFG scale. So what was my prompt? Variations of &lt;code&gt;Fox working with a laptop in an office drinking a cup of coffee&lt;/code&gt;.With various alterations of phrasing and omitting details. Why this prompt? Well it's simply a reference to my the company I work at Charlie Foxtrot; a software development consultancy with foxes in our branding.&lt;/p&gt;

&lt;p&gt;I ended up with images to containing all the contents of the prompt; even if very disjoint and not a combined picture.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Dq7ICvAs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wrjhppdb8med3lqnj5oq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Dq7ICvAs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wrjhppdb8med3lqnj5oq.png" alt="Disjoint result" width="512" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I thought this might simply be to hard a prompt for this model. So I changed the prompt again; keeping the fox but altering the rest of the prompt to be a more natural setting for the fox.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CzmpOGBy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/10vsh3mp301emoxfebgx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CzmpOGBy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/10vsh3mp301emoxfebgx.png" alt="Natural setting prompt" width="768" height="768"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Much better. After this I got back to trying various versions of the original prompt with smaller alterations for each prompt.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.2 The end
&lt;/h3&gt;

&lt;p&gt;Then my laptop blue screened. I left it a short while to cool down and then started it up again; but now for some reason my python and conda setup refused to work.&lt;br&gt;
During my setup I obviously fucked up some step which left it in a state that a fresh start of the system were lacking some kind of path var or similar.&lt;/p&gt;

&lt;p&gt;Part of the problem is of course that I did not pay enough attention when installing my dependencies and setting up my paths etc. &lt;/p&gt;

&lt;p&gt;To avoid this happening again, to be able to share the setup with friends and colleagues as well as my future plan of getting it set up in a cloud solution I decided to get setup in a Docker image instead. In addition to this I decided to look for a more feature complete solution; preferably with an already prepared docker setup.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.3: Giving it another shot
&lt;/h3&gt;

&lt;p&gt;As mentioned I wanted a more feature complete solution with an existing docker setup; and I found it &lt;a href="https://invoke-ai.github.io/InvokeAI/"&gt;InvokeAI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;While this probably relates more to my setup and experience; setting this up was a lot smoother compared to my initial setup, I simply had to build the image according to instrucitons and run it. I suddenly was making images with outcomes that looked like my prompt with a provided GUI. When my laptop inevitable blue screened again from being pushed past its limit I recovered in seconds. &lt;/p&gt;

&lt;p&gt;But the images took longer to generate than expected and the gpu was hardly working even when I tried to pass through GPU resources. Did this have something to do with InvokeAI, the model or my setup? After verifying the requirements I simplified the setup by using invokeai's simple installer version; removing potential issues with Docker (running via WSL).&lt;/p&gt;

&lt;p&gt;I instantly got better performance and thus could figure out that something was not working as intended. With this knowledge I could debug and resolve the issue with the gpu passthrough and get back to my docker setup.&lt;/p&gt;

&lt;p&gt;After this I simply dialed in the prompt configuration to find a good balance between output and runtime by testing various combinations of prompts, cfg and steps.&lt;br&gt;
When this was done I tried all of the recommended models from the invokeai installer and tried a few iterations of each to find the model(s) that I thought generated the best images for my given prompt. For some models I had to play around a bit with new baselines for cfg/steps to get images I thought looked good.&lt;/p&gt;

&lt;p&gt;I could now generate images in bulk where some of them actually looked as intended.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5ivhZqom--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rurydxyqqcz4n7kq4fyo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5ivhZqom--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rurydxyqqcz4n7kq4fyo.png" alt="Successful outcome example" width="768" height="768"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1.4 Learnings
&lt;/h3&gt;

&lt;p&gt;Some simple learnings from this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Always work with a recoverable / reproducable environment.&lt;/li&gt;
&lt;li&gt;Understand the tools (models) better when using them. Even when playing around you need to play around in a mindful manner.&lt;/li&gt;
&lt;li&gt;When experimenting always sanity check with a known input/output as soon as possible. It might seem more fun to have the first outcome to be what you want; but you probably want to verify your setup first.&lt;/li&gt;
&lt;li&gt;Image generation is just structured randomization. You will need to generate a lot of images and sort through them either manually or with image analysis to provide outcomes you're happy with. Finetuning input for your model can take a lot of iterations.&lt;/li&gt;
&lt;li&gt;Schedule the time for your input/model testing better than I did; generating images is a resource hog and it will make using the device for anything else at the same time a pain. Alternatively get it set up on a secondary machine asap when you know you have working setup.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Chapter 2: To the cloud
&lt;/h2&gt;

&lt;p&gt;As I now had a dockerized soloutin that I liked&lt;/p&gt;

&lt;p&gt;After finding models and configurations that performed to my liking on my laptop it was now time to get into the cloud. This is for multiple reasons. Amongst others it would allow for scaling above physical local devices, would not bog down said local devices during runtime and in general be better for sharing and demo purposes.&lt;/p&gt;

&lt;p&gt;So what's on the shopping list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Container Hosting (potential autoscaling)&lt;/li&gt;
&lt;li&gt;Gpu resources for the container&lt;/li&gt;
&lt;li&gt;A storage volume to make outputs, models and invokeai setup stable between instances.&lt;/li&gt;
&lt;li&gt;Keeping costs down&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To simplify the decisions I limited myself to the Azure platform as my company already had an existing setup for it. &lt;/p&gt;

&lt;h3&gt;
  
  
  2.1 Container hosting
&lt;/h3&gt;

&lt;p&gt;So lets start with getting the container into the cloud; that's the minimum working solution. Getting something autoscaling would simplify maintenance and in general be resource efficient.&lt;/p&gt;

&lt;p&gt;Starting with simple &lt;code&gt;azure container apps&lt;/code&gt; would allow for azure handled autoscaling and some free resources monthly; which would be nice for a project of this scale. Sadly the maximum memory of azure container apps of 4Gi is way below the required specs for invokeai of 12GB.&lt;br&gt;
I never tried how it would perform on these resources and there is the possibility to request a manual increase of memory limit.&lt;br&gt;
So this is something that could be explored in the future.&lt;/p&gt;

&lt;p&gt;Secondly we could explore azures kubernetes setup &lt;code&gt;aks&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Sadly on a free tier there is no autoscaling which made me opt out from this option. However neither the standard tier cluster nor the nodes are that expensive and there are a lot of GPU supported options which might be worth trying out in another iteration in the future.&lt;/p&gt;

&lt;p&gt;However I opted for a regular container instance. In theory there should also be cost effective K80 GPU's that could be used; however it's a preview feature which is not intended for production use and needs to be manually approved by Azure prior to usage.&lt;br&gt;
Our request got rejected; hence we are running without a GPU in the cloud.&lt;/p&gt;

&lt;p&gt;The pricing for our needs is low; 1 cpu and 12 GB memory which totals to ~$2 per day of uptime; and with mindful shutdown of the service we would of course only pay for actually active resources. And even without a gpu we can produce images in a somewhat acceptable time.&lt;/p&gt;

&lt;p&gt;In addition to all this we will of course need a registry. This costs $0.167 / day on the basic tier.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.2 Cloud storage volume
&lt;/h3&gt;

&lt;p&gt;Setting up a volume mount for the container seemed pretty simple. All I needed was to set up a &lt;code&gt;file share&lt;/code&gt; and mount it to my container instance. &lt;/p&gt;

&lt;p&gt;Depending on your setup you should only need ~12GB for your models as well as extra storage for caching between steps of the image generation + generated output storage. I could not see storage going above ~25GB with some mindful cleaning of unused data. At this point pretty much any storage option would be cheap; I went for a transaction optimized setup at $0.06 per used GiB and month for the storage + $0.015 per 10000 read/writes. At this price point we should not need to worry at all. &lt;/p&gt;

&lt;p&gt;The first few burst tries of starting one docker container; generating one image and then killing everything this worked fine.&lt;/p&gt;

&lt;p&gt;I then tried sharing the volume between two different container instances and generated multiple images on both instances. &lt;br&gt;
Sharing a volume worked fine and I thought that was it; I generated a few images each for a few hours straight.&lt;/p&gt;

&lt;p&gt;Happy with the performance and results I closed them down for the day.&lt;/p&gt;

&lt;p&gt;Next day I sanity checked my cost analysis and realized that for some reason I had an unexpectedly huge storage cost. Turns out that this also induces a network fee for the file transfers; while not immensly large this costed about 90% of the storage cost and even 90% of the entire project at this scale of use. &lt;/p&gt;

&lt;p&gt;Thus I decided to cut it from the project to keep costs down. &lt;br&gt;
The only implication from this is that I need to reinitiate the invokeai setup for every container on startup; re-install any models I want to use and ensure to download any outputs I want to keep before shutting it down. For this type of hobby project that's perfectly fine.&lt;/p&gt;

&lt;p&gt;When the week was up it was apparent what had happened; azure gave me the finger.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Kngk7WAh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tcdmmho7vufbfo72n9x9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Kngk7WAh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tcdmmho7vufbfo72n9x9.png" alt="Azure subliminal messaging" width="162" height="187"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2.3 Learnings
&lt;/h3&gt;

&lt;p&gt;So what did I learn this time&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start any request for potential resource needs way ahead of time; there might be a lot of forth and back and you might eventually get rejected.&lt;/li&gt;
&lt;li&gt;Read pricing details more closely so you understand potential extra costs in your calculations. &lt;/li&gt;
&lt;li&gt;When trying out things do it in iterations and inspect the outcomes after use vigilantly. Had I paid more attention the first few days the spike would have never occured. This time the cost was just high relative to an extremely low baseline; but in any project costs can run amok if you don't pay attention.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Outro: The outcome and next steps
&lt;/h2&gt;

&lt;p&gt;After all of this I opted to let the iteration 0 frame to be a simple solution, we bought a photo frame with a proprietary application for sharing images.&lt;/p&gt;

&lt;p&gt;There are a lot of places to take this project in a second iteration; building a custom photo frame with functionality for automatically pushing new images generated to it, training / extending a model to use the companys mascot and logos rather than generic foxes, a different cloud hosted solution with the same or different provider, using any of the many other features invokeai supports like multistep workflows, or simply replacing invokeai with a different solution. Or maybe this is the final iteration of the project?&lt;/p&gt;

</description>
      <category>writing</category>
      <category>learning</category>
      <category>stablediffusion</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Rpi 4 meets Flutter and Rust</title>
      <dc:creator>AdaShoelace</dc:creator>
      <pubDate>Fri, 06 Nov 2020 16:05:05 +0000</pubDate>
      <link>https://dev.to/charliefoxtrot/rpi-4-meets-flutter-and-rust-23ma</link>
      <guid>https://dev.to/charliefoxtrot/rpi-4-meets-flutter-and-rust-23ma</guid>
      <description>&lt;p&gt;At Charlie foxtrot we aim to stay relevant and keep up with new and exciting tech. So how do we do that? We experiment! This time we wanted to capitalize on our in-house competence in Flutter and Rust. Our Flutter expert, Jonathan, had read about Darts foreign function interface (ffi) capabilities and wanted to try it in conjunction with Rust. He asked me if I thought if we could build something that would run on a Raspberry pi (rpi). Without having a clue, I said “YES!” and got to work. The resulting code can be found &lt;a href="https://github.com/Charlie-Foxtrot-AB/rutter-pi" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After some debating, we landed in an idea where we would have a Flutter interface that let the user take a photo via the rpi camera module and then display the image in the app. This is a simple app but considering that Flutter don’t have official support for the rpi, this could be quite the challenge. We also decided to build a small (read: very small) library in Rust to communicate with the camera. &lt;/p&gt;

&lt;p&gt;This project has quite a few requirements: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.rust-lang.org/" rel="noopener noreferrer"&gt;Rust&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://flutter.dev/?gclid=CjwKCAiA4o79BRBvEiwAjteoYAKTfaki-mqcniau_hBmw3-lyF_yJ_KCCg7aeBQONhfKgXj-pRWHaBoCOSgQAvD_BwE&amp;amp;gclsrc=aw.ds" rel="noopener noreferrer"&gt;Flutter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ardera/flutter-pi" rel="noopener noreferrer"&gt;flutter-pi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thepihut.com/collections/raspberry-pi/products/raspberry-pi-4-model-b" rel="noopener noreferrer"&gt;rpi 4 4gb ram&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;an &lt;a href="https://thepihut.com/products/raspberry-pi-camera-module" rel="noopener noreferrer"&gt;rpi camera module&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;a touch screen, we went with the &lt;a href="https://shop.pimoroni.com/products/hyperpixel-4?variant=12569485443155" rel="noopener noreferrer"&gt;Hyperpixel 4.0&lt;/a&gt;. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;First thing to do is to set up the Raspberry Pi. In the README of the &lt;a href="https://github.com/ardera/flutter-pi" rel="noopener noreferrer"&gt;flutter-pi&lt;/a&gt; repo it's mentioned that &lt;a href="https://github.com/ardera/flutter-pi" rel="noopener noreferrer"&gt;flutter-pi&lt;/a&gt; should run without Xserver. Therefore I went with a headless version of &lt;a href="https://www.raspberrypi.org/downloads/raspberry-pi-os/" rel="noopener noreferrer"&gt;RaspberryOS&lt;/a&gt;. Once you've flashed the os to a ssd card, follow the instructions in the &lt;a href="https://github.com/ardera/flutter-pi" rel="noopener noreferrer"&gt;flutter-pi&lt;/a&gt; README and install drivers for your touch screen of choice. Be sure to clone the &lt;a href="https://github.com/ardera/flutter-pi/tree/engine-binaries" rel="noopener noreferrer"&gt;engine-binaries&lt;/a&gt; branch of &lt;a href="https://github.com/ardera/flutter-pi" rel="noopener noreferrer"&gt;flutter-pi&lt;/a&gt; and place the files in the correct directories aswell.  &lt;/p&gt;

&lt;p&gt;On the software side we first want to set up Flutter on our laptop. If you are using a linux distro you may have the option to install and run Flutter via snap. I found that this leads to several issues. Because of that I cloned the Flutter repo from Github and installed it manually.  Where you install Flutter doesn’t really matter as long as you put &lt;code&gt;/flutter/bin&lt;/code&gt; in your &lt;code&gt;$PATH&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next you want to make sure you are using a Flutter version that’s compatible with &lt;a href="https://github.com/ardera/flutter-pi" rel="noopener noreferrer"&gt;flutter-pi&lt;/a&gt;. At the time of writing this the compatible version is 1.22.2. You can change Flutter-version by checking out the corresponding branch. You can now test your installation by running &lt;code&gt;flutter create &amp;lt;name&amp;gt;&lt;/code&gt; followed by &lt;code&gt;flutter build bundle&lt;/code&gt;. If it builds without errors, everything should be correct. &lt;/p&gt;

&lt;p&gt;We will also need to install Rust so that we can build the small library that lets us talk to the camera. Do this by going over to &lt;a href="https://www.rust-lang.org/tools/install" rel="noopener noreferrer"&gt;the Rust website&lt;/a&gt; and follow the instructions. Once Rust is installed we need to add the armv7 target for the rust compiler in order for us to cross compile the code. Do this with: &lt;code&gt;rustup component add rust-std-armv7-unknown-linux-gnueabihf&lt;/code&gt;. Now create a Rust project using &lt;code&gt;cargo new –-lib ffi-test&lt;/code&gt;. The last part (ffi-test) is the name of the project and doesn’t matter, choose a name to your liking. As I mentioned earlier we need to cross compile the code since it’s going to run on the rpi and not the machine we are writing the code on. Create a directory called &lt;code&gt;.cargo&lt;/code&gt; and place a file in there named &lt;code&gt;config.toml&lt;/code&gt;. In that file place the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[build]&lt;/span&gt; 
&lt;span class="py"&gt;target&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"armv7-unknown-linux-gnueabihf"&lt;/span&gt;  

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;target.armv&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="err"&gt;-unknown-linux-gnueabihf&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
&lt;span class="py"&gt;linker&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"arm-linux-gnueabihf-gcc"&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last part after “linker =” is the gcc linker for arm. Install this if you don’t already have it on your machine. Google the correct name of the package for your distro. The name displayed here is the package name on Manjaro. &lt;br&gt;
We also need to declare, inside the &lt;code&gt;Cargo.toml&lt;/code&gt;, that we want to build a dynamically linked library (&lt;code&gt;.so&lt;/code&gt;) like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[lib]&lt;/span&gt;
&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ffi_test"&lt;/span&gt;
&lt;span class="py"&gt;crate-type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"cdylib"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c"&gt;#dynamic library&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next logical step would be to build a small "Hello world" library in Rust and consume it from Dart/Flutter. Lets create a function that returns a hard coded string when called.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[no_mangle]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;string_from_rust&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;c_char&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;CString&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello from Rust!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Create a CString from "Hello world"&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="nf"&gt;.as_ptr&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Get a pointer to the underlaying memory for s&lt;/span&gt;
    &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;forget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Give up the responsibility of cleaning up/freeing s&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since Dart's ffi mechanisms utilizes the C &lt;a href="https://en.wikipedia.org/wiki/Application_binary_interface" rel="noopener noreferrer"&gt;ABI&lt;/a&gt;, we need to annotate the Rust function with &lt;code&gt;#[no_mangle]&lt;/code&gt; in order to preserve the function signatures symbol upon compilation. Since we are compiling this into a &lt;code&gt;.so&lt;/code&gt; we need to mark the function as &lt;code&gt;extern&lt;/code&gt; so that it can be linked as any other library. The functions return type is &lt;code&gt;*const c_char&lt;/code&gt;, which is a raw pointer, basically a raw memory adress. We have to do this since Rust's types are not available in Dart. When we send data over to Dart, Rust can no longer take responsibility for cleaning up that data. Rust no longer have the required information regarding that data's usage and could therefore free the data at an inappropriate time. To build this just run &lt;code&gt;cargo b&lt;/code&gt;  &lt;/p&gt;

&lt;p&gt;Now we want to consume the Rust function from the Dart side of the project. To do that we need the following dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'dart:ffi'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ffi&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'dart:ffi'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'dart:typed_data'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter/material.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:ffi/ffi.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can load and use the Rust library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;typedef&lt;/span&gt; &lt;span class="n"&gt;NativeRustStringFromRustFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ffi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Pointer&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Utf8&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;_MyHomePageState&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyHomePage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;_MyHomePageState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_dl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
          &lt;span class="n"&gt;ffi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DynamicLibrary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"libffi_test.so"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_string_from_rust_ffi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
          &lt;span class="n"&gt;_dl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lookupFunction&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;NativeRustStringFromRustFunction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NativeRustStringFromRustFunction&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
          &lt;span class="s"&gt;"string_from_rust"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;_counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Photos taken: 0"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;ffi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DynamicLibrary&lt;/span&gt; &lt;span class="n"&gt;_dl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;NativeRustStringFromRustFunction&lt;/span&gt; &lt;span class="n"&gt;_string_from_rust_ffi&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;_updateMessage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;_counter&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;foreignMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ffi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Utf8&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromUtf8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_string_from_rust_ffi&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
      &lt;span class="n"&gt;_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"'&lt;/span&gt;&lt;span class="si"&gt;$foreignMessage&lt;/span&gt;&lt;span class="s"&gt;': '&lt;/span&gt;&lt;span class="si"&gt;$_counter&lt;/span&gt;&lt;span class="s"&gt;'"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Scaffold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;appBar:&lt;/span&gt; &lt;span class="n"&gt;AppBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;body:&lt;/span&gt; &lt;span class="n"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nl"&gt;mainAxisAlignment:&lt;/span&gt; &lt;span class="n"&gt;MainAxisAlignment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;center&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;[&lt;/span&gt;
            &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_message&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;$_counter&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="nl"&gt;style:&lt;/span&gt; &lt;span class="n"&gt;Theme&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;textTheme&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;headline4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;floatingActionButton:&lt;/span&gt; &lt;span class="n"&gt;FloatingActionButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;onPressed:&lt;/span&gt; &lt;span class="n"&gt;_updateMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;tooltip:&lt;/span&gt; &lt;span class="s"&gt;'Increment'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Icons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We first load the &lt;code&gt;.so&lt;/code&gt; library we compiled from Rust, we look up the function and store it in the state. We then write a small helper function that will call the &lt;code&gt;_string_from_rust_ffi&lt;/code&gt;-function. Then we have to encode the string returned from Rust to UTF8 using &lt;code&gt;Utf8.fromUtf8()&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;In order to test this enable desktop support with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;flutter channel dev
&lt;span class="nv"&gt;$ &lt;/span&gt;flutter upgrade
&lt;span class="nv"&gt;$ &lt;/span&gt;flutter config &lt;span class="nt"&gt;--enable-linux-desktop&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the config with &lt;code&gt;flutter devices&lt;/code&gt; and see that your os shows up. Then to run the app run &lt;code&gt;flutter run -d linux&lt;/code&gt;. You should something like this:&lt;br&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4csorut8sjhfmtf9ydci.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4csorut8sjhfmtf9ydci.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Moving over to the Rpi
&lt;/h2&gt;

&lt;p&gt;The main goal in this post is to get Flutter running on the rpi while consuming a Rust library. So far we haven't run anything on the rpi. Lets fix that!  &lt;/p&gt;

&lt;p&gt;Flutter does not have any official support for rpi, that's why we need to use the aforementioned &lt;a href="https://github.com/ardera/flutter-pi" rel="noopener noreferrer"&gt;flutter-pi&lt;/a&gt;. If you have followed the instructions in the repo for &lt;a href="https://github.com/ardera/flutter-pi" rel="noopener noreferrer"&gt;flutter-pi&lt;/a&gt; you should have it installed on the rpi. It would be ideal if we could just take the code we built earlier and throw it on to the rpi and run it. Unfortunately that's not the case. The &lt;code&gt;engine-binaries&lt;/code&gt;branch from the &lt;a href="https://github.com/ardera/flutter-pi" rel="noopener noreferrer"&gt;flutter-pi&lt;/a&gt; repo needs to be cloned to the "host" (the computer you are coding on) in order for us to build and compile the Flutter app. Once you've done that go through the build steps in the README of &lt;a href="https://github.com/ardera/flutter-pi" rel="noopener noreferrer"&gt;flutter-pi&lt;/a&gt;. To save myself time I've saved these as bash scripts. These are listed below.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;build_snapshot.sh&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
~/flutter/bin/cache/dart-sdk/bin/dart &lt;span class="se"&gt;\&lt;/span&gt;
    ~/flutter/bin/cache/dart-sdk/bin/snapshots/frontend_server.dart.snapshot &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--sdk-root&lt;/span&gt; ~/flutter/bin/cache/artifacts/engine/common/flutter_patched_sdk_product &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;flutter &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--aot&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--tfa&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-Ddart&lt;/span&gt;.vm.product&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--packages&lt;/span&gt; .packages &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--output-dill&lt;/span&gt; build/kernel_snapshot.dill &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--verbose&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--depfile&lt;/span&gt; build/kernel_snapshot.d &lt;span class="se"&gt;\&lt;/span&gt;
    package:hello_world/main.dart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;build_so.sh&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;
~/engine-binaries/gen_snapshot_linux_x64 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--causal_async_stacks&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--deterministic&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--snapshot_kind&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;app-aot-elf &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--elf&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;build/app.so &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--strip&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--sim_use_hardfp&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--no-use-integer-division&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  build/kernel_snapshot.dill
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;build.sh&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
flutter clean &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    flutter build bundle &lt;span class="nt"&gt;--release&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    ./build_snapshot.sh &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    ./build_so.sh &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To build for &lt;a href="https://github.com/ardera/flutter-pi" rel="noopener noreferrer"&gt;flutter-pi&lt;/a&gt; now run the &lt;code&gt;build.sh&lt;/code&gt;script.&lt;br&gt;
Upload the files to the rpi using the &lt;code&gt;upload.sh&lt;/code&gt; script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
rsync &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="nt"&gt;--info&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;progress2 ./build/flutter_assets/ pi@raspberrypi:/home/pi/flutter_hello_world_assets &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    scp ./build/app.so pi@raspberrypi:/home/pi/flutter_hello_world_assets/app.so
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To run the application &lt;code&gt;ssh&lt;/code&gt; into the rpi and run &lt;code&gt;flutter-pi flutter_hello_world_assets&lt;/code&gt;. If all goes well you should see the "Hello world" app from Flutter and once you press the button the text changes to "Hello from rust.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Incorporating the camera
&lt;/h2&gt;

&lt;p&gt;Now that we know how to compile and run Rust and Flutter in conjunction on the rpi we want to be able to control the camera from our app. There might be libraries for controlling the camera written in Dart but since we want to use Rust together with Dart, we're going to do it from Rust.&lt;br&gt;&lt;br&gt;
I've chosen a library called &lt;a href="https://github.com/pedrosland/rascam" rel="noopener noreferrer"&gt;rascam&lt;/a&gt;. It's a small library built on top of &lt;a href="https://github.com/pedrosland/mmal-sys" rel="noopener noreferrer"&gt;mmal-sys&lt;/a&gt;. We can add &lt;a href="https://github.com/pedrosland/rascam" rel="noopener noreferrer"&gt;rascam&lt;/a&gt; to our Rust project by adding this to the &lt;code&gt;Cargo.toml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[dependencies]&lt;/span&gt;
&lt;span class="py"&gt;rascam&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"*"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now lets take a look at the code for taking an image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ffi-test/src/lib.rs&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;ffi&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;CString&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;os&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;c_char&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;rascam&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="nd"&gt;#[repr(C)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;ImageBuffer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;img_ptr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[no_mangle]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;take_photo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;ImageBuffer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="py"&gt;.cameras&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Found 0 cameras. Exiting"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// note that this does not run destructors&lt;/span&gt;
        &lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;process&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;camera&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;SimpleCamera&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="py"&gt;.cameras&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;camera&lt;/span&gt;&lt;span class="nf"&gt;.activate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;camera&lt;/span&gt;&lt;span class="nf"&gt;.take_one&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="nf"&gt;.as_mut_ptr&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;forget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;ib&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ImageBuffer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;img_ptr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;into_raw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ib&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;forget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;ret&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is a lot going on here. If youve never ventures in to the unforgiving territory of low level Rust, this might look a little daunting. But fear not! I will explain it all, piece by piece.&lt;/p&gt;

&lt;p&gt;On a high level this code solves two problems, take a photo and send it to whoever is calling the function. We will start with the second problem, sending the photo to the caller. Since it's just two values we we want to pass on, one might be tempted to utilize a tuple like &lt;code&gt;(*mut u8, u32)&lt;/code&gt;. This is however not a viable option since the memory layout of a tuple in Rust is not guaranteed. So we went with a simple struct. The &lt;code&gt;#[repr(C)]&lt;/code&gt; tells the compiler to treat the struct as a C struct. This means that the fields of the struct will be aligned the same way in memory as we declared them in the code.  We need this because the C ABI being the common grounds for communication between Rust and Dart.  &lt;/p&gt;

&lt;p&gt;We start with getting the necessary info for the camera. We use this to check if there even is a camera to begin with. If there isn't we just close the process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="py"&gt;.cameras&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Found 0 cameras. Exiting"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="c1"&gt;// note that this does not run destructors&lt;/span&gt;
      &lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;process&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We then instatiate the camera using the info and activate it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;camera&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;SimpleCamera&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="py"&gt;.cameras&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
 &lt;span class="n"&gt;camera&lt;/span&gt;&lt;span class="nf"&gt;.activate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We take a photo, get the number of bytes, get a pointer to the byte array and tell the compiler to forget about the byte array. Just as with the string earlier this array will be cleaned up by Dart.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;camera&lt;/span&gt;&lt;span class="nf"&gt;.take_one&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="nf"&gt;.as_mut_ptr&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;forget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we create an &lt;code&gt;ImageBuffer&lt;/code&gt; and place it on the heap by wrapping it in a &lt;code&gt;Box&lt;/code&gt;. If we didn't place it on the heap and still returned a pointer to it, the &lt;code&gt;ImageBuffer&lt;/code&gt; would be popped of the stack once the function call returns. That would make it possible for the memory to get overwritten while Dart uses the pointer. We don't want that!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;ib&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ImageBuffer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;img_ptr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;into_raw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ib&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;forget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;ret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that everything is well and done on the Rust side but how do we actually use this in Dart?&lt;br&gt;
First will need to declare a type to represent the &lt;code&gt;ImageBuffer&lt;/code&gt; in Dart.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ImageBuffer&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Pointer&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Uint8&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;img_ptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

  &lt;span class="nd"&gt;@Uint32&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then we need a type for the actual function providing us the &lt;code&gt;ImageBuffer&lt;/code&gt; and we need to look it up in the library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="kd"&gt;typedef&lt;/span&gt; &lt;span class="n"&gt;NativeRustTakePhotoFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ffi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Pointer&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ImageBuffer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="c1"&gt;// inside MyHomePageState&lt;/span&gt;
  &lt;span class="n"&gt;_MyHomePageState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_dl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
          &lt;span class="n"&gt;ffi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DynamicLibrary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/home/pi/target/debug/libffi_test.so"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_take_photo_ffi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
          &lt;span class="n"&gt;_dl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lookupFunction&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;NativeRustTakePhotoFunction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NativeRustTakePhotoFunction&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
          &lt;span class="s"&gt;"take_photo"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We then declare a function to be called on button press:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;_takePhoto&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;_imageBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_take_photo_ffi&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// _imageBuffer is a member of our state&lt;/span&gt;
      &lt;span class="n"&gt;_counter&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Photos taken: '&lt;/span&gt;&lt;span class="si"&gt;$_counter&lt;/span&gt;&lt;span class="s"&gt;'"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once all that is done we can register the function with the button:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="c1"&gt;// Inside a widget array in a scaffold&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_imageBuffer&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_imageBuffer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;img_ptr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asTypedList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_imageBuffer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;len&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unfortunately I couldn't build the Rust library on my Linux machine because of &lt;a href="https://github.com/pedrosland/mmal-sys" rel="noopener noreferrer"&gt;mmal-sys&lt;/a&gt;. There might be a solution for this. But to build this I:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;pushed the Rust library code to github &lt;/li&gt;
&lt;li&gt;built the flutter bundle on the host, using the scripts&lt;/li&gt;
&lt;li&gt;uploaded it to the rpi and ran it. 
It then gave me this:
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Feed52p020i2necemrmvc.jpg"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now you should hopefully have a Flutter app running on a rpi!&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;p&gt;For me the main takeaway is that our approach here might actually be a viable option for resource scarce devices. The possibility of writing a beautiful, interactive application in Flutter and have run in a car infotainment system for example is quite exciting. The possibility to handle the low level stuff with languages such as Rust and C, really opens up this domain for Flutter.&lt;br&gt;
I at least know that I am waiting for official rpi support for Flutter so that I can build something more robust!&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>rust</category>
      <category>raspberrypi</category>
      <category>linux</category>
    </item>
    <item>
      <title>Drawing arrows in Flutter, or anything else, based on widget positions</title>
      <dc:creator>Jonathan Böcker</dc:creator>
      <pubDate>Fri, 07 Aug 2020 07:19:32 +0000</pubDate>
      <link>https://dev.to/charliefoxtrot/drawing-arrows-in-flutter-or-anything-else-based-on-widget-positions-2883</link>
      <guid>https://dev.to/charliefoxtrot/drawing-arrows-in-flutter-or-anything-else-based-on-widget-positions-2883</guid>
      <description>&lt;p&gt;I recently made a Flutter package called &lt;code&gt;widget_arrows&lt;/code&gt; which caught some attention on the &lt;a href="https://www.reddit.com/r/FlutterDev/comments/i2dv6o/i_made_a_package_for_drawing_arrows_between_any/" rel="noopener noreferrer"&gt;FlutterDev subreddit&lt;/a&gt;.&lt;br&gt;
I thought I'd take a minute to explain how it works, since the technique can be applied to other things, such as a &lt;a href="https://www.flutterclutter.dev/flutter/tutorials/how-to-cut-a-hole-in-an-overlay/2020/510/" rel="noopener noreferrer"&gt;tutorial hole overlay&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Schwusch" rel="noopener noreferrer"&gt;
        Schwusch
      &lt;/a&gt; / &lt;a href="https://github.com/Schwusch/widget_arrows" rel="noopener noreferrer"&gt;
        widget_arrows
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Draw arrows between widgets in Flutter
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;widget_arrows&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;Draw arrows between widgets&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/a39a90347114bed6311a26c3fb0e1516551ced9cceb9b61aa7063a947d2cf7eb/68747470733a2f2f6d656469612e67697068792e636f6d2f6d656469612f6769764665446f504c62574c6e5a637651522f67697068792e676966"&gt;&lt;img src="https://camo.githubusercontent.com/a39a90347114bed6311a26c3fb0e1516551ced9cceb9b61aa7063a947d2cf7eb/68747470733a2f2f6d656469612e67697068792e636f6d2f6d656469612f6769764665446f504c62574c6e5a637651522f67697068792e676966" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Schwusch/widget_arrows" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;Using it is fairly straight forward, wrap the Widgets you want to draw arrows between with an &lt;a href="https://pub.dev/documentation/widget_arrows/latest/widget_arrows/ArrowElement-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;ArrowElement&lt;/code&gt;&lt;/a&gt; and wrap both with an &lt;a href="https://pub.dev/documentation/widget_arrows/latest/widget_arrows/ArrowContainer-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;ArrowContainer&lt;/code&gt;&lt;/a&gt; higher up in the Widget hierarchy .&lt;/p&gt;

&lt;p&gt;In this case I wrap the whole &lt;code&gt;MaterialApp&lt;/code&gt; in an &lt;code&gt;ArrowContainer&lt;/code&gt; in order to display the arrows while dragging an element:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/schwusch/embed/yLemBZQ?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The core Widget is the &lt;code&gt;ArrowContainer&lt;/code&gt;, which is the one drawing the arrows on a canvas layered on top of the child, using a &lt;code&gt;Stack&lt;/code&gt;.&lt;br&gt;
Here's an example: &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="n"&gt;ArrowContainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="n"&gt;ArrowElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;id:&lt;/span&gt; &lt;span class="s"&gt;'top'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;targetId:&lt;/span&gt; &lt;span class="s"&gt;'bottom'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Text1'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="n"&gt;ArrowElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;show:&lt;/span&gt; &lt;span class="n"&gt;showArrows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;id:&lt;/span&gt; &lt;span class="s"&gt;'bottom'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Text2'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;During &lt;code&gt;initState()&lt;/code&gt;, the &lt;code&gt;_ArrowElementState&lt;/code&gt; looks up the widget hierarchy and finds the closest &lt;code&gt;_ArrowContainerState&lt;/code&gt; and registers itself by calling &lt;code&gt;addArrow(this)&lt;/code&gt; on the container. The &lt;code&gt;_ArrowContainerState&lt;/code&gt; will then trigger a repaint on the &lt;code&gt;CustomPainter&lt;/code&gt; that draws on top of &lt;code&gt;ArrowContainer&lt;/code&gt;s child, which in this case is a &lt;code&gt;Column&lt;/code&gt;.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkakpxhetb19tfjxqm1we.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkakpxhetb19tfjxqm1we.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How does the &lt;code&gt;_ArrowElementState&lt;/code&gt; find the &lt;code&gt;_ArrowContainerState&lt;/code&gt;? By calling this method on the &lt;code&gt;BuildContext&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findAncestorStateOfType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;_ArrowContainerState&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Since &lt;code&gt;ArrowContainer&lt;/code&gt; is a &lt;code&gt;StatefulWidget&lt;/code&gt;, it has its associated &lt;code&gt;_ArrowContainerState&lt;/code&gt;. It's a relatively expensive lookup, but the good news is that it is only needed once per &lt;code&gt;ArrowElement&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;_ArrowContainerState&lt;/code&gt; has &lt;code&gt;ChangeNotifier&lt;/code&gt; mixed in, in its class declaration. That means that it can be passed in as an argument to the &lt;code&gt;CustomPainter&lt;/code&gt; constructor, and it will repaint every time &lt;code&gt;_ArrowContainerState&lt;/code&gt; calls &lt;code&gt;notifyListeners()&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;_ArrowContainerState.notifyListeners()&lt;/code&gt; is called every time an arrow element is added or removed, which means it is always kept in sync with all &lt;code&gt;ArrowElement&lt;/code&gt;s currently mounted in its child &lt;code&gt;Widget&lt;/code&gt; subtree.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;_ArrowContainerState&lt;/code&gt; build method look like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="nd"&gt;@override&lt;/span&gt;
&lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Stack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;child&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;IgnorePointer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;CustomPaint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nl"&gt;foregroundPainter:&lt;/span&gt; &lt;span class="n"&gt;_ArrowPainter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="n"&gt;_elements&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="n"&gt;Directionality&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
              &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
          &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;CustomPaint&lt;/code&gt; is wrapped with an &lt;code&gt;IgnorePointer&lt;/code&gt;, to let through touch events to &lt;code&gt;widget.child&lt;/code&gt;, which is the users real UI. The &lt;code&gt;_ArrowPainter&lt;/code&gt; is a custom class extending &lt;code&gt;CustomPainter&lt;/code&gt; to draw the Arrows. It takes the &lt;code&gt;_ArrowElementState&lt;/code&gt;s as a first argument, the &lt;code&gt;TextDirection&lt;/code&gt; as the second argument (we will cover why later), and a &lt;code&gt;Listenable&lt;/code&gt; as the third argument. The &lt;code&gt;_ArrowContainerState&lt;/code&gt; is a &lt;code&gt;Listenable&lt;/code&gt;, due to having &lt;code&gt;ChangeNotifier&lt;/code&gt; mixed in.&lt;/p&gt;

&lt;p&gt;What happens in &lt;code&gt;_ArrowPainter.paint()&lt;/code&gt; is the real magic. It loops through all &lt;code&gt;_ArrowElementState&lt;/code&gt;s, and calls this method:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;renderBox&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arrowElementState&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;context&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findRenderObject&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;RenderBox&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;RenderBox&lt;/code&gt; is the key to finding the position of the start and end of the arrows we're about to draw.&lt;br&gt;
By calling this method:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Offset&lt;/span&gt; &lt;span class="n"&gt;upperLeftCorner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderBox&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;localToGlobal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Offset&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;zero&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We get an &lt;code&gt;Offset&lt;/code&gt; of where it is relative to the top-left corner of the screen. The &lt;code&gt;RenderBox&lt;/code&gt; also has &lt;code&gt;RenderBox.size&lt;/code&gt; which gives us its dimensions, which is used to describe the rectangle in which the child is drawn. &lt;/p&gt;

&lt;p&gt;This is where &lt;code&gt;TextDirection&lt;/code&gt; comes in. The &lt;code&gt;ArrowElement&lt;/code&gt; has a &lt;code&gt;sourceAnchor&lt;/code&gt; and a &lt;code&gt;targetAnchor&lt;/code&gt; argument which takes an &lt;a href="https://api.flutter.dev/flutter/painting/AlignmentGeometry-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;AlignmentGeometry&lt;/code&gt;&lt;/a&gt;. This allows us to specify where in the child &lt;code&gt;Widget&lt;/code&gt; we like the arrow to start or end from, and is &lt;code&gt;Alignment.centerLeft&lt;/code&gt; by default. You can pass an &lt;a href="https://api.flutter.dev/flutter/painting/AlignmentDirectional-class.html" rel="noopener noreferrer"&gt;&lt;code&gt;AlignmentDirectional&lt;/code&gt;&lt;/a&gt; to make it adapt to whether the text is right-to-left or left-to-right. To adapt to the text direction, this method is called on the &lt;code&gt;AlignmentGeometry&lt;/code&gt; object:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Offset&lt;/span&gt; &lt;span class="n"&gt;startPosition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sourceAnchor&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;textDirection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withinRect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cm"&gt;/*child widget rectangle*/&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;From there, all that's left is to draw a &lt;code&gt;Path&lt;/code&gt; or whatever you like on the canvas at that position.&lt;/p&gt;

&lt;p&gt;Happy Fluttering!&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
    </item>
  </channel>
</rss>
