@@ -104,13 +104,12 @@ module.exports = class ThumbnailGenerator extends Plugin {
 
     image = this.protect(image)
 
-    var steps = Math.ceil(Math.log2(image.width / targetWidth))
+    var steps = Math.ceil(Math.abs(Math.log2(image.width / targetWidth)))
     var sW = targetWidth * Math.pow(2, steps - 1)
     var sH = targetHeight * Math.pow(2, steps - 1)
     var x = 2
 
     while (steps--) {
-      console.log(sW, sH)
       var canvas = document.createElement('canvas')
       canvas.width = sW
       canvas.height = sH
const Plugin = require('../../core/Plugin')
const Utils = require('../../core/Utils')
/**
 * The Thumbnail Generator plugin
 *
 */

module.exports = class ThumbnailGenerator extends Plugin {
  constructor (uppy, opts) {
    super(uppy, opts)
    this.type = 'thumbnail'
    this.id = 'ThumbnailGenerator'
    this.title = 'Thumbnail Generator'
    this.queue = []
    this.queueProcessing = false

    const defaultOptions = {
      thumbnailWidth: 200
    }

    this.opts = Object.assign({}, defaultOptions, opts)

    this.addToQueue = this.addToQueue.bind(this)
  }

  /**
   * Create a thumbnail for the given Uppy file object.
   *
   * @param {{data: Blob}} file
   * @param {number} width
   * @return {Promise}
   */
  createThumbnail (file, targetWidth) {
    const originalUrl = URL.createObjectURL(file.data)
    const onload = new Promise((resolve, reject) => {
      const image = new Image()
      image.src = originalUrl
      image.onload = () => {
        URL.revokeObjectURL(originalUrl)
        resolve(image)
      }
      image.onerror = () => {
        // The onerror event is totally useless unfortunately, as far as I know
        URL.revokeObjectURL(originalUrl)
        reject(new Error('Could not create thumbnail'))
      }
    })

    return onload
      .then(image => {
        const targetHeight = this.getProportionalHeight(image, targetWidth)
        const canvas = this.resizeImage(image, targetWidth, targetHeight)
        return this.canvasToBlob(canvas, 'image/png')
      })
      .then(blob => {
        return URL.createObjectURL(blob)
      })
  }

  /**
   * Make sure the image doesn’t exceed browser/device canvas limits.
   * For ios with 256 RAM and ie
   */
  protect (image) {
    // https://stackoverflow.com/questions/6081483/maximum-size-of-a-canvas-element

    var ratio = image.width / image.height

    var maxSquare = 5000000  // ios max canvas square
    var maxSize = 4096  // ie max canvas dimensions

    var maxW = Math.floor(Math.sqrt(maxSquare * ratio))
    var maxH = Math.floor(maxSquare / Math.sqrt(maxSquare * ratio))
    if (maxW > maxSize) {
      maxW = maxSize
      maxH = Math.round(maxW / ratio)
    }
    if (maxH > maxSize) {
      maxH = maxSize
      maxW = Math.round(ratio * maxH)
    }
    if (image.width > maxW) {
      var canvas = document.createElement('canvas')
      canvas.width = maxW
      canvas.height = maxH
      canvas.getContext('2d').drawImage(image, 0, 0, maxW, maxH)
      image.src = 'about:blank'
      image.width = 1
      image.height = 1
      image = canvas
    }

    return image
  }

  /**
   * Resize an image to the target `width` and `height`.
   *
   * Returns a Canvas with the resized image on it.
   */
  resizeImage (image, targetWidth, targetHeight) {
    // Resizing in steps refactored to use a solution from
    // https://blog.uploadcare.com/image-resize-in-browsers-is-broken-e38eed08df01

    image = this.protect(image)

    var steps = Math.ceil(Math.log2(image.width / targetWidth))
    var sW = targetWidth * Math.pow(2, steps - 1)
    var sH = targetHeight * Math.pow(2, steps - 1)
    var x = 2

    while (steps--) {
      console.log(sW, sH)
      var canvas = document.createElement('canvas')
      canvas.width = sW
      canvas.height = sH
      canvas.getContext('2d').drawImage(image, 0, 0, sW, sH)
      image = canvas

      sW = Math.round(sW / x)
      sH = Math.round(sH / x)
    }

    return image
  }

  /**
   * Save a <canvas> element's content to a Blob object.
   *
   * @param {HTMLCanvasElement} canvas
   * @return {Promise}
   */
  canvasToBlob (canvas, type, quality) {
    if (canvas.toBlob) {
      return new Promise(resolve => {
        canvas.toBlob(resolve, type, quality)
      })
    }
    return Promise.resolve().then(() => {
      return Utils.dataURItoBlob(canvas.toDataURL(type, quality), {})
    })
  }

  getProportionalHeight (img, width) {
    const aspect = img.width / img.height
    return Math.round(width / aspect)
  }

  /**
   * Set the preview URL for a file.
   */
  setPreviewURL (fileID, preview) {
    const { files } = this.uppy.state
    this.uppy.setState({
      files: Object.assign({}, files, {
        [fileID]: Object.assign({}, files[fileID], {
          preview: preview
        })
      })
    })
  }

  addToQueue (item) {
    this.queue.push(item)
    if (this.queueProcessing === false) {
      this.processQueue()
    }
  }

  processQueue () {
    this.queueProcessing = true
    if (this.queue.length > 0) {
      const current = this.queue.shift()
      return this.requestThumbnail(current)
        .catch(err => {}) // eslint-disable-line handle-callback-err
        .then(() => this.processQueue())
    } else {
      this.queueProcessing = false
    }
  }

  requestThumbnail (file) {
    if (Utils.isPreviewSupported(file.type) && !file.isRemote) {
      return this.createThumbnail(file, this.opts.thumbnailWidth)
        .then(preview => {
          this.setPreviewURL(file.id, preview)
        })
        .catch(err => {
          console.warn(err.stack || err.message)
        })
    }
    return Promise.resolve()
  }

  install () {
    this.uppy.on('file-added', this.addToQueue)
  }
  uninstall () {
    this.uppy.off('file-added', this.addToQueue)
  }
}

I'm not sure if `Math.abs` is the best way to do it, for very small images the Math.abs call might return a positive number > 1 which would cause the step scaling to first size it up to N times the target size and then resize it back down. Another way could be to check if `steps < 1` and then set it to 1?