I really struggled to find a good example for this. An MSDN example shows how to do this using the App model, but what about from something running directly in your SharePoint site?

I decided to build something reusable from various approaches I saw. This code assumes you already have a File object, which you can get from an Input element, however in my case I'm capturing Image data directly from the clipboard on a paste event.

Source TypeScript (but if you aren't using TypeScript, see below for the JS)

'use strict';
//Author: Tim Wheeler (http://timwheeler.io)
//Purpose: Upload a file to a SharePoint library using REST and jQuery
module FileManager {
    export class SPRestFileUploader {
        public uploadFileAsArrayBuffer(file: File, webUrl: string, listname: string, filename: string): JQueryPromise<any> {
            var deferred = jQuery.Deferred();
            this.getArrayBuffer(file)
                .fail((error) => {
                    console.error("Get file buffer failed: " + error);
                    deferred.reject(error);
                })
                .done((arrayBuffer: any) => {
                    let options = {
                        url: `${webUrl}/_api/web/lists/getByTitle('${listname}')/RootFolder/Files/Add(url='${filename}', overwrite=true)`,
                        type: "POST",
                        data: arrayBuffer,
                        processData: false,
                        headers: {
                            "accept": "application/json;odata=verbose",
                            "X-RequestDigest": jQuery("#__REQUESTDIGEST").val(),
                            "content-length": arrayBuffer.byteLength
                        }
                    };
                    jQuery.ajax(options)
                        .fail((jqXHR, textStatus) => {
                            console.error("Upload file failed: " + textStatus);
                            deferred.reject(jqXHR, textStatus);
                        })
                        .done((data: any, textStatus: string, jqXHR: JQueryXHR) => {
                            console.log(textStatus);
                            if (data.d) {
                                deferred.resolve(data.d);
                            }
                            else {
                                deferred.resolve(data);
                            }
                        });
                });
            return deferred.promise();
        }
        private getArrayBuffer(file: File) {
            var deferred = jQuery.Deferred();
            var reader = new FileReader();
            reader.onloadend = (e: any) => {
                deferred.resolve(e.target.result);
            }
            reader.onerror = (e: any) => {
                deferred.reject(e.target.error);
            }
            reader.readAsArrayBuffer(file);
            return deferred.promise();
        }
    }
}

Source (JavaScript)

'use strict';
//Author: Tim Wheeler (http://timwheeler.io)
//Purpose: Upload a file to a SharePoint library using REST and jQuery
var FileManager;
(function (FileManager) {
    var SPRestFileUploader = /** @class */ (function () {
        function SPRestFileUploader() {
        }
        SPRestFileUploader.prototype.uploadFileAsArrayBuffer = function (file, webUrl, listname, filename) {
            var deferred = jQuery.Deferred();
            this.getArrayBuffer(file)
                .fail(function (error) {
                console.error("Get file buffer failed: " + error);
                deferred.reject(error);
            })
                .done(function (arrayBuffer) {
                var options = {
                    url: webUrl + "/_api/web/lists/getByTitle('" + listname + "')/RootFolder/Files/Add(url='" + filename + "', overwrite=true)",
                    type: "POST",
                    data: arrayBuffer,
                    processData: false,
                    headers: {
                        "accept": "application/json;odata=verbose",
                        "X-RequestDigest": jQuery("#__REQUESTDIGEST").val(),
                        "content-length": arrayBuffer.byteLength
                    }
                };
                jQuery.ajax(options)
                    .fail(function (jqXHR, textStatus) {
                    console.error("Upload file failed: " + textStatus);
                    deferred.reject(jqXHR, textStatus);
                })
                    .done(function (data, textStatus, jqXHR) {
                    console.log(textStatus);
                    if (data.d) {
                        deferred.resolve(data.d);
                    }
                    else {
                        deferred.resolve(data);
                    }
                });
            });
            return deferred.promise();
        };
        SPRestFileUploader.prototype.getArrayBuffer = function (file) {
            var deferred = jQuery.Deferred();
            var reader = new FileReader();
            reader.onloadend = function (e) {
                deferred.resolve(e.target.result);
            };
            reader.onerror = function (e) {
                deferred.reject(e.target.error);
            };
            reader.readAsArrayBuffer(file);
            return deferred.promise();
        };
        return SPRestFileUploader;
    }());
    FileManager.SPRestFileUploader = SPRestFileUploader;
})(FileManager || (FileManager = {}));
//# sourceMappingURL=SPRestFileUpload.js.map

Example call (TypeScript)

Here's a quick example how I call this helper:

try {
                let fileUpload = new FileManager.SPRestFileUploader();
                let filename = "myfilename";
                let extension = "jpg";
                fileUpload.uploadFileAsArrayBuffer(file, _spPageContextInfo.webAbsoluteUrl, "Documents", `${filename}.${extension}`)
                    .fail((sender, args) => {
                        alert("Upload failed");
                    })
                    .done((d) => {
                        let serverRelativeUrl = d.ServerRelativeUrl;
                        let uniqueId = d.UniqueId;
                        //...do something here :)
                    });
            } catch (e) {
                console.error('Darn: ', e);
            }

Example call (JavaScript)

Here's a quick example how I call this helper:

 try {
                var fileUpload = new FileManager.SPRestFileUploader();
                var filename = "myfilename";
                var extension = "jpg";
                fileUpload.uploadFileAsArrayBuffer(file, _spPageContextInfo.webAbsoluteUrl, kb.data.listNames.FilesLibrary, filename + "." + extension)
                    .fail(function (sender, args) {
                    alert("Upload failed");
                })
                    .done(function (d) {
                    var serverRelativeUrl = d.ServerRelativeUrl;
                    var uniqueId = d.UniqueId;
                    //...do something here :)
                });
            }
            catch (e) {
                console.error('Darn: ', e);
            }