Layers

Sometimes those of us who deal with computers on a day to day basis take things for granted. Anybody who’s had even a passing interaction with graphics applications is familiar with the concept of layers. For those who aren’t, this post is for you.

In the process of creating a final image that is composed of multiple source images, text, and other shapes there are situations where you want some items to be on “top” of other images.

Before we get to layers it’s important to first talk about the canvas. The canvas is what everything gets drawn to (much like a real canvas) every time you make a change to the image. Here’s where graphics editing differs from traditional canvas drawing though: A canvas is drawn on by rendering a bunch of images in a specific order. Each image that is drawn to the canvas is what we would call a layer.

So what is a layer? For the purpose of PhotoMonkee (and most other graphics editing programs), a layer is either a collection of pixels or some text (which can later be converted into a collection of pixels). Layers have attributes such as opacity (how transparent its contents are), blending mode and most important for our topic today, depth index. The depth index (or z-index) determines what position the layer is rendered in.

In the example below I’ve drawn four squares (each in their own layer) and renamed each layer to match the depth index that it’s currently at. As you can see, the green square is lowest, with an index of 4 and the red square is highest with an index of 1. The blue square, with an index of 2, is drawn above the green square but below the red one.

To quickly demonstrate the blending and opacity attributes of layers I’ve set the opacity for layers 1 and 3 to 50% and changed their blending modes to “difference”. The blending mode will impact how the layer is drawn based on the layers that have been drawn before it (or under it).

Let’s cook up a fictitious example piece where we can put layers to use. Using my awesome graphic design skills I’ve crafted up a logo template that will be the envy of design shops around the world.

For this piece there are four layers, shown in the layer dialog box here

If I was going to try and create this awesome logo in Microsoft Paint it would require that I first draw the background pieces and ensure that I worked from back to front. Hopefully I never would want to change how any of the background elements looked or were positioned because then I would have to start all over.

Using layers, the process of editing becomes much more flexible. If I waned to move the little raver dude in the logo I simply have to select that layer in the dialog box, and move it around. If I wanted to see how the logo looked without the raver dude, I would simply click on the visibility check box to temporarily remove him from the canvas.

The concept of drawing with layers has been around for quite some time. Any modern graphics editor comes with the feature and virtually the same set of functionality is expected by the end-user. I’ll be interested to see if the layer-based editing paradigm changes anytime soon and if there is a better way to work with raster-based editing software. What do you think? Is there a better way to organize and edit? Leave a comment below and if it’s something you’d like to see in PhotoMonkee I’ll be more than happy to bring it to life!

Dealing with no Image2d support in OpenCL

The Image2d type is not a guaranteed type because the underlying device must support it. Since I like to keep things as open as possible I opted to skip using Image2D in PhotoMonkee’s image filtering system and instead go with using int.

int?

Yeah, like 32 bits of colory goodness. Since Qt currently only supports 32 bit images there’s no need to deal with higher bit rates in the filter infrastructure. The tricky part (and maybe performance reducing part) is converting the integer into its component color parts so that we can modify it.

Let’s dig into an example to break things down. In this sample I’ll be showing you the kernel for image desaturation (i.e. converting to grayscale).

Passing image data to the kernel

As previously mentioned, PhotoMonkee uses Qt for holding image data. We use a combination of QPixmap and QImage, depending on the area. In this case, we’re using QImage for direct pixel access. The OpenCL memory buffer is populated with the contents inside of QImage::bits().

The Kernel

Because we’re working with 32bpp the kernel takes in int * as the source and destination buffer types.

__kernel void grayscale(__global int *srcImage,
                         __global int *destImage) {

In order to pick out the exact pixel we need from the buffer we simply need the GID which idexes directly to our source and destination pixel. With the GID in hand, we reach into the array and get back our int. One problem, we need RGBA components we can work with.

    int gid = get_global_id(0);
    int4 color = GetColorInt4(srcImage[gid]);

Enter: the bit shifter! 

This function, and its corresponding reversal function, will convert between the int and int4 data types.

__attribute__ ((always_inline)) int4 GetColorInt4(int srcColor) {

    int4 color;

    color.x = (srcColor >> 16) & 0xff;
    color.y = (srcColor >> 8) & 0xff;
    color.z = (srcColor & 0xff);
    color.w = (srcColor >> 24) & 0xff;

    return color;
}

__attribute__ ((always_inline)) int ColorToInt(int4 srcColor) {

    return ((srcColor.w & 0xff) << 24) |
            ((srcColor.x & 0xff) << 16) |
            ((srcColor.y & 0xff) << 8) |
            (srcColor.z & 0xff);
}

Why not convert from an int into a char4? Some image manipulation operations will blow past the upper bounds (255) or lower bounds(0) of the color range. By using an int we allow for that to occur. Note: it’s up to the kernel to make sure the value gets properly clamped before returning! 

Now that we’ve got our RGBA color components we can modify the values.

    int grayColor = 0.299f * color.x +
                    0.587f * color.y +
                    0.114f * color.z;

    grayColor = clamp((float)grayColor, 0.0f, 255.0f);

    color.x = grayColor;
    color.y = grayColor;
    color.z = grayColor;

Lastly, we convert back from int4 to int and then stash the result in the output buffer.

    destImage[gid] = ColorToInt(color);
}

I’ve done every filter in PhotoMonkee using this method for accessing image data. While I don’t have any performance comparisons to using Image2D I’m happy with the rate at which the filters execute on both GPU and CPU-only accelerated platforms. The only downside I’ve seen from using this methodology is that reading or writing to buffers outside of their range is BAD! It causes all sorts of strange things to happen the most severe of which is watching the GPU driver crash. Not cool.

In summary: I thought this was a pretty cleaver workaround to the problem spotty Image2D support. Do you have a solution that you have used in your implementations? I’d love to hear about it. Drop a comment below or feel free to shoot me an email: admin at this website.

Thanks for reading!

Enough Coding Already!

With the release of 0.56b I’m going to take a break from coding new features on PhotoMonkee and focus on the marketing/promotion side of things. I’d like to build up a base of “advocates” not for the financial aspect but rather to get more feedback on PhotoMonkee’s usability, features that it could use and of course, finding more bugs. I’ll continue to put out releases for bug fixes and if a rainy weekend comes along, maybe slip in a small feature or enhancement.

So what’s the plan for marketing? To be honest, I’m not sure. By day I work as a tools developer so creating online communities really isn’t my specialty. I’ve tried a Google adwords campaign, which definitely brought in some hits to the site but I didn’t receive much feedback. Everything I’ve read about “grass roots” marketing says that seeking out your users and engaging with them is the most effective way to create a community.

Here is my short list of “action items” (ug, I hate using managerial terms) that I’ll be going through to generate more awareness for PhotoMonkee:

  • Daily blog posts (sweet, I got today’s done!)
  • Seek out graphic artists/bloggers and ask them:
    • What their most used Photoshop feature/workflow is
    • If they would like to try PhotoMonkee
  • Create stuff with PhotoMonkee and submit it to sites like DeviantArt, Flickr or Imgur
  • Join blogging/graphics editing communities and answer as many questions as possible.
  • Join StackOverflow and answer Qt questions (not sure if this will drive users to PhotoMonkee but it wouldn’t hurt)
  • Start getting into photography. I’m not a photographer so learning some of the industry lingo and workflows would help.
As I mentioned before, Friday night is my “dedicated” evening during the week to work on PM community building. I’ll put up an update each Friday night (or Saturday) to update on the marketing type activities I did for the week. A little accountability never hurt!
Thanks for reading and happy trails to you!

Don’t forget to submit bugs and feature requests at our support site!

Creating a Ruler Widget in Qt

In the latest PhotoMonkee build I cooked up some rulers to serve as a handy reference point when editing items on the canvas. I’m pretty happy with how they turned out. The feature took a little longer than planned due to some struggles with how I wanted to handle zooming. In the end I took a shortcut (violated some OOP “rules”) to quickly bypass the issues I was hitting.

So what do the new rulers look like?

Well, like rulers! In the above picture you’ll see both a horizontal and vertical ruler extending along the edge of the window. A blue hash mark shows the current position of the cursor. I went with the “quarters” type of ruler whereby major hash marks are shown with three quarter hash marks are drawn in between each major.

Scrolling the canvas (when zoomed in far enough to allow for scrolling) will force a redraw of the ruler to update the coordinates as needed. In addition, zooming the canvas will also force an update to the rulers so that they can account for the new scaling that is required.

Future enhancements I’ve got planned for the rulers include:

  • Highlighting an area on the ruler when a selection is made via the marquee tool
  • Allowing the user to select the unit type used in the ruler
  • Allowing the user to turn the ruler on or off (it’s always on right now)
  • Creating guides by dragging them “out” of the rulers (not really a ruler feature but it’ll be involved)

The Design

As with any Qt widget, the ruler widget (PMRuler was the class name I used) will be based off of the QWidget class. Rather than break out the horizontal and vertical drawing logic into separate classes I just created an orientation enum and tossed some conditionals into the drawing routines.

Here is the header file for PMRuler

#ifndef PMRULER_H
#define PMRULER_H

#include <QWidget>
namespace Ui {class PMRuler;};

class PMRuler : public QWidget
{
    Q_OBJECT

public:
    enum Orientation {
        Horizontal,
        Vertical
    };

    PMRuler(PMRuler::Orientation orientation, QWidget *parent = 0);
    ~PMRuler();


    QSize sizeHint() const;
    QSize minimumSizeHint() const;
    void paintEvent(QPaintEvent* pEvent);
    void DrawHash(QPainter &painter, QLine &hashLine, int iHashType, int iMinorInterval);

    void ZoomUpdate();
private slots:
    void MousePosUpdate();

private:
    Ui::PMRuler *ui;
    PMRuler::Orientation m_Orientation;
    QSize                m_Size;
    QPoint               m_MousePos;   
    QTimer               *m_pTimer;
    QPixmap              m_CachePixmap;

};

#endif // PMRULER_H

What’s The Timer For?

Rather than have the ruler connect to another widget or have the parent window notify the ruler when the mouse moved I opted for polling the moue using QCursor::pos(). Right now I’ve got it set on a 50 millisecond polling interval.

Widget positioning

I found that by using the QGridLayout in the parent window allowed for easy positioning of the ruler widgets and the QScrollArea (which houses the canvas).

// Set the layout to make sure that the scroll area takes up the entire window's client area.
    QGridLayout *gridLayout = new QGridLayout();
    gridLayout->setSpacing(0);
    gridLayout->setMargin(0);

    QLabel *pLabel = new QLabel("px");
    pLabel->setBackgroundRole(QPalette::Window);
    pLabel->setStyleSheet("color: rgb(255, 255, 255);");
    pLabel->setAlignment(Qt::AlignCenter);
    pLabel->setFixedSize(24, 24);
   
    m_pHorizRuler = new PMRuler(PMRuler::Horizontal, this);
    m_pHorizRuler->show();     

    m_pVertRuler = new PMRuler(PMRuler::Vertical, this);
    m_pVertRuler->show();  

    gridLayout->addWidget(pLabel, 0, 0);
    gridLayout->addWidget(m_pHorizRuler, 0, 1);
    gridLayout->addWidget(m_pVertRuler, 1, 0);
    gridLayout->addWidget(m_ScrollArea, 1, 1); 

    this->setLayout(gridLayout);

Drawing the Ruler

First rule of drawing rulers: cache drawing the ruler as often as possible. Right now we’re drawing major hash marks, quarter hash marks and numbers on the major hash lines. If we add in eighth or sixteenth hash marks things could get a little more expensive. Even without the other hash types, drawing everything each time the mouse moves (to update the blue mouse position indicator) is a huge waste of resources. We only redraw the ruler to a QPixmap cache when the zoom factor is updated or a scroll bar is dragged.

The painting handler

void PMRuler::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    painter.drawPixmap(0, 0, m_CachePixmap);

    QLine mousePosLine;
   
    // Draw the blue hash mark for the current mouse position
    if(m_Orientation == Vertical)
        mousePosLine = QLine(0, m_MousePos.y(), 24, m_MousePos.y());               
    else
        mousePosLine = QLine(m_MousePos.x(), 0, m_MousePos.x(), 24);   
   
    painter.setPen(Qt::blue);
    painter.drawLine(mousePosLine);
   
}//end of PMRuler::paintEvent()

So what is the actual algorithm to draw the ruler? Well, I break it down into two passes: Drawing from 0 to end of the ruler and 0 to the start of the ruler. Each loop simply calls a function to perform drawing where it’s appropriate. The iMinorInterval variable determines the spacing, in real screen coordinates, for each hash marks. This is currently set to 25 pixels which means every 100 pixels we get a major hash mark. The iHashType variable is simply a counter. Inside DrawHash() we do a “ihashType % 4″ check to see if we’re on a major or minor hash.

        // Draw the hashes from canvas(0,0) to the end of the ruler
    for(int x = iStart; x < iEnd; x+= iMinorInterval) {                            

        DrawHash(painter, hashLine, iHashType, iMinorInterval);    
        iHashType++;
    }

The hashLine variable (a QLine object) is the current line we’re drawing. It’s a reference so DrawHash() will actually move the line to the next location for the next iteration (woops, did I just violate another OOP rule?)

Coordinate Conversion

During the initial implementation I tried to pass in the scale factor to the PMRuler object and have it convert from actual pixel coordinate space to canvas coordinate space. After a couple of nights of frustration I just punted. The ghetto hack? Have the PMRuler object ask its parent to convert a coordinate from actual pixel space to canvas coordinate space.

You see, when a horizontal PMRuler draws its first major hash mark it is at (100,0). If the canvas is currently set to 100% zoom then we are ALSO at (100,0) on the canvas. If the canvas is currently zoomed in to 110% then (100,0) is actually (110,0) on the canvas.

To perform the conversion I converted the PMRuler‘s local coordinates to global coordinates using mapToGlobal(). Then I take that global coordinate and map it to the QGraphicsView coordinate system using mapFromGlobal(). Lastly we go from widget space to canvas space by calling mapToScene().

Gotchas

Along the way I hit a couple of issues that took some time to resolve. The first was the failure to re-implement the sizeHint() and minimumSizeHint() functions in the PMRuler class. That means when Qt was trying to figure out the appropriate size for the rulers it would end up calling the default QWidget implementation. Who knows what that said the size should be…it definitely wasn’t right!

Readability of the code was also an issue that I took some time to address. Initially I had two methods in PMRuler to perform the drawing. One method was for drawing “forward” (zero to end of ruler) and the other was “backwards” (zero to the start of ruler). I’m glad I took the time to clean things up because while writing this feature. There are other sections of PhotoMonkee that have very messy code and I’m not looking forward to reacquainting myself with them :)

Conclusion

I’m pretty happy with how the control turned out. It serves as a great basis for some future enhancements and helps PhotoMonkee look a little more like a “real” image editing program. Granted, breaking away from the traditional mold of image editing wouldn’t be a bad thing.

If there are more features you’d like me to write about please drop a comment below or contact me directly: admin at photomonkee dot you know what! Until next time….stay thirsty my friends.

 

Going Free (for now)

After a couple of months of being available for sale it’s becoming obvious that I need to spend more time with my marketing hat on. We’ve had about 200 downloads of the PhotoMonkee trial directly from our website and 500 from external shareware sites. After all those downloads only one person pulled out his wallet and made the $8 purchase (Thanks Jim!).

Last week Robert Cooper (site) shot me a few messages on Twitter and suggested that until there is a rabid fanbase for PhotoMonkee, people will be reluctant to bust out the credit card to make a purchase. Obviously he’s on to something considering the dismal sell-through rate we’ve experienced.

Then there is the matter of other fantastic free editors available today. Paint.NET and GIMP stand out as the two leaders in that area. Until users see that PhotoMonkee presents an additional value above and beyond what the current free software provides, it’s a tough task to ask them to choose a for-pay product.

In that light, I’m making PhotoMonkee completely free of charge with no trial expiration or restrictions. You’ll get automatic updates and all the new features throughout the rest of the beta program. Even after we release 1.0 your beta copy will continue to be fully functional (you just won’t get updates from the 1.x series). The goal here is to remove any reservations you might have about taking PhotoMonkee for a test drive.

I still want to make PhotoMonkee a world-class photo editor and admittedly there’s still a ways to go. With the help of your input and testing I think the program stands a much better chance of becoming something great. Don’t get me wrong, I’d love to make a living by working solely on PhotoMonkee but I think we’re still a long way off from that stage. For now, I’m focused on making PhotoMonkee a kick-ass product.

Now…about that marketing hat. Just making PhotoMonkee free probably isn’t enough to magically attract eyeballs. This blog, our video channel and spreading the word via social media are all going to be venues I need to dedicate more attention to. Too often I get knee-deep in new feature development and neglect promotional tasks. Going forward, I am planning on spending Friday night’s* writing up blog content, connecting with graphic artists and creating PhotoMonkee videos. Not exactly a rock-star type Friday night but by setting aside one night for non-programming work I’ll start some type of buzz/community.

Viva Le Friday Night!

*Previously known as Game Night where I rack up head shots like they’re candy.

Brush System Screenshots

Crap. Did I say brushes would be done this week? I did, didn’t I? They’re almost done – I promise. There is just one last outstanding bug that I’m trying to squash (sometimes adding a new brush causes PhotoMonkee to crash) and also adding some last tweaks to the feature. In the meantime why don’t we go over the brush system as it stands right now.

In the toolbar for the brush tool (that’s one too many tools) there is a button which is labeled with the current brush shape. Clicking on that button will crack open the newly minted brush dialog box. Note: In the not to distant future I’ll implement a much smaller popup widget to save screen real estate.

The brush dialog contains a listing of the brushes in the current brush set. Akin to the Photoshop model, PhotoMonkee manages brushes as collections. You can add/remove brushes to your current set and if desired, export the current set as a different file. Each individual brush has its own settings for the following:

  • Spacing
  • Scatter (X & Y axis)
  • Size Jitter
  • Angle Jitter
  • Hue Saturation and Lightness Jitter
  • Opacity Jitter

So what do all these different brush settings do? I’m glad you asked! SCREEN SHOTS TO THE RESCUE! 

Spacing controls how much distance the brush must move before another stroke is drawn on the canvas. In this screenshot the top line has no spacing and the bottom line has 100% spacing. Since we’re using the default round brush the result is a series of dots that appear to be loosely connected.

Scattering simply randomizes where the brush will be drawn on the canvas for each stroke. Screenshots don’t really help illustrate this feature so we’ll skip that for this section.

Size Jitter allows PhotoMonkee to randomly change the size of the brush as you draw on the canvas. For each brush stroke PhotoMonkee will randomly change the size of the brush by the percentage amount you choose. If you choose 5% then the brush will be up to 5% smaller or 5% larger than the current setting.

Angle Jitter is useful for non-round brushes where you want the orientation of the brush to randomly change. I cooked up a triangle brush and set the jitter to 360 to illustrate this setting in action.

 

HSL Jittering randomly changes the hue, saturation and lightness of the current brush color. This setting uses OpenCL to randomly generate brushes and performs reasonably well even with larger brushes. The only “gotcha” with this setting is that if the current brush color is achromatic then no changes are made. I coded the randomization scheme to wrap in the event a chosen random value is outside the acceptable bounds for the component (i.e. greater than 360 for hue). So if your hue value is 350 and the random offset chosen is 40 then the new hue value will be 30.  (((350 + 40 = 390) – 360) = 30. This feature was probably one of the most interesting to code up and honestly the most gratifying to see in action. I need to cook up some more brushes to make better use of some of these brush settings.

 

Opacity Jittering, as you might have guessed, randomly changes the alpha component (or opacity) of the brush. I have no idea why you’d want to use this setting but it’s got to have some use out there. Surprise me!

 

What’s left?

For this release I’m leaving out the following items just to get something out the door and into users hands:

  • Integration of the brush system with other tools such as erase, smudge, sharpen and smooth.
  • A quick-brush selection popup when clicking on the toolbar icon instead of the full dialog box.
  • Adobe Brush file importing (I just need to find a good reference on the file format)

Before I ship the feature I’d like to have a real graphic artist come up with some quality default brushes to use. Right now mine consist of some pretty basic shapes that I’m sure most folks with be bored with very quickly.

As always your suggestions are greatly appreciated as well as your help in spreading the word about PhotoMonkee. Thanks for reading!

Zimventures is not a startup

If Zimventures was a startup I would be pretty discouraged by now. PhotoMonkee has been available to purchase for about a month and a half now and we’ve pulled in a whopping single purchase. If I was in a startup, we’d be seriously debating if PhotoMonkee was going to make it.

Luckily, I have a 9-5 job that pays the bills. Obviously that takes away from my time to work on PM but the upside is tremendous: I can focus on creating the best software possible. If ten more months pass and the sales still look miserable what have I lost? Nothing but my time and a few bucks for the logo design and the LLC formation. And in reality, the experience I’ve gained developing PhotoMonkee is something quite valuable.

So what does the lack of sales mean? There are two possible reasons that I can conjur up:

  • People have tried PhotoMonkee and think it’s crap
  • PhotoMonkee just needs more PR and word of mouth exposure.

My guess is that it’s a little bit of both. Calling PM crap is a bit harsh: it’s rough around the edges and still has room for improvement to compete with other low-end graphics editing packages. On the PR front I’ve only cooked up a few tutorials, tossed out some blog posts and threw a hundred bucks into a Google Adwords campaign that netted about 180 downloads of the trial.

So what’s a coder to do? 

Keep coding, of course! Since I’m not a startup I don’t have to worry about exit strategies, impatient investors or worrying if I’ll be able to make my mortgage payment next month. If I keep focused on creating a quality product and occasionally put on my marketing hat time will sort things out….hopefully.

 

Brush System

As I’ve said on twitter, work continues with PhotoMonkee’s brush system. The initial implementation was nothing more than a fancy line drawing mechanism. Every time you clicked and dragged the paint tool PhotoMonkee would draw a series of lines (using a circle) that would result in a relatively simple way to draw.

Big-boy paint programs have brushes with lots of cool knobs to change everything from spacing to randomizing the color the brush paints on the canvas. When I say “brushes” I’m actually talking about the shape of the thing that applies color to the canvas. Again, the old version would simply paint using a circle. The new system allows you to specify whatever shape you want, via a PNG file.

Brush Shapes

Within the PNG file you can define whatever shape you want for the brush. The image should be grey-scale for reasons I’ll talk about in a moment. It’s important to note that when the user wants to scale a brush (larger or smaller) PhotoMonkee will need to scale the image you provide. It’s best to make the brush as large as possible so when PhotoMonkee never needs to scale up and lose data.

As previously mentioned, brushes should be grey-scale. Pixels that are full black will drop down the full intensity of the current brushes color. As the brush pixel source color moves from black to white less and less of the original source color will be applied.

Brush Parameters

Just painting various shapes is only half the fun! Each brush will be able to have the following parameters tweaked:

  • Spacing: How far apart each paint operation should occur
  • Scatter (X & Y): Randomly jitter where each paint operation is placed
  • Hue Jitter: Randomly change the hue of the source color
  • Saturation Jitter: Randomly change the saturation of the source color
  • Lightness Jitter: Randomly change the lightness of the source color
  • Opacity Jitter: Randomly change how opaque each paint operation is
  • Angle Jitter: Randomly change the orientation for each paint operation
  • Size Jitter: How big each paint operation should be, as a percentage of the original

I’ve got a few more knobs in store for later but those should be enough to get started with.

I’ve done some poking around on the Intertubes to try and get a reference for the Photoshop brush file format but I haven’t found any definitive guides yet. It’s on the bucket list but for now it’ll have to wait.

Right now the actual brush functionality works however building the UI for managing brushes is proving to be more time consuming than I had hoped.

Viva Le Brushes!

Cubicle Denizens: Don’t fork() your heath monitor and ignore the process return value.

I’ve been working in software for twelve years. That puts me at the ripe old age of 34 (note the sarcasm there, ladies and gents). Last week I had a heart attack. Yeah, the “oh shit, what the hell is that pain in my chest and arm?” kind of heart attack. Thankfully, through the wonders of modern medicine, I’m recovering with a little piece of stainless steel in an artery and am on the way to a full recovery (knocks on kitchen table). It turns out, one of my arteries that fed my heart with blood was 95% blocked.

Alright, I can hear the skepticism now. “Sure, but you’re probably massively overweight, smoking and throwing back a case of Mountain Dew every day”. Negative, Ghost Rider. I’m 5’10, 190 pounds and moderately active. Sure, I could stand to shed a few pounds but I hardly qualify to be on The Biggest Loser.

I’m moderately active during the non-winter months with a pretty hefty golf addiction. I practice four times a week and play two or more times a week, always walking the full round. The winter months, however, involve nothing more than lots of gaming and the occasional day trip to go skiing.

Over on the eating side I’ll pretty much eat anything but am fairly balanced Monday – Friday. Every day starts with a bowl of cereal and milk. I drink coffee (way too much) once I’m in the office, usually three cups (yeah, way too much). Lunch is either left-overs from our family dinner or a sandwich, some chips and piece of fruit. Dinner is where I usually go a bit overboard, especially with portion size. About every other night I’ll have a drink or two (ok, sometimes three) of anything from wine to scotch and any mixed drink in between.

So my exercise and eating wasn’t horrible but it wasn’t good either. Cholesterol levels read by the cardiologist after my procedure were suggestive that I should have changed my diet and exercise but nothing to the extreme that I’d have a severe blockage.

Going forward I’ll be getting at least 30 minutes of cardiovascular exercise and interrogating the nutrition label of anything that plans on venturing through my digestive system. I’ve already signed up for an account over on MyFitnessPal and started using my Android phone to scan the UPC code of everything I eat except for those fresh fruits and veggies, of course.

Given the statistics, I’m an edge case. The kind of bug that you look back at and go, “Oh yeah, that makes sense now.” but you never saw it coming. That still doesn’t mean I shouldn’t share my story with the rest of the coder community in the hopes that it might serve as a warning for you to fix before your compiler throws an error. Have your doctor double check your diet and exercise syntax to make sure you’re not skipping over a potentially unhanded exception. Who knew code reviews could be life saving?

Be well!

3rd Party Software: How $#it Gets Done!

In case you weren’t aware, PhotoMonkee is a one man coding effort right now (which reminds me…why do I say “we” all the time when I blog?). One of the biggest challenges for me is to appropriately categorize tasks to do in the small windows of time that present themselves.

As of right now most of the features in the program are random ideas I come up with when either using the software or during a “what’s something cool I can code” brainstorming sessions. Some features are small enough they can be cranked out in under an hour. Other features are projects unto themselves. It’s those features, regardless of how much fun they’d be to work on, that require seeking out a pre-existing solution.

For example, back in January I wasn’t sure how to handle, or even to have, licensing. I didn’t want to leave the program completely license free but coding up my own cross-platform licensing technology would require servers, encryption and other time consuming areas that I have no expertise on. After a little searching I stumbled across a small company that offered both a licensing AND an auto-updater. In a single weekend I had both technologies integrated and I didn’t need to pull an all-nighter either!

The big example of 3rd party awesomeness is the Qt framework. PhotoMonkee uses a lot of the drawing libraries within Qt and probably saved months of coding time. In addition, once I get around to setting up a Mac and Linux box, PhotoMonkee should compile on those platforms relatively easily thanks to Qt’s cross-platform nature.

On the customer-facing side of “the business” technologies such as Google Adwords, Twitter, WordPress and Uservoice allow me to interact with potential customers and offer them support with little to no capital expenditures. For the store and sales side I partnered with FastSpring. They actually integrated (seamlessly) with my licensing provider and required absolutely no capital to setup or maintain my account. They take a percentage of each transaction and make monthly transfers into my checking account as sales are made. The only “coding” I had to do in this area was some PHP for the static elements of photomonkee.com.

I’d also be a total jerk if I didn’t mention the wonderful art assets used for PhotoMonkee’s icons. I’m far from a competent artist so when it comes to art assets I immediately punt to someone or somewhere else.

So in 7 months I prototyped a fully functional image editor with licensing and a sales channel. That’s pretty impressive considering all that was done while holding down a 9-5 and not completely neglecting my wife and kids.

Viva 3rd Party!