Home Upgrade Search Memberlist Extras Hacker Tools Award Goals Help Wiki Contact

C# 

Spreeder | Create Custom SpeedRead Gifs | Gif Encode, Measure String

After seeing a hilarious use of speed reading as a signature, I was inspired to recreate this in C#. This was a lot of fun to make and I learned some more about the Drawing.Graphics class in the process, which is why I'm sharing it.

So how does this work? We start by splitting up the input by space - to retain punctuation - and building a new frame for each of them. The main issue was font size as some words are larger than others and may spill out of the frame. To fix this, we take the largest word and update the font size to the bitmap's size divided by the width of our measured string (largest word).

For ease, I pinched the BumpKit GifEncoder and used that to encode and export the output.

Ignore the poor front end, it's sloppy and was only for demonstration. Otherwise, I'd like some feedback on the class. I rarely write from scratch in C# so I'm looking forward to what people can pick out.

Demonstration: (Click to View)

Downloads:
Full source (GitHub)
Binary only (MediaFire)

Credits:
BumpKit GifEncoder: https://github.com/DataDink/Bumpkit/blob...Encoder.cs
That's a badass project! In my opinion pretty easy to make but very useful aswell for signatures and stuff.
Can you explain BumpKit? I think i know what it is but i want to be sure.

[Image: D12KBT6.png]
(Aug 4, 2015 06:57 AM)Snoweyes Wrote:  That's a badass project! In my opinion pretty easy to make but very useful aswell for signatures and stuff.
Can you explain BumpKit? I think i know what it is but i want to be sure.

I never said it was a hard project 😝

BumpKit is an image manip library with all sorts of goodies to easily do more with the Graphics class. You can read more on their Git readme: https://github.com/DataDink/Bumpkit

But rather than carry an entire lib, I just took the GifEncoder class.
Nice project you're working on, thanks for the PM.
I only do deals onsite through PM's/Contracts.
I do not use Discord, or Skype, or talk to members offsite whatsoever.
This is a pretty nice program, I love it already.
*shitty ad for money*

A few things.

1: Where the fuck are the namespaces?
2: LINQ is pretty cool, try using it.
Your BuildFrames return is
Code
foreach (var word in words)
      yield return RenderFrame(word);
Becomes:
Code
return words.Select(RenderFrame);
3: Add some error handling. I see a lot of unhandled exceptions in the making.

I was going to harass you about passing in a stream as a constructor but you are implementing IDisposable and correctly using a using statement so thats a nice surprise.

There's some quality of life changes such as incorporating a few design patterns to make your code more accessible.
Not bad overall though. Much higher quality than what I was expecting. Main thing is just to handle your exceptions and you're good.
(Aug 4, 2015 11:50 AM)Odus Wrote:  Oops that slipped by me, fixed.

Good point, done.

Also done, I just read into those. Very cool. Thank you Trvp :)

Also, since you are calling RenderFrame in a for each loop, I would pass the brush as a parameter so you don't initialize the same brush multiple times.

[Image: 1zL3pDG.jpg]

Some feedback and nitpicks for ReaderEngine:

(Aug 4, 2015 12:07 PM)SIM-1676753 Wrote:  Also, since you are calling RenderFrame in a for each loop, I would pass the brush as a parameter so you don't initialize the same brush multiple times.

Instead you should have the brush be a private instance variable and have the ForeColor property interface with Brush.Color.

https://github.com/oduslabs/Speed-Reader...ine.cs#L19
I think you meant to name fontCol foreCol. Also it seems kind of weird that you would let the class be constructed with a ForeColor and BackColor but not with Font and Size seeing as how they're all public properties and all the constructor parameters are optional anyway.

Also it's generally better to be verbose (at least, in C#) or at least consistent in your naming style. fontCol should be foreColor, backCol should be backColor (plus this makes it consistent with the property names), maxWrd should be maxWord and so forth. And compare line 64-74 with lines 45-58: you chose to shorten graphic to g, brush to b, fileStream to fs, yet you spelled out stream and encoder.

https://github.com/oduslabs/Speed-Reader...ine.cs#L45
Why write the gif to a MemoryStream then to a FileStream when you can write directly to the FileStream?
So question. Are you just abusing the nullable variables or is there actually a reason you're doing something like this

Code
public ReaderEngine(Color? fontCol = null, Color? backCol = null)
    {
      Font = new Font("Arial", 120, FontStyle.Regular);

      ForeColor = fontCol ?? Color.Black;
      BackColor = backCol ?? Color.White;
    }

Why not use have two constructors - one that takes no parameters and sets forecolor to black and so on and one that takes two variables and sets them to the colors.

Also going off what zer0 was saying is that you should really never have variables from initialized parameters and then be able to set variables later on down the road. Pick one. Either let the user change the variables on the fly and set them to be public or private readonly them all and initialize from constructor.

I shouldn't really be able to do something like this:

Code
var reader = new ReaderEngine(Color.Black, Color.White)
{
     Font = "Arial",
     ForeColor = Color.Purple,
     BackColor = Color.White
}

I think this would be a good case where you could use the factory pattern efficiently.
(Aug 4, 2015 12:05 PM)Serux Wrote:  2: LINQ is pretty cool, try using it.
Your BuildFrames return is
Code
foreach (var word in words)
      yield return RenderFrame(word);
Becomes:
Code
return words.Select(RenderFrame);

You know what, I remember saying exactly the same thing with something like this, no idea why I forgot. Very clever, thanks. LINQ was already present though, see maxWord ln

(Aug 4, 2015 12:05 PM)Serux Wrote:  There's some quality of life changes such as incorporating a few design patterns to make your code more accessible.
Not bad overall though. Much higher quality than what I was expecting. Main thing is just to handle your exceptions and you're good.

I agree, will work on that later.

(Aug 4, 2015 12:41 PM)Zer0Fact0r Wrote:  Instead you should have the brush be a private instance variable and have the ForeColor property interface with Brush.Color.

Very good idea, implemented it.

(Aug 4, 2015 12:41 PM)Zer0Fact0r Wrote:  I think you meant to name fontCol foreCol. Also it seems kind of weird that you would let the class be constructed with a ForeColor and BackColor but not with Font and Size seeing as how they're all public properties and all the constructor parameters are optional anyway.

These were named like such since the names I'd like to use were already in use. Taking Trvp's advice of auto properties freed them up and I forgot to change them. As for font -> fore, the property was originally named 'FontColor' but I changed it last minute since it never really sat with me. Mismatching conventions have also been fixed.

(Aug 4, 2015 12:41 PM)Zer0Fact0r Wrote:  Why write the gif to a MemoryStream then to a FileStream when you can write directly to the FileStream?

Fantastic idea. I forgot they both derive from Stream.

(Aug 4, 2015 02:28 PM)Serux Wrote:  So question. Are you just abusing the nullable variables or is there actually a reason you're doing something like this

It was a workaround since the compiler wasn't happy my optional args weren't 'compile-time constants'. Got rid of all optional and just initialized instead. As for error handling, inadvertently got most of it covered since all my properties & private variables are initialized. I've also added some checks for null arguments.

Thanks very much to both of you for your feedback. I'm going to post more in C#, never had this kind of criticism before. Fixes have been pushed to master.
This is fun to play around with, good work Odus!
"I sexually identity as an Attack helicopter" lmfao.

Regardless, nice release.


Possibly Related Threads...
Thread / Author Replies Views Last Post
[C#] by draxyeeMay 13, 2020 08:33 AM 5 215 May 13, 2020 08:33 AM
Last Post: draxyee
[C#] by mayar2020Apr 13, 2020 08:52 PM 9 252 Apr 13, 2020 08:52 PM
Last Post: zataeta
[C#] by Fun VidosJan 27, 2020 02:36 AM 2 185 Jan 27, 2020 02:36 AM
Last Post: Fun Vidos