Browse Source

Allow easy image uploads

shortcutme 7 years ago
parent
commit
1a9040e32f
3 changed files with 100 additions and 3 deletions
  1. 91 3
      js/utils/CustomAlloyEditor.coffee
  2. 8 0
      js/utils/InlineEditor.coffee
  3. 1 0
      js/utils/Meditor.coffee

+ 91 - 3
js/utils/CustomAlloyEditor.coffee

@@ -19,8 +19,7 @@ class CustomAlloyEditor extends Class
 			), 100
 		editor.get('nativeEditor').on "click", @handleSelectionChange
 		editor.get('nativeEditor').on "change", @handleChange
-		editor.get('nativeEditor').on 'imageAdd', (e) ->
-			e.data.el.remove()  # Don't allow image upload yet
+		editor.get('nativeEditor').on 'imageAdd', @handleImageAdd
 		editor.get('nativeEditor').on "actionPerformed", @handleAction
 		editor.get('nativeEditor').on 'afterCommandExec', @handleCommand
 
@@ -28,9 +27,98 @@ class CustomAlloyEditor extends Class
 
 		@el_last_created = null
 
-		return editor
+		@image_size_limit = 200*1024
+		@image_resize_width = 1200
+		@image_resize_height = 900
+		@image_preverse_ratio = true
+		@image_try_png = false
 
+		return @
 
+
+	calcSize: (source_width, source_height, target_width, target_height) ->
+		if source_width <= target_width and source_height <= target_height
+			return [source_width, source_height]
+
+		width = target_width
+		height = width * (source_height / source_width);
+		if height > target_height
+			height = target_height
+			width = height * (source_width / source_height)
+		return [Math.round(width), Math.round(height)]
+
+
+	scaleHalf: (image) ->
+		canvas = document.createElement("canvas")
+		canvas.width = image.width / 1.5
+		canvas.height = image.height / 1.5
+		ctx = canvas.getContext("2d")
+		ctx.drawImage(image, 0, 0, canvas.width, canvas.height)
+		return canvas
+
+
+	resizeImage: (image, width, height) =>
+		canvas = document.createElement("canvas")
+		if @image_preverse_ratio
+			[canvas.width, canvas.height] = @calcSize(image.width, image.height, width, height)
+		else
+			canvas.width = width
+			canvas.height = height
+
+		ctx = canvas.getContext("2d")
+		ctx.fillStyle = "#FFF"
+		ctx.fillRect(0, 0, canvas.width, canvas.height)
+		image_resized = image
+		while image_resized.width > width * 1.5
+			image_resized = @scaleHalf(image_resized)
+		ctx.drawImage(image_resized, 0, 0, canvas.width, canvas.height)
+
+		if @image_try_png and @getExtension(image.src) == "png"  # and canvas.width < 1400 and canvas.height < 1000
+			###
+			quant = new RgbQuant({colors: 256, method: 1})
+			quant.sample(canvas)
+			quant.palette(true)
+			canvas_quant = drawPixels(quant.reduce(canvas), width)
+			optimizer = new CanvasTool.PngEncoder(canvas_quant, { bitDepth: 8, colourType: CanvasTool.PngEncoder.ColourType.TRUECOLOR })
+			image_base64uri = "data:image/png;base64," + btoa(optimizer.convert())
+			###
+			image_base64uri = canvas.toDataURL("image/png", 0.1)
+			if image_base64uri.length > @image_size_limit
+				# Too large, convert to jpg
+				@log "PNG too large (#{image_base64uri.length} bytes), convert to jpg instead"
+				image_base64uri = canvas.toDataURL("image/jpeg", 0.7)
+			else
+				@log "Converted to PNG"
+		else
+			image_base64uri = canvas.toDataURL("image/jpeg", 0.7)
+
+		@log "Resized #{image.width}x#{image.height} to #{canvas.width}x#{canvas.height} (#{image_base64uri.length} bytes)"
+		return [image_base64uri, canvas.width, canvas.height]
+
+	getExtension: (data) =>
+		return data.match("/[a-z]+")[0].replace("/", "").replace("jpeg", "jpg")
+
+	handleImageAdd: (e) =>
+		if e.data.file.name
+			name = e.data.file.name.replace(/[^\w\.-]/gi, "_")
+		else
+			name = Time.timestamp() + "." + @getExtension(e.data.file.type)
+		e.data.el.$.style.maxWidth = "2400px"  # Better resize quality
+
+		if e.data.file.size > @image_size_limit
+			@log "File size #{e.data.file.size} larger than allowed #{@image_size_limit}, resizing..."
+			[image_base64uri, width, height] = @resizeImage(e.data.el.$, @image_resize_width, @image_resize_height)
+			e.data.el.$.src = image_base64uri
+			name = name.replace(/(png|gif|jpg)/, @getExtension(image_base64uri))  # Change extension if necessary
+		else
+			image_base64uri = e.data.el.$.src
+		# e.data.el.remove()  # Don't allow image upload yet
+		e.data.el.$.style.maxWidth = ""  # Show in standard size
+		e.data.el.$.alt = "#{name} (#{width}x#{height})"
+		@handleImageSave(name, image_base64uri, e.data.el.$)
+
+
+	# Html fixes
 	handleAction: (e) =>
 		el = e.editor.getSelection().getStartElement()
 		# Convert  Pre to Pre > Code

+ 8 - 0
js/utils/InlineEditor.coffee

@@ -24,6 +24,7 @@ class InlineEditor
 
 		if @elem.data("editable-mode") == "meditor"
 			@editor = new Meditor(@elem[0], @getContent(@elem, "raw"))
+			@editor.handleImageSave = @handleImageSave
 			@editor.load()
 		else
 			@editor = $("<textarea class='editor'></textarea>")
@@ -65,6 +66,13 @@ class InlineEditor
 
 		return false
 
+	handleImageSave: (name, image_base64uri, el) =>
+		el.style.opacity = 0.5
+		object_name = @getObject(@elem).data("object").replace(/[^A-Za-z0-9]/g, "_").toLowerCase()
+		file_path = "data/img/#{object_name}_#{name}"
+		Page.cmd "fileWrite", [file_path, image_base64uri.replace(/.*,/, "")], =>
+			el.style.opacity = 1
+			el.src = file_path
 
 	stopEdit: =>
 		@editor.remove()

+ 1 - 0
js/utils/Meditor.coffee

@@ -38,6 +38,7 @@ class Meditor extends Class
 
 		# Create ckeditor
 		@editor = new CustomAlloyEditor(@tag)
+		if @handleImageSave then @editor.handleImageSave = @handleImageSave
 
 		# Create markdown editor textfield
 		@tag.insertAdjacentHTML('beforeBegin', @tag_original.outerHTML)