Generate SFTP Checker

Batch file to generate batch files to check for missing files on an SFTP server.

Needed a simple solution to repeatedly check an external SFTP server for a missing file to become available. This is a regularly occuring problem for me with different files/servers each time. This batch file asks for server name, username, password, etc, and then writes a customized “WaitFor_%filename%.bat” file to run, along with a helper file “WaitFor_%filename%_FTPCommands.txt” to store the FTP commands. The FTP commands are ran through psftp.exe. When the file is found and downloaded, a big red command-prompt popup will be made to get your attention.


  1. Download and install PuTTY
  2. Ensure psftp.exe from the PuTTY install is in your PATH
  3. Run the batch file, answer the questions
  4. Run the generated batch file customized to your answers to begin waiting. Be responsible with your passwords!




REM GenerateSFTPChecker.bat
REM Kristofer Christakos
REM Batch file to generate batch files to check for missing files on an SFTP server.
REM License: Modify as desired.

@echo off
set /P servername="Enter the SFTP server name: "
set /P username="Enter the username: "
set /P password="Enter the password: "
set /P directory="Enter the directory of the file to wait for (or leave blank for default directory): "
set /P filename="Enter the filename to wait for: "
set /P seconds="Enter how often you want to check (in number of seconds): "

set batchname="WaitFor_%filename%.bat"
set helpbatchname="WaitFor_%filename%_FTPCommands.txt"

IF EXIST %batchname% del %batchname%
IF EXIST %batchname% echo Error clearing %batchname%&pause
echo @echo off
echo :loop
echo psftp %username%@%servername% -pw %password% -b %helpbatchname%
echo IF NOT EXIST %filename% GOTO :sleep
echo start "Available File!" cmd /c "color C0&date /T&time /T&echo File %filename% is downloaded.&pause"
echo exit
echo :sleep
echo timeout /t %seconds%
echo goto :loop)>>%batchname%

IF EXIST %helpbatchname% del %helpbatchname%
IF EXIST %helpbatchname% echo Error clearing %helpbatchname%&pause
IF DEFINED directory echo cd %directory%>>%batchname%&timeout /t 1 /nobreak>nul
echo get %filename%>>%helpbatchname%

echo Done.


Tracks remote disconnections by parsing and recording output from Microsoft’s ping utility.


Call pingtest(target_name, ping_count) to run the command “ping target_name -n ping_count“. Then pingtest() will return a list of times for each ping_count pings.

  • time == -1 is error
  • time == 0 is when ping <1ms
  • time >= 1 is the time in milliseconds

This was written to test various servers for network connectivity, continously, and discover if any disconnections occured while away. The times were logged with a little formatting to a TSV file to be sorted and check for any -1 time values (disconnections). An example of this is in Example output below, pinging each target twice:

2017-10-12 19:39:00.817122     2       2
2017-10-12 19:39:01.849578      14      14
2017-10-12 19:39:02.910976    -1      -1
2017-10-12 19:39:11.848790  153     160
2017-10-12 19:39:13.035685     1       1
2017-10-12 19:39:14.067242      14      12
2017-10-12 19:39:15.108837    -1      -1
2017-10-12 19:39:23.848390  150     148
2017-10-12 19:39:25.010907     1       1
2017-10-12 19:39:26.035119      13      16



'''Contains pingtest(), to run Microsoft's ping utility and parse output.
Tracks remote disconnections by parsing and recording output from Microsoft's ping utility.

Kristofer Christakos 2017

import subprocess    #For running Microsoft's ping utility in pingtest()
import datetime        #For outputting time in log file, not needed in pingtest()
import sys             #For the tests only, not needed in pingtest()

def pingtest(target_name, ping_count):
    '''Runs "ping target_name -n ping_count" and parses output as list of times.
    Time -1 is error, 0 is when ping <1ms, and time >=1 is in milliseconds
    process ="ping " + target_name + " -n " + str(ping_count), stdout=subprocess.PIPE)
    result = process.stdout.decode("utf-8").splitlines()
    times = []
    for line in result[2: 2 + ping_count]:
        time_index = line.find("time")
        if (time_index == -1): 
            times.append(-1)    #Request timed out.
        time_index += 4
        space_index = line.find(" ", time_index)
        if (space_index == -1):
            times.append(-1)    #Error
        if (line[time_index] == '='): time_index += 1
        time_str = line[time_index:space_index]
        if (time_str == "<1ms"): times.append(0)
            time = time_str[0:-2]
    return times

def get_timestamp():
    return str(

def join_ints(int_list, separator):
    '''Inputs list of ints and joins them to a string.
       Example input:    [1, 2, 3, 4], '\t'
       Example output:   "1\t2\t3\t4"
    return separator.join([str(n) for n in int_list])

def pingtest_and_write(server, file_handle=None, yes_print=True):
    '''Perform pingtest, then do custom formatting and write to log and print.'''
    timestamp = get_timestamp()
    times = pingtest(server, 2)
    writestr = timestamp + '\t' + server + '\t' + join_ints(times, '\t') + '\n'
    if yes_print: print(writestr, end='')
    if (file_handle != None): file_handle.write(writestr)

### Run some tests using the above functions ###

f = None
if (len(sys.argv) == 2):
        f = open(sys.argv[1], "a")
        print("Could not open file to log to.");
    print("Enter a single parameter to store log file. Currently not logging.")

    pingtest_and_write("", f)
    pingtest_and_write("", f)
    pingtest_and_write("", f)
    pingtest_and_write("", f) #GreenTeamDNS 2


Memory Warden

Click here to jump to the latest download below.


Memory Warden monitors your system memory usage (% RAM). When usage gets too high, this program can alert you and optionally close programs to prevent computer lockup, even when your mouse cursor is not responding.

This program was written for people without the time or technical expertise to investigate why their computer is slowing down (such as busy stock traders). To accommodate all levels of urgency and autonomy, there are four different actions that may be set at any percent level:


(1) quiet background warning
A passive warning that will not interrupt whatever you are doing.

(2) alert with pop-up warning
An aggressive warning that will pop-up over any windows you have open.

(3) end memory hogs from kill list
Will automatically close programs, but only those from a list that you build.

(4) end any memory hogging program
Will automatically close any program.

To prevent a program from being automatically closed, add it to your Safe List in Advanced Settings.

Suggested Use

Create warnings (using actions 1 & 2 above) for when your memory begins getting high (70% to 85%). This will give yourself a chance to gracefully close programs. The warnings will tell you who the memory hogs are.

When system memory usage reaches 95% or higher, have Memory Warden automatically end the memory hogs in case your computer begins locking up (using actions 3 & 4 above).

Using the Kill List

Some users will want Memory Warden to automatically close specific programs before others. You can do this with the preferred kill list in Advanced Settings. For example, add Chrome, Internet Explorer, and Firefox to this list. Then use action “(3) end memory hogs from kill list”.


Memory Warden is installed for all users or the current user with an MSI file. Download the latest version below.

Old versions will be uninstalled by new versions automatically.

Prerequisites: Microsoft .NET Framework version 4.5.2.

If Memory Warden fails to run because this is not installed, download and install the framework from Microsoft’s website here:

License and Source Code

Please read the EULA before installing: MemoryWardenLicense.rtf

Program written in C# with WPF and WiX for the installer. Up-to-date source code is currently not public. Feel free to message me with questions or comments at or

Latest Version

Memory Warden v1.3 download (624 KB): MemoryWarden-v1.3.0.msi

Released: 2017-10-12

Change Log:

  • New window to view current usage and processes — access by left clicking or right clicking the tray icon
  • Counts per-process full working set memory instead of private working set memory (improvement over Task Manager) — results in more accurate detection of memory hogs
  • UI: settings window now remains on top, so it is unlikely to unintentionally leave it open and miss warnings
  • Bug fix: all old logs were deleted, now logs are deleted only if older than 30 days
  • Bug fix: Windows shortcut alt+tab would bring up an inactive settings window
  • Bug fix: duplicate instances running on startup

Old Versions

Memory Warden v1.2.1 download (624 KB): MemoryWarden-v1.2.1.msi

Released: 2017-10-02

Change Log:

  • Smart all-user vs current-user automatic startup
  • Added versioning to user settings
  • Removed redundant error messages
  • Fully revamped installer
  • Support for easy upgrades in future
  • Bug fixes

Memory Warden v1.1 download (1.45 MB): MemoryWarden-v1.1.0.0-x86.msi

Released: 2017-09-27

Change Log:

  • Default install directory & registry path changes
  • Fix refreshing RAM when hovering over tray icon
  • Disable Cancel button if program wasn’t running
  • Upper right X button now minimizes to tray

Memory Warden v1.0 download (1.45 MB): MemoryWarden-v1.0.0.0-x86.msi

Released: 2017-09-24

Auto Clicker for Clicker Heroes


Clicks over and over again while playing Clicker Heroes in Chrome.

Safety features:

  • Caps Lock must be toggled on
  • Active window title must contain “Clicker Heroes” and “Google Chrome”

Prevent resource hogging:

  • Only checks for Caps Lock once per second.


'''Clicks over and over again while playing Clicker Heroes in Chrome.
Safety features:
Caps Lock must be toggled on
Active window title must contain "Clicker Heroes" and "Google Chrome"
Prevent resource hogging:
Only checks for Caps Lock once per second

import win32api, win32con, win32gui
#python -m pip install pypiwin32
import time

while True:
    capsLockOn = win32api.GetKeyState(win32con.VK_CAPITAL)
    if (capsLockOn == 1):
        topWinText = win32gui.GetWindowText(win32gui.GetForegroundWindow())
        if (("Clicker Heroes" in topWinText) and 
            ("Google Chrome" in topWinText)):
            win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0, 0, 0)
            win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0, 0, 0)



Download Executable Version (no Python needed)

License: MIT License: software as is, no warranty, and this license must always be included with this software:


Build Info

Written in Python 3. Uses pypiwin32, so install “python -m pip install pypiwin32“.

To create the executable, I wrote a py2exe setup script. For more information on this technique, see How to Convert Python Scripts to Executables.


The Python script runs in a loop, so you can simply download and double click the .py file, or run it from command prompt using:


The executable can be ran without Python installed.

After opening the program, you will see a blank prompt. Then:

  1. Navigate to your Google Chrome window with Clicker Heroes open.
  2. Point your mouse where you want to click a lot.
  3. Turn on Caps Lock.

If you turn off Caps Lock, or the cursor is moved and it clicks off the browser window, then the script will stop clicking.


Use at your own risk. If the script is against Clicker Heroes’ policy, then don’t use it. Also, don’t run any auto clicker program while you have important documents open or buttons that you shouldn’t click. The safety feature takes one bad click to activate. Feel free to modify the code however you’d like for yourself.

PropReports Assistant


Creates links for visiting PropReports pages, one month at a time.

This tool makes viewing monthly reports easier by building the links for each month instead of having to manually chose the start and end dates for each month on the website.


  1. Sign into PropReports and copy-paste the URL into the program. This tells the program what the links should look like.
  2. Fill in the date range of when you would like monthly reports, as well as your report type settings.
  3. Press the Generate Links button to see a list of links for monthly reports. Click on the links.


No installation required. PropReports Assistant is a stand-alone executable. You may have to update your .NET runtime assemblies. If so, run Windows Updates, or let me know.


Program written in C# with .NET and WPF.


If PropReports modifies their website, the generated links may not work anymore. If so, let me know and I’ll release a fixed version.



Release Date: 2017-05-01
Initial release.

Download Program: PropReportsAssistant.exe
Source Code:

How to Use Markdown

What is Markdown?

Markdown is a text document syntax that is easy to read in plain text form, but can be converted to HTML. I use it for writing notes and documents such as this one, where I want to be able to read the source but easily view and format with HTML too.

The purpose of this document is to provide a reference to getting started with markdown, how to view markdown in a web browser, and a limited cheatsheet for myself. The cheatsheet is not comprehensive.

The purpose of markdown, as stated by markdown’s original author:

Markdown’s syntax is intended for one purpose: to be used as a format for writing for the web.

John Gruber,

Example Markdown File

Plain text form while writing:

# Vacation Planning Notes

## Saturday

![Sunday Weather](weather.png)

1. Visit river in morning
2. [Mom's restaurant for lunch](
3. Dinner TODO

## Sunday

TODO: Need to talk to Jason.

Saved as “”

Rendered as HTML in browser:

How to Write Markdown

Markdown may be written in any plain text editor such as Notepad. Simply save the file as *.md

I like to use Notepad++ with Edditoria’s markdown_npp language xml file imported. While the language import is not needed, it gives MD files a little syntax coloring that I like. Downloading and importing the language file is very straightforward in the Usage of the project readme. Project link:

Markdown to HTML

Quick Rendering

This is where markdown gets really useful for personal documents.

For quick rendering, I use the Google Chrome extension Markdown Preview Plus. Using this or a similar extension, you can open MD files in Chrome and see the markdown auto converted to HTML and the page rendered for you. I recommend turning on the auto-refresh feature in the extension settings so you can modify an MD file and see the changes update almost immediately.

Now you can use MD files for taking quick yet nicely-formatted notes. For example, you may keep a notebook folder with MD files. The MD files default open in Chrome upon clicking; allowing you to see the rendered HTML. If you want to edit your notes instead, simply right click and open in Notepad++ rather than Chrome. Using this approach, you can quickly create and view documents containing images and links without having to use a word processor at all.

Python Rendering

First install python’s markdown package (available for Python 2 and 3). Download from or run:

python -m pip install markdown

Then in the folder containing your markdown file, run:

python -m markdown > outputname.html


Markdown to HTML converters are intended to simply replace MD syntax with semantically meaningful HTML tags, as per the original specifications. You can then add your own CSS styling for the tags in outputname.html if desired.



Double line break (\n\n) after first line

Inserts a new <p> block. Renders like this:

Line 1

Line 2

Single line break (\n) after first line

Uses the same <p> block. Renders like this:

Line 1 Line 2

Two spaces and single line break ( \n) after first line

Uses the same <p> block and inserts a break <br>. Renders like this:

Line 1
Line 2


  • <>
  • <>
  • [link text](
  • [link text]( "title")
  • [link text][idtag]
    with anywhere in document:
    [idtag]: "title"
  • [link text][]
    with anywhere in document:
    [link text]: "title"


Same syntax as links, both inline and reference styles with title support, except use an ! prepended. Example:

![img alt text](/images/something.png "title")

As with links, relative paths may be used for the URI, or a full path with protocol such as As with links, reference tags may be used. The reference definition does not need ! too.


Note for below: Some MD to HTML converters will add additional <span> tags in the <code></code> span for nice language-specific styling.

Pre-Formatted Blocks

Indented lines convert to <pre><code></code></pre> code blocks.

The source code to my constructor is:

    string message = "Hello world!";
    this.count = 0;

The source code to my constructor is:

string message = "Hello world!";
this.count = 0;

Not-Formatted Inline Spans

Enclosing backticks convert to <code></code> inline code spans.


Then use the `printf()` function.


Then use the printf() function.

More Not-Formatted Inline Spans

Some MD to HTML converters will add extra styling if code is enclosed in three backticks. These converters will optionally accept the language on the first line.

my_list = ["toothbrush", "pen", "charger"]
for (item in my_list):

python my_list = ["toothbrush", "pen", "charger"] for (item in my_list): print(item)

Text Styling

  • *italics*
  • **bold**
  • <u>underline</u>;
  • <s>strikethrough</s>

Literal Characters

Used when writing literal HTML, outside of a code block, that shouldn’t be recognized by markdown.

  • &lt; <
  • &amp; &
  • %20 for spaces in a link
  • &nbsp; for multiple spaces in text

Backslash Support

Backslash for escaping chars:

\ backslash
` backtick
* asterisk
_ underscore
{} curly braces
[] square brackets
() parentheses
# hash mark
+ plus sign
– minus sign (hyphen)
. dot
! exclamation mark

Horizontal Rule

3 or more hyphens/asterisks/underscores with optional spaces produce a horizontal rule tag <hr>. Example inputs:

  • ———————————————-
  • * * *
  • ___

Block Quotes

Prepend > to every line of a quote to wrap it in <blockquote> tags.


How to Convert Python Scripts to Executables

Here you will learn how to convert your Python programs into executables. This is a great option for deploying your scripts to people who do not have Python installed, or who have a different version of Python and/or required modules.

You will need to use command prompt for this tutorial. If you are used to writing and running your Python code in an IDE, I highly suggest you spend a little time learning to run your script from command prompt.

1. Write your Python program

If your program is written in Python 2, or Python 3.4 or less, then you’ve got nothing to worry about. Skip ahead to the next section.

At the time of this writing, py2exe does not support Python 3.5 and 3.6. If you’re using Python 3.5 or 3.6, I suggest doing what I did:

  1. Install Python 3.4 to C:\Python34, and do not add this Python to PATH during the installation options.
  2. Attempt to run your program in command prompt, but call “C:\Python34\python” instead of simply “python“. This is important because calling “python” will default to whichever “python.exe” is found in PATH, which will be your main installation. You want to temporarily use the version 3.4 installation to make your executable.
  3. If you are missing modules, install them without calling your default Python installation too. For example, if you need to install pandas, instead of running:
    pip install pandas

    Run pip from your Python 3.4 version like so:

    C:\Python34\python -m pip install pandas

2. Install py2exe

Run in command prompt:

python -m pip install py2exe

Or specify “C:\Python34\python” if you had to do that above.

3. Write your setup script

Now you’re going to write a Python script that uses the py2exe module to read your .py files and convert them into executables. Save it in the same folder as your program’s .py files. The most basic setup script looks like this:

from distutils.core import setup
import py2exe


To run this script, you must pass the parameter “py2exe”. So in command prompt:

python py2exe

The above script will use py2exe to convert a console based “” program into a new executable “helloworld.exe”. If you wanted to create multiple executables at once that are meant to be deployed together and share similar dependencies, you may list more file names:

setup(console=['', ''])

By default, a folder called “dist” will be made, and your .exe(s) will be in there with a lot of dependency files. The dependencies are copies of files from all the Python installation packages and modules you are implicitly using in your script. Some of the common dependencies will be bundled into a file called “” too. Also by default, your executable will still depend on having Python installed. To bundle everything into the executables and a single zip file of dependencies, add the option:


To change the name of “”, use the zipfile parameter:


Saving common dependencies in a zip file makes sense for deploying multiple executables. If you only have one executable or really want to bundle everything into a single .exe, simply set the zipfile name to None. Therefore the following script will completely convert to helloworld.exe, with no external depencies or Python installation needed for the user:

from distutils.core import setup
import py2exe


Additional Resources

If you want to make executables of GUI-based scripts or exclude unnecessary dependencies, explore the py2exe options in more detail at:

py2exe List of Options

The py2exe tutorial is also a good source for your first setup script:

Startup Automation


Startup Automation is a library of Python 3 functions used for common automation and window repositioning tasks.

For example, I like to keep a bandwidth monitor running in the top corner of my screen whenever I turn on my computer. I wrote a Python script to run on startup that uses to automatically open and move the window.

Also included with StartupAutomation:

  • is a tool to give the screen coordinates at wherever the mouse cursor is placed.
  • is a tool to give the name, position, and size of whichever window the mouse cursor is moved over.

Example Startup Script

import StartupAutomation as sa
import time

# start the desired program
process_handle = sa.run_program("C:\\SomeProgram.exe")

# get the window handles for the program
window_list = sa.get_process_window_handles(process_handle)

# reposition the window where I want it, at (1590, 0)
# (I know the program only has only one window, and one window handle)
sa.set_window_coords(window_list[0], 1590, 0)

Build Notes

  • For Microsoft Windows only
  • Written in Python 3
  • Must install the pypiwin32 module first:
python -m pip install pypiwin32



Process Related Functions

    Creates a new process with a new console window.

    Returns the handle to the process.

    Attempts to retrieve the executable path of the given process.

    Parameter process_handle must have been created with the PROCESS_QUERY_INFORMATION or at least PROCESS_QUERY_LIMITED_INFORMATION access right. This is automatically true for handles returned by run_program(). Returns an empty string "" on failure.

    Gets the PID of the process owning the given window.

    Attempts to retrieve the executable path of the process owning the given window.

Window Related Functions

    Returns a list of all window handles for all processes.

    Returns a list of all window handles for a single process.

    process_handle can be retrieved and saved from run_program()

    Returns the window handle for the console window associated with this 

    Returns the window handle for the window with the given title.

get_window_handle_multiple_tries(window_name, seconds_to_wait, number_of_attempts)
    Tries get_window_handle() multiple times, with a time delay between attempts.

    Returns the title of the window with the given window handle.

    Retrieves the coordinates of the window with the given handle.

    Coordinates returned in the 4-tuple: (left, top, right, bottom)

set_window_coords(window_handle, left, top, right=0, bottom=0)
    Repositions a window to new coordinates.

    If the right and bottom coordinates are ignored, the window size is 

set_window_size(window_handle, width, height)
    Resizes a window without repositioning.

    Sets the foreground window to the window of the given handle.

    Retrieves the window handle of the foreground window.

    Confirms the given window is the foreground window.

get_parent_window_at_coordinates(x, y)
    Returns the handle of the parent window at (x,y) screen coordinates.

get_child_window_at_coordinates(x, y)
    Returns the handle of the first child window at (x,y) screen coordinates.

    Returns None if no child window contains the coordinates.

get_window_tree_at_coordinates(x, y)
    Returns a list of window handles at (x,y) screen coordinates.

    The first handle in the list is the parent window. The other handles 
    are the first child window of the previous handle that contains the 
    coordinates. These are iteratively found with 
    get_child_window_at_coordinates(x, y).

Keyboard Related Functions

    Virtually types the text string.

    Attempts typing capital letters and special character keys.

type_string_safely(text, foreground_window_handle)
    Verifies the foreground window before every virtual keypress.

    Presses the print screen key.

    Presses the return key. Same as press_enter().

    Presses the enter key. Same as press_return().

    Verifies the foreground window before pressing the enter key.

    Presses the given virtual key down and up with no delay.

    Use type_string() instead if possible.

    Determines if caps lock is pressed, returning True or False.

Cursor Related Functions

    Retrieves the cursor screen coordinates (x,y).

set_cursor(x, y)
    Moves the cursor to screen coordinates (x,y).

    Simulates a mouse left-click with no delay.




Please feel free to contribute to this library on Github:

If you find this library useful, I’d like to hear about it too.


Release Date: 2017-05-07
Latest release. See readme for details.

Source Code:, source.tar.gz



BMPtoHTML.exe converts a BMP image to an HTML table of colored cells.

I’ll admit, this program is just for academic purposes and has no real value. The idea behind it is to display an image on a website using pure HTML instead of an image file. It could hypothetically be used by those websites that try to block a user’s right-click menu via JavaScript, but in reality we all have a print screen button anyways for saving any picture we see.


BMPtoHTML.exe [input_bmp_filename] [output_html_filename]

The output HTML file contains a <table> of cells, each with a width and height of 1×1 pixels. Each <td> in the table is given a background color to recreate the BMP image.

Note not all BMP files are supported. Because this program is a proof of concept, I didn’t spend time supporting compression, different bit depths, etc.


Input BMP: 49 KB
Output HTML: 466 KB

Example 1 Output HTML

Input BMP: 572 KB
Output HTML: 5519 KB (over 5 MB!)

Example 2 Output HTML <– Huge file!

The browser also takes a noticeable number of seconds to render the HTML. The large increase in file size, long rendering time, and complete abuse of HTML tables likely makes the downsides of using this technique outweigh any upsides. It’s amusing to see it work though.


BMPtoHTML.cpp, written in C++, a single cpp file.

Converts a BMP image to an HTML table of colored cells.
Each cell is 1 pixel in width and height.

#include <iostream>
#include <fstream>
#include <Windows.h>
#include <string>

using namespace std;

int main(int argc, char* argv[])
    if (argc != 3) {
        cout << "Converts a BMP image to an HTML table of colored cells." << endl << endl;
        cout << "BMPtoHTML.exe [input_bmp_filename] [output_html_filename]" << endl;
        return 0;
    string bmpFileName = argv[1];
    string htmlFileName = argv[2];

    //Open input BMP file
    fstream bmpFile;, fstream::in | fstream::binary);
    if (!bmpFile.is_open()) {
        cout << "Error opening input BMP file " << bmpFileName << endl;
        return -1;

    //Read BMP file header
    BITMAPFILEHEADER bFileHeader;*)&bFileHeader, sizeof(bFileHeader));
    if ((bFileHeader.bfType != 0x4D42) &&//BM
        (bFileHeader.bfType != 0x4142) &&//BA
        (bFileHeader.bfType != 0x4943) &&//CI
        (bFileHeader.bfType != 0x5043) &&//CP
        (bFileHeader.bfType != 0x4349) &&//IC
        (bFileHeader.bfType != 0x5450)) {//PT
        cout << "Can't read this BMP file." << endl;
        cout << "bfType: " << bFileHeader.bfType << endl;
        return -1;

    //Read size of info header to determine which struct to use
    unsigned int headerSize;*)&headerSize, 4);
    bmpFile.seekg((int)bmpFile.tellg() - 4);

    memset(&bHeader, 0, sizeof(bHeader));
    if (headerSize == 12) {*)&bHeader, 12);
    else if (headerSize == 40) {*)&bHeader, 40);
        memcpy(&bHeader, &bHeader, 12);
    else if (headerSize == 108) {
        BITMAPV4HEADER bHeaderExt;*)&bHeaderExt, 108);
        memcpy(&bHeader, &bHeaderExt, 40);
    else if (headerSize == 124) {
        BITMAPV5HEADER bHeaderExt;*)&bHeaderExt, 124);
        memcpy(&bHeader, &bHeaderExt, 40);
    else {
        cout << "Header unsupported. Length " << headerSize << endl;
        return -1;

    //Check for unsupported features
    if (bHeader.biPlanes != 1) {
        cout << "Unsupported number of planes ("<< bHeader.biPlanes << ")" << endl;
        return -1;
    if (bHeader.biBitCount != 24) {
        cout << "Unsupported number of bits per pixel (" << bHeader.biBitCount << ")" << endl;
        return -1;
    if (bHeader.biCompression != BI_RGB) {//BI_RGB means uncompressed
        cout << "Compressed image formats not supported." << endl;
        return -1;

    //Rows are rounded to 4 bytes
    //Calculate how many bytes to jump at the end of a row
    unsigned int requiredRowBytes = bHeader.biWidth * 3;
    int paddedBytes = (4 - (requiredRowBytes % 4)) % 4;
    unsigned int actualRowBytes = requiredRowBytes + paddedBytes;

    //Read the pixel data and close the BMP file
    unsigned int bytesToRead = actualRowBytes * bHeader.biHeight;
    char* pixelData = new char[bytesToRead];
    bmpFile.seekg(bFileHeader.bfOffBits);, bytesToRead);

    //Open output HTML file
    fstream htmlFile;, fstream::out | fstream::trunc);
    if (!htmlFile.is_open()) {
        cout << "Error opening output HTML file " << htmlFileName << endl;
        return -1;

    //Write the HTML file and parse the colors simultaneously
    char htmlTableStart[] = "<html>\n<head>\n<style type=\"text/css\">\ntd\
    {\n    height:1px;\n    width:1px;\n}\n</style>\n</head>\n<body>\n<tab\
    le border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n";
    htmlFile.write(htmlTableStart, strlen(htmlTableStart));
    for (int row = 0; row < bHeader.biHeight; ++row) {
        char htmlRowStart[] = "<tr>\n";
        htmlFile.write(htmlRowStart, strlen(htmlRowStart));
        unsigned int rowOffset = (bHeader.biHeight - row - 1) * actualRowBytes;
        for (int col = 0; col < bHeader.biWidth; ++col) {
            char htmlCellStart[] = "<td bgcolor=\"#";
            htmlFile.write(htmlCellStart, strlen(htmlCellStart));
            unsigned int colOffset = col * 3;
            //Read 3 bytes for BGR and write their RGB hex string
            for (int z = 2; z >= 0; --z) {
                int color = 0;//must be int for _itoa_s()
                ((char*)&color)[0] = pixelData[rowOffset + colOffset + z];
                char hexcode[3];
                memset(hexcode, 0, sizeof(hexcode));
                _itoa_s(color, hexcode, sizeof(hexcode), 16);
                //if hexcode is 1 char long, need to write a 0 too
                if (hexcode[1] == 0) {
                    hexcode[1] = hexcode[0];
                    hexcode[0] = '0';
                htmlFile.write(hexcode, 2);
            char htmlCellEnd[] = "\"></td>\n";
            htmlFile.write(htmlCellEnd, strlen(htmlCellEnd));
        char htmlRowEnd[] = "</tr>\n";
        htmlFile.write(htmlRowEnd, strlen(htmlRowEnd));
    delete[] pixelData;
    char htmlTableEnd[] = "</table>\n</body>\n</html>\n";
    htmlFile.write(htmlTableEnd, strlen(htmlTableEnd));

    return 0;


Download BMPtoHTML.cpp

Download BMPtoHTML.exe