Skip to content

Commit

Permalink
Cleaned up image processing backend and added scramble command
Browse files Browse the repository at this point in the history
  • Loading branch information
Numenization committed Apr 22, 2018
1 parent 58518c4 commit aea9d80
Show file tree
Hide file tree
Showing 4 changed files with 200 additions and 20 deletions.
49 changes: 42 additions & 7 deletions Modules/ImageProcessing/ImageCommands.cs
Original file line number Diff line number Diff line change
@@ -1,37 +1,72 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Diagnostics;
using Discord;
using Discord.Commands;

namespace GarlicBot.Modules.ImageProcessing
{
public class ImageCommands : ModuleBase<SocketCommandContext> {
[Command("read", RunMode = RunMode.Async)]
[Command("scramble", RunMode = RunMode.Async)]
public async Task readImage() {
var attachments = Context.Message.Attachments.GetEnumerator();
if(attachments.MoveNext()) {
string url = attachments.Current.Url;
ImageReader reader = new ImageReader();
var reader = new ImageReader();
var error = new ImageReadError();
var progress = new Progress<string>();
progress.ProgressChanged += (s, e) => {
Utilities.Log(e, LogSeverity.Verbose);
};
if (await reader.ReadFromUrl(url, progress)) {
if (await reader.ReadFromUrl(url, progress, error)) {
//do stuff with image
var processProgress = new Progress<double>();
processProgress.ProgressChanged += (s, e) => {
Utilities.Log($"Processing {e}%", LogSeverity.Verbose);
};
ImageProcessor processor = new ImageProcessor(reader);
string file = await processor.Scramble(processProgress);
await Utilities.Log("Sending file...", LogSeverity.Info);
await Context.Channel.SendFileAsync(file);
}
else {
var embed = new EmbedBuilder();
embed.WithTitle(await Utilities.GetAlert("commandErrorTitle"));
embed.WithDescription(error.ErrorReason);
embed.WithColor(await Utilities.ParseColor(Config.bot.embedColor));
embed.WithAuthor(Config.bot.botName, Config.bot.botIconURL);
await Context.Channel.SendMessageAsync("", false, embed.Build());
}
}
}

[Command("read", RunMode = RunMode.Async)]
[Command("scramble", RunMode = RunMode.Async)]
public async Task readImageUrl([Remainder]string url) {
ImageReader reader = new ImageReader();
var reader = new ImageReader();
var error = new ImageReadError();
var progress = new Progress<string>();
progress.ProgressChanged += (s, e) => {
Utilities.Log(e, LogSeverity.Verbose);
};
if (await reader.ReadFromUrl(url, progress)) {
// do stuff with image
if (await reader.ReadFromUrl(url, progress, error)) {
//do stuff with image
var processProgress = new Progress<double>();
processProgress.ProgressChanged += (s, e) => {
Utilities.Log($"Processing {e}%", LogSeverity.Verbose);
};
ImageProcessor processor = new ImageProcessor(reader);
string file = await processor.Scramble(processProgress);
await Utilities.Log("Sending file...", LogSeverity.Info);
await Context.Channel.SendFileAsync(file);
}
else {
var embed = new EmbedBuilder();
embed.WithTitle(await Utilities.GetAlert("commandErrorTitle"));
embed.WithDescription(error.ErrorReason);
embed.WithColor(await Utilities.ParseColor(Config.bot.embedColor));
embed.WithAuthor(Config.bot.botName, Config.bot.botIconURL);
await Context.Channel.SendMessageAsync("", false, embed.Build());
}
}
}
Expand Down
110 changes: 110 additions & 0 deletions Modules/ImageProcessing/ImageProcessor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading.Tasks;
using System.Diagnostics;

namespace GarlicBot.Modules.ImageProcessing
{
public class ImageProcessor
{
public ImageProcessor(ImageReader reader) {
_working = false;
_progress = 0;
_progressDecimals = 1;
_timeBetweenUpdates = 500;
_reader = reader;
}

public ImageProcessor(ImageReader reader, ImageProcessorSettings settings) {
_working = false;
_progress = 0;
_progressDecimals = settings.ProgressDecimals;
_timeBetweenUpdates = settings.UpdateTick;
_reader = reader;
}

public async Task<string> Scramble(IProgress<double> progress) {
if(_reader.Bitmap != null && _reader.Ready) {
//do stuff with image
await Utilities.Log("Processing image...", Discord.LogSeverity.Info);
Bitmap bitmap = _reader.Bitmap;
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
Random rand = new Random();
long totalPixels = bitmap.Width * (bitmap.Height / 2);
long lastUpdate = 0;
long pixelsProcessed = 0;

for (int i = 0; i < bitmap.Width; i++) {
for (int j = 0; j < bitmap.Height / 2; j++) {
if (rand.Next() % 2 == 1) {
Color temp = bitmap.GetPixel(i, j);
bitmap.SetPixel(i, j, bitmap.GetPixel(i, (bitmap.Height - 1) - j));
bitmap.SetPixel(i, (bitmap.Height - 1) - j, temp);
}
pixelsProcessed++;
if (stopwatch.ElapsedMilliseconds - lastUpdate >= _timeBetweenUpdates) {
lastUpdate = stopwatch.ElapsedMilliseconds;
progress.Report(Math.Round(((double)pixelsProcessed / totalPixels) * 100, _progressDecimals));
}
}
}

string newFileName = $"Resources/Images/{_reader.FileName}_Scrambled.jpg";
bitmap.Save(newFileName, ImageFormat.Jpeg);
stopwatch.Stop();
await Utilities.Log($"Done ({(double)stopwatch.ElapsedMilliseconds / 1000} s)", Discord.LogSeverity.Verbose);
return newFileName;
}
else {
throw new Exception("Trying to modify image from invalid reader.");
}
}

private double _progress;
private bool _working;
private ImageReader _reader;
private long _timeBetweenUpdates;
private int _progressDecimals;

public bool Working {
get {
return _working;
}
}
public double Progress {
get {
return _progress;
}
}
public long UpdateTick {
set {
_timeBetweenUpdates = value;
}
get {
return _timeBetweenUpdates;
}
}
public int ProgressDecimals {
set {
_progressDecimals = value;
}
get {
return _progressDecimals;
}
}
}

public class ImageProcessorSettings {
public ImageProcessorSettings(long updateTick = 500, int progressDecimals = 1) {
UpdateTick = updateTick;
ProgressDecimals = progressDecimals;
}

public long UpdateTick;
public int ProgressDecimals;
}
}
58 changes: 46 additions & 12 deletions Modules/ImageProcessing/ImageReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,45 +18,52 @@ public ImageReader() {
}
}

public async Task<bool> ReadFromUrl(string url, IProgress<string> progress) {
public async Task<bool> ReadFromUrl(string url, IProgress<string> progress, ImageReadError error) {
if(!_ready) {
progress.Report("Already working on operation");
string errorMsg = "Already working on operation";
progress.Report(errorMsg);
error.ErrorReason = errorMsg;
return false;
}
_ready = false;

Uri uri;
if(Uri.TryCreate(url, UriKind.RelativeOrAbsolute, out uri)) {
if(Uri.TryCreate(url, UriKind.Absolute, out uri) && Path.HasExtension(url)) {
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri);
HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
long fileSize = webResponse.ContentLength;
string extension = Path.GetExtension(url);
if (fileSize <= (Config.bot.maxFileSize * kilobyteRatio)) { // max file size is in kilobytes, file size is given in bytes
progress.Report($"File size is {Math.Round((double)fileSize / kilobyteRatio)} KB. Opening download stream...");
WebClient client = new WebClient();
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
long elapsedTimeSinceLastUpdate = 0;

client.DownloadProgressChanged += (s, e) => {
if(stopwatch.ElapsedMilliseconds % 250 == 0)
if(stopwatch.ElapsedMilliseconds - elapsedTimeSinceLastUpdate >= 250) {
elapsedTimeSinceLastUpdate = stopwatch.ElapsedMilliseconds;
progress.Report($"Downloading {Math.Round((double)e.BytesReceived / kilobyteRatio)}/{Math.Round((double)fileSize / kilobyteRatio)} KB");
}
};

string fileName = $"{DateTime.Now.ToFileTime()}";
await client.DownloadFileTaskAsync(uri, $"{folder}/{fileName}{extension}");
_fileName = $"{DateTime.Now.ToFileTime()}";
await client.DownloadFileTaskAsync(uri, $"{folder}/{_fileName}{extension}");
stopwatch.Stop();
progress.Report($"Download complete ({Math.Round((double)fileSize / kilobyteRatio)} KB). Opening file for modification...");
_bitmap = (Bitmap)System.Drawing.Image.FromFile($"{folder}/{fileName}{extension}");
progress.Report("Image opened and ready for writing.");
_bitmap = (Bitmap)System.Drawing.Image.FromFile($"{folder}/{_fileName}{extension}");
progress.Report($"Download complete ({Math.Round((double)fileSize / kilobyteRatio)} KB).");
}
else {
progress.Report($"File is too big! ({Math.Round((double)fileSize / kilobyteRatio)}/{Config.bot.maxFileSize} KB)");
string errorMsg = $"File is too big! ({Math.Round((double)fileSize / kilobyteRatio)}/{Config.bot.maxFileSize} KB)";
progress.Report(errorMsg);
error.ErrorReason = errorMsg;
_ready = true;
return false;
}
}
else {
progress.Report($"Could not read URL");
string errorMsg = await Utilities.GetAlert("imageDownloadFailed");
progress.Report(errorMsg);
error.ErrorReason = errorMsg;
_ready = true;
return false;
}
Expand All @@ -75,11 +82,38 @@ public bool Ready {
}
}

private string _fileName;
public string FileName {
get {
return _fileName;
}
}

private Bitmap _bitmap;
public ref Bitmap Bitmap {
get {
return ref _bitmap;
}
}
}

public class ImageReadError {
public ImageReadError() {
_reason = "NULL";
}

public ImageReadError(string reason) {
_reason = reason;
}

private string _reason;
public string ErrorReason {
set {
_reason = value;
}
get {
return _reason;
}
}
}
}
3 changes: 2 additions & 1 deletion SystemLang/alerts.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@
"rollOutput": "Roll the Dice ({0} sides)",
"rollResult": "{0}Result: `{1}`",
"invalidPerms": "You do not have the required permissions for that command",
"shutdownMessage": "Shutting down {0}..."
"shutdownMessage": "Shutting down {0}...",
"imageDownloadFailed": "Error in downloading image."
}

0 comments on commit aea9d80

Please sign in to comment.