diff --git a/app/models/optimized_image.rb b/app/models/optimized_image.rb
index 7566c09ff..05be3317b 100644
--- a/app/models/optimized_image.rb
+++ b/app/models/optimized_image.rb
@@ -1,7 +1,35 @@
 class OptimizedImage < ActiveRecord::Base
   belongs_to :upload
 
-  def filename
-    "#{sha[0..2]}/#{sha[3..5]}/#{sha[6..16]}_#{width}x#{height}#{ext}"
+  def self.create_for(upload_id, path)
+    image_info = FastImage.new(path)
+    OptimizedImage.new({
+      upload_id: upload_id,
+      sha: Digest::SHA1.file(path).hexdigest,
+      ext: File.extname(path),
+      width: image_info.size[0],
+      height: image_info.size[1]
+    })
   end
+
+  def url
+    "#{Upload.base_url}/#{optimized_path}/#{filename}"
+  end
+
+  def path
+    "#{path_root}/#{optimized_path}/#{filename}"
+  end
+
+  def path_root
+    @path_root ||= "#{Rails.root}/public"
+  end
+
+  def optimized_path
+    "uploads/#{RailsMultisite::ConnectionManagement.current_db}/_optimized/#{sha[0..2]}/#{sha[3..5]}"
+  end
+
+  def filename
+    "#{sha[6..16]}_#{width}x#{height}#{ext}"
+  end
+
 end
diff --git a/app/models/upload.rb b/app/models/upload.rb
index 953749767..fcc78095d 100644
--- a/app/models/upload.rb
+++ b/app/models/upload.rb
@@ -2,6 +2,8 @@ require 'digest/sha1'
 require 'image_sizer'
 require 's3'
 require 'local_store'
+require 'tempfile'
+require 'pathname'
 
 class Upload < ActiveRecord::Base
   belongs_to :user
@@ -14,6 +16,40 @@ class Upload < ActiveRecord::Base
   validates_presence_of :filesize
   validates_presence_of :original_filename
 
+  def thumbnail
+    @thumbnail ||= optimized_images.where(width: width, height: height).first
+  end
+
+  def thumbnail_url
+    thumbnail.url if has_thumbnail?
+  end
+
+  def has_thumbnail?
+    thumbnail.present?
+  end
+
+  def create_thumbnail!
+    return unless SiteSetting.create_thumbnails?
+    return unless width > SiteSetting.auto_link_images_wider_than
+    return if has_thumbnail?
+    @image_sorcery_loaded ||= require "image_sorcery"
+    original_path = "#{Rails.root}/public#{url}"
+    temp_file = Tempfile.new(["discourse", File.extname(original_path)])
+    if ImageSorcery.new(original_path).convert(temp_file.path, resize: "#{width}x#{height}")
+      thumbnail = OptimizedImage.create_for(id, temp_file.path)
+      optimized_images << thumbnail
+      # make sure the directory exists
+      FileUtils.mkdir_p Pathname.new(thumbnail.path).dirname
+      # move the temp file to the right location
+      File.open(thumbnail.path, "wb") do |f|
+        f.write temp_file.read
+      end
+    end
+    # close && remove temp file if it exists
+    temp_file.close
+    temp_file.unlink
+  end
+
   def self.create_for(user_id, file)
     # compute the sha
     sha = Digest::SHA1.file(file.tempfile).hexdigest
diff --git a/db/migrate/20130616082327_create_optimized_images.rb b/db/migrate/20130616082327_create_optimized_images.rb
index 24d73e260..a927548a0 100644
--- a/db/migrate/20130616082327_create_optimized_images.rb
+++ b/db/migrate/20130616082327_create_optimized_images.rb
@@ -9,6 +9,7 @@ class CreateOptimizedImages < ActiveRecord::Migration
     end
 
     add_index :optimized_images, :upload_id
+    add_index :optimized_images, [:upload_id, :width, :height], unique: true
   end
 
   def down
diff --git a/lib/cooked_post_processor.rb b/lib/cooked_post_processor.rb
index f46c49d83..192502d4a 100644
--- a/lib/cooked_post_processor.rb
+++ b/lib/cooked_post_processor.rb
@@ -2,7 +2,6 @@
 # example, inserting the onebox content, or image sizes.
 
 require_dependency 'oneboxer'
-require_dependency 'image_optimizer'
 
 class CookedPostProcessor
 
@@ -34,10 +33,18 @@ class CookedPostProcessor
       if src.present?
         # make sure the img has both width and height attributes
         update_dimensions!(img)
-        # optimize image
-        img['src'] = optimize_image(img)
-        # lightbox treatment
-        convert_to_link!(img)
+        # retrieve the associated upload, if any
+        upload = get_upload_from_url(img['src'])
+        if upload.present?
+          # create a thumbnail
+          upload.create_thumbnail!
+          # optimize image
+          img['src'] = optimize_image(img)
+          # lightbox treatment
+          convert_to_link!(img, upload.thumbnail_url)
+        else
+          convert_to_link!(img)
+        end
         # mark the post as dirty whenever the src has changed
         @dirty |= src != img['src']
       end
@@ -74,14 +81,19 @@ class CookedPostProcessor
     end
   end
 
+  def get_upload_from_url(url)
+    if Upload.has_been_uploaded?(url) && m = Upload.uploaded_regex.match(url)
+      Upload.where("id = ?", m[:upload_id]).first
+    end
+  end
+
   def optimize_image(img)
     return img["src"]
     # 1) optimize using image_optim
     # 2) .png vs. .jpg
-    # TODO: needs some <3
   end
 
-  def convert_to_link!(img)
+  def convert_to_link!(img, thumbnail=nil)
     src = img["src"]
     width, height = img["width"].to_i, img["height"].to_i
 
@@ -99,6 +111,7 @@ class CookedPostProcessor
     end
 
     # not a hyperlink so we can apply
+    img['src'] = thumbnail if thumbnail
     a = Nokogiri::XML::Node.new "a", @doc
     img.add_next_sibling(a)
     a["href"] = src