Commit 9e242d22 authored by Sergio Monge's avatar Sergio Monge
Browse files

Serverles Azure Function with client - convert images to ascii

parents
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# Azure Functions localsettings file
local.settings.json
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
project.fragment.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
#*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush
.cr/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
\ No newline at end of file
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.Drawing;
using System.Text;
using System.Runtime.Serialization.Formatters.Binary;
using System.Collections.Generic;
namespace ConvertImageToAscii
{
public enum ContentType
{
HTML,
String
}
public class RequestPayload
{
public byte[] image { get; set; }
public int size { get; set; }
public ContentType type { get; set; }
}
public static class ConverToAsciiFunction
{
private static List<string> _AsciiChars = new List<string>() { "#", "#", "@", "%", "=", "+", "*", ":", "-", "." };
[FunctionName("ConvertImageToAscii")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest request,
ILogger log)
{
string content;
try
{
var data = await new StreamReader(request.Body).ReadToEndAsync();
RequestPayload payload = JsonConvert.DeserializeObject<RequestPayload>(data);
Bitmap image = new Bitmap(new MemoryStream(payload.image), true);
image = GetReSizedImage(image, payload.size);
content = ConvertToAscii(image, payload.type);
}
catch (Exception ex)
{
return new BadRequestObjectResult(ex.ToString());
}
return new OkObjectResult(content);
}
private static string ConvertToAscii(Bitmap image, ContentType type)
{
string newLineCharacter = string.Empty;
switch (type)
{
case ContentType.String:
newLineCharacter = Environment.NewLine;
_AsciiChars.Add(" ");
break;
case ContentType.HTML:
default:
newLineCharacter = "<BR>";
_AsciiChars.Add("&nbsp;");
break;
}
Boolean toggle = false;
StringBuilder sb = new StringBuilder();
for (int h = 0; h < image.Height; h++)
{
for (int w = 0; w < image.Width; w++)
{
Color pixelColor = image.GetPixel(w, h);
//Average out the RGB components to find the Gray Color
int red = (pixelColor.R + pixelColor.G + pixelColor.B) / 3;
int green = (pixelColor.R + pixelColor.G + pixelColor.B) / 3;
int blue = (pixelColor.R + pixelColor.G + pixelColor.B) / 3;
Color grayColor = Color.FromArgb(red, green, blue);
//Use the toggle flag to minimize height-wise stretch
if (!toggle)
{
int index = (grayColor.R * 10) / 255;
sb.Append(_AsciiChars[index]);
}
}
if (!toggle)
{
sb.Append(newLineCharacter);
toggle = true;
}
else
{
toggle = false;
}
}
return sb.ToString();
}
private static Bitmap GetReSizedImage(Bitmap inputBitmap, int asciiWidth = 200)
{
int asciiHeight = 0;
//Calculate the new Height of the image from its width
asciiHeight = (int)Math.Ceiling((double)inputBitmap.Height * asciiWidth / inputBitmap.Width);
//Create a new Bitmap and define its resolution
Bitmap result = new Bitmap(asciiWidth, asciiHeight);
Graphics g = Graphics.FromImage((Image)result);
//The interpolation mode produces high quality images
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.DrawImage(inputBitmap, 0, 0, asciiWidth, asciiHeight);
g.Dispose();
return result;
}
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AzureFunctionsVersion>v3</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.11" />
<PackageReference Include="System.Drawing.Common" Version="5.0.2" />
</ItemGroup>
<ItemGroup>
<None Update="host.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="local.settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
</ItemGroup>
</Project>
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<WebPublishMethod>ZipDeploy</WebPublishMethod>
<PublishProvider>AzureWebSite</PublishProvider>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<SiteUrlToLaunchAfterPublish>https://gap-convertimagetoascii.azurewebsites.net</SiteUrlToLaunchAfterPublish>
<LaunchSiteAfterPublish>False</LaunchSiteAfterPublish>
<ResourceId>/subscriptions/a5c3c34d-8e9e-41a3-bef0-3a80474c4063/resourcegroups/ConvertImageToAscii20211011103709ResourceGroup/providers/Microsoft.Web/sites/GAP-ConvertImageToAscii</ResourceId>
<UserName>$GAP-ConvertImageToAscii</UserName>
<_SavePWD>True</_SavePWD>
<PublishUrl>https://gap-convertimagetoascii.scm.azurewebsites.net/</PublishUrl>
</PropertyGroup>
</Project>
\ No newline at end of file
{
"dependencies": {
"appInsights1": {
"type": "appInsights"
}
}
}
\ No newline at end of file
{
"dependencies": {
"appInsights1": {
"type": "appInsights.sdk"
}
}
}
\ No newline at end of file
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
}
}
}
\ No newline at end of file
namespace ImageToASCIIconverter
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.btnConvertToAscii = new System.Windows.Forms.Button();
this.btnBrowse = new System.Windows.Forms.Button();
this.txtPath = new System.Windows.Forms.TextBox();
this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog();
this.browserMain = new System.Windows.Forms.WebBrowser();
this.menuStrip1 = new System.Windows.Forms.MenuStrip();
this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.saveAsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.saveFileDialog1 = new System.Windows.Forms.SaveFileDialog();
this.trackBar = new System.Windows.Forms.TrackBar();
this.menuStrip1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.trackBar)).BeginInit();
this.SuspendLayout();
//
// btnConvertToAscii
//
this.btnConvertToAscii.Location = new System.Drawing.Point(243, 63);
this.btnConvertToAscii.Name = "btnConvertToAscii";
this.btnConvertToAscii.Size = new System.Drawing.Size(107, 23);
this.btnConvertToAscii.TabIndex = 3;
this.btnConvertToAscii.Text = "Convert To ASCII";
this.btnConvertToAscii.UseVisualStyleBackColor = true;
this.btnConvertToAscii.Click += new System.EventHandler(this.btnConvertToAscii_Click);
//
// btnBrowse
//
this.btnBrowse.Location = new System.Drawing.Point(356, 35);
this.btnBrowse.Name = "btnBrowse";
this.btnBrowse.Size = new System.Drawing.Size(51, 23);
this.btnBrowse.TabIndex = 5;
this.btnBrowse.Text = "Browse";
this.btnBrowse.UseVisualStyleBackColor = true;
this.btnBrowse.Click += new System.EventHandler(this.btnBrowse_Click);
//
// txtPath
//
this.txtPath.Location = new System.Drawing.Point(12, 37);
this.txtPath.Name = "txtPath";
this.txtPath.Size = new System.Drawing.Size(338, 20);
this.txtPath.TabIndex = 6;
//
// openFileDialog1
//
this.openFileDialog1.FileName = "openFileDialog1";
//
// browserMain
//
this.browserMain.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.browserMain.Location = new System.Drawing.Point(12, 111);
this.browserMain.MinimumSize = new System.Drawing.Size(20, 20);
this.browserMain.Name = "browserMain";
this.browserMain.Size = new System.Drawing.Size(760, 641);
this.browserMain.TabIndex = 7;
//
// menuStrip1
//
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.fileToolStripMenuItem});
this.menuStrip1.Location = new System.Drawing.Point(0, 0);
this.menuStrip1.Name = "menuStrip1";
this.menuStrip1.Size = new System.Drawing.Size(784, 24);
this.menuStrip1.TabIndex = 8;
this.menuStrip1.Text = "menuStrip1";
//
// fileToolStripMenuItem
//
this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.saveAsToolStripMenuItem,
this.exitToolStripMenuItem});
this.fileToolStripMenuItem.Name = "fileToolStripMenuItem";
this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20);
this.fileToolStripMenuItem.Text = "File";
//
// saveAsToolStripMenuItem
//
this.saveAsToolStripMenuItem.Name = "saveAsToolStripMenuItem";
this.saveAsToolStripMenuItem.Size = new System.Drawing.Size(114, 22);
this.saveAsToolStripMenuItem.Text = "Save As";
this.saveAsToolStripMenuItem.Click += new System.EventHandler(this.saveAsToolStripMenuItem_Click);
//
// exitToolStripMenuItem
//
this.exitToolStripMenuItem.Name = "exitToolStripMenuItem";
this.exitToolStripMenuItem.Size = new System.Drawing.Size(114, 22);
this.exitToolStripMenuItem.Text = "Exit";
//
// trackBar
//
this.trackBar.Location = new System.Drawing.Point(12, 63);
this.trackBar.Maximum = 400;
this.trackBar.Minimum = 1;
this.trackBar.Name = "trackBar";
this.trackBar.Size = new System.Drawing.Size(214, 45);
this.trackBar.TabIndex = 9;