--!movie
--!encoding=utf-8
global $
global emotionApiKey
global overlayInfoColor
global txt
global bmp
global imgOverlay
----------------------------------------
--
----------------------------------------
on startMovie
-- CONFIG ----------------------------
-- this is a private key - please use your own key for your own projects!
emotionApiKey = "4ed9846aac5247d291d73d990fda6141"
-- color used for face marker rects and emotion scores
overlayInfoColor = rgb(0,255,0)
-- /CONFIG ---------------------------
-- import libs
$.import("curl")
$.import("drop")
$.import("file")
$.import("json")
-- window settings
w = 800
h = 600
_movie.stage.title = "Drop a JPG or PNG image file into the window"
_movie.stage.titlebarOptions.visible = TRUE
_movie.stage.rect = rect(0,0,w,h)
_movie.centerStage = 1
_movie.stage.bgColor = rgb(0,0,0)
-- create text member for rendering emotion scores
txt = new(#text)
if $.OS="win" then
txt.font = "MS Sans Serif"
else
txt.font = "Arial"
end if
txt.fontSize = 10
txt.fixedLineSpace = 10
-- create bitmap member for displaying the dropped image
bmp = new(#bitmap)
-- create sprite, assign dropped image bitmap member
sprite(1).puppet = 1
sprite(1).member = bmp
sprite(1).loc = point(0,0)
-- create bitmap member for overlay infos
m = new(#bitmap)
m.image = image(w,h,32)
m.image.fill(m.image.rect, rgb(255,255,255))
m.regPoint = point(0,0)
imgOverlay = m.image
-- create sprite, assign overlay bitmap member
sprite(2).puppet = 1
sprite(2).member = m
sprite(2).loc = point(0,0)
sprite(2).ink = 36
sprite(2).color = overlayInfoColor
-- force immediate update
_movie.updateStage()
-- show the window
_movie.stage.visible = 1
-- start drop support
$.drop.setCallback(#filesDropped)
$.drop.start()
end
----------------------------------------
-- @callback
----------------------------------------
on filesDropped (tItems)
if tItems.files.count<1 then return -- no file was dropped
ok = bmp.importFileInto(tItems.files[1])
if not ok then return -- the first dropped file was not a JPG/PNG image
-- show the dropped image with correct ratio
sprite(1).rect = findMaxRect(_movie.stage.image.rect, float(bmp.width)/bmp.height)
-- clear previous overlay infos
imgOverlay.fill(imgOverlay.rect, rgb(255,255,255))
-- force immediate update
_movie.updateStage()
-- call Project Oxford Emotion Analysis API
_player.cursor(4)
res = getEmotion(tItems.files[1])
_player.cursor(0)
if integerP(res) then return _player.alert("Error:" && curl_error(res))
info = $.json.decode(res)
if ilk(info)=#propList then return _player.alert(info["error"]["message"])
cnt = info.count
if cnt=0 then return _player.alert("No faces were detected in this image")
-- show the result in the overlay layer
img = bmp.image
props = [:]
props[#shapeType] = #rect
props[#lineSize] = 1
props[#color] = rgb(0,0,0)
repeat with i = 1 to cnt
fr = info[i]["faceRectangle"]
-- map returned face rect to image as currently displayed in window
r = rect(fr["left"], fr["top"], fr["left"]+fr["width"], fr["top"]+fr["height"])
r = r.map(img.rect, sprite(1).rect)
-- draw face rect
imgOverlay.draw(r, props)
-- draw emotion scores
str = ""
scores = info[i]["scores"]
cntj = scores.count
repeat with j = 1 to cntj
put scores.getPropAt(j)&": "&scores[j]&RETURN after str
end repeat
delete the last char of str
txt.text = str
-- hilite the emotion with max. score
txt.line[scores.getPos(max(scores))].fontStyle = [#underline]
txtImg = txt.image.extractAlpha()
x = r.left + 3
y = r.bottom + 2
r = rect(x, y, x+txtImg.width, y+txtImg.height)
imgOverlay.copyPixels(txtImg, r, txtImg.rect, [#ink:36])
end repeat
-- force immediate update
_movie.updateStage()
end
----------------------------------------
-- Returns (centered) max. rect with specified ratio that fits into specified rect
-- @param {rect} tRect
-- @param {float} tRatio
-- @return {rect}
----------------------------------------
on findMaxRect (tRect, tRatio)
if tRect.width=0 OR tRect.height=0 OR tRatio=0 then return tRect
tMaxRectRatio = float(tRect.width)/tRect.height
if tMaxRectRatio>=tRatio then
h = tRect.height
w = h * tRatio
x = (tRect.width-w)/2
y = 0
else
w = tRect.width
h = w / tRatio
x = 0
y = (tRect.height-h)/2
end if
return rect(x, y, x+w, y+h)
end
----------------------------------------
-- Sends image file to Project Oxford Emotion Analysis API, returns result as JSON string
-- @param {string} fn
-- @return {string}
----------------------------------------
on getEmotion (fn)
-- get a CURL handle (=Curl Xtra instance)
ch = $.curl.init()
-- upload this image file as raw POST data
if $.OS="win" then
ch.setSourceFile(fn)
else
ch.setSourceFile(curl_hfs2posix(fn)) -- Curl Xtra for Mac expects POSIX, not HFS pathes
end if
-- specify options
ch.setOption($.curl.CURLOPT.URL, "https://api.projectoxford.ai/emotion/v1.0/recognize")
ch.setOption($.curl.CURLOPT.POST, 1)
-- add custom HTTP headers
header = []
header.add("Ocp-Apim-Subscription-Key: "&emotionApiKey)
header.add("Content-Type: application/octet-stream")
header.add("Content-Length: " & $.file.size(fn))
ch.setOption($.curl.CURLOPT.HTTPHEADER, header)
-- returnMode: 0=return error code (=default), 1=return data
return ch.exec(1)
end