diff --git a/BlockPi/index.html b/BlockPi/index.html
index e9cb940..88a39d7 100644
--- a/BlockPi/index.html
+++ b/BlockPi/index.html
@@ -958,6 +958,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ image
+
+
+
+
+
+
+ video
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/BlockPi/src/msg/en.js b/BlockPi/src/msg/en.js
index 32c0221..187f2c4 100644
--- a/BlockPi/src/msg/en.js
+++ b/BlockPi/src/msg/en.js
@@ -28,6 +28,8 @@ var MSG = {
catGPIOin: "GPIO IN",
catGPIOout: "GPIO OUT",
catTube: "Digital Tube",
+ catPicamera: "Picamera",
+ catPicameraPro: "Professional Mode",
listVariable: "list",
textVariable: "text",
deviceVariable: "device",
diff --git a/BlockPi/src/msg/js/en.js b/BlockPi/src/msg/js/en.js
index 59fd789..6eedda5 100644
--- a/BlockPi/src/msg/js/en.js
+++ b/BlockPi/src/msg/js/en.js
@@ -437,6 +437,7 @@ Blockly.Msg["PROCEDURES_HUE"] = "290";
Blockly.Msg["GPIOIN_HUE"] = "180";
Blockly.Msg["GPIOOUT_HUE"] = "0";
Blockly.Msg["SENSEHAT_HUE"] = "40";
+Blockly.Msg["CAMERA_HUE"] = "135";
Blockly.Msg["COLOUR_CONVERT_TITLE"] = "convert colour %1 to RGB array"
Blockly.Msg["COLOUR_CONVERT_TOOLTIP"] = "Converts the colour to an array of RGB values(0-255)."
@@ -622,4 +623,108 @@ Blockly.Msg["TUBE_SHOW_TOOLTIP"] = "Displays a text string, no more than 4 chara
Blockly.Msg["TUBE_SCROLL_TITLE"] = "%1 scroll text %2 delay %3 ms"
Blockly.Msg["TUBE_SCROLL_TOOLTIP"] = "Scrolls a text string from right to left with the given delay, 250ms means 4 fps."
Blockly.Msg["TUBE_CLEAR_TITLE"] = "clear %1"
-Blockly.Msg["TUBE_CLEAR_TOOLTIP"] = "Clears the digital tube."
\ No newline at end of file
+Blockly.Msg["TUBE_CLEAR_TOOLTIP"] = "Clears the digital tube."
+Blockly.Msg["CAMERA_ENABLE_TITLE"] = "%1 camera"
+Blockly.Msg["CAMERA_ENABLE_ENABLE"] = "enable"
+Blockly.Msg["CAMERA_ENABLE_STOP"] = "stop"
+Blockly.Msg["CAMERA_ENABLE_TOOLTIP"] = "Enables or disables the Picamera module."
+Blockly.Msg["CAMERA_PREVIEW_TITLE"] = "%1 preview"
+Blockly.Msg["CAMERA_PREVIEW_OPEN"] = "open"
+Blockly.Msg["CAMERA_PREVIEW_CLOSE"] = "close"
+Blockly.Msg["CAMERA_PREVIEW_TOOLTIP"] = "Opens or closes a preview window for the camera."
+Blockly.Msg["CAMERA_CAPTURE_TITLE"] = "capture image %1 . %2"
+Blockly.Msg["CAMERA_CAPTURE_TOOLTIP"] = "Captures an image from the camera, storing it in the given path/filename and format."
+Blockly.Msg["CAMERA_RECORD_TITLE"] = "record video %1 .h264"
+Blockly.Msg["CAMERA_RECORD_TOOLTIP"] = "Starts recording video from the camera, storing it in the given path/filename in h264 format."
+Blockly.Msg["CAMERA_STOP_RECORDING_TITLE"] = "stop recording video"
+Blockly.Msg["CAMERA_STOP_RECORDING_TOOLTIP"] = "Stops recording video."
+Blockly.Msg["CAMERA_WEB_STREAM_TITLE"] = "start web video streaming, port: %1"
+Blockly.Msg["CAMERA_WEB_STREAM_TOOLTIP"] = "Starts HTTP video streaming on your RPi ip and given port. Open the link http://your-pi-ip:port/stream.mjpg with any web browser or video player to watch the stream."
+Blockly.Msg["CAMERA_RESOLUTION_TITLE"] = "set camera resolution %1 x %2"
+Blockly.Msg["CAMERA_RESOLUTION_TOOLTIP"] = "Sets the resolution at which image captures, video recordings, and previews will be captured."
+Blockly.Msg["CAMERA_FLIP_TITLE"] = "flip camera %1"
+Blockly.Msg["CAMERA_FLIP_H"] = "horizontally"
+Blockly.Msg["CAMERA_FLIP_V"] = "vertically"
+Blockly.Msg["CAMERA_FLIP_TOOLTIP"] = "Sets whether the camera\'s output is horizontally/vertically flipped."
+Blockly.Msg["CAMERA_ROTATE_TITLE"] = "rotate camera %1"
+Blockly.Msg["CAMERA_ROTATE_TOOLTIP"] = "Sets the current rotation of the camera\'s image."
+Blockly.Msg["CAMERA_FRAMERATE_TITLE"] = "set camera framerate %1"
+Blockly.Msg["CAMERA_FRAMERATE_TOOLTIP"] = "Sets the framerate at which video recordings, and previews will run."
+Blockly.Msg["CAMERA_ANNOTATE_TEXT_TITLE"] = "add annotation text %1"
+Blockly.Msg["CAMERA_ANNOTATE_TEXT_TOOLTIP"] = "Sets a text annotation for all output. Only ASCII characters available, with a limited length of 32 characters."
+Blockly.Msg["CAMERA_ANNOTATE_SIZE_TITLE"] = "set annotation size %1"
+Blockly.Msg["CAMERA_ANNOTATE_SIZE_TOOLTIP"] = "Sets the size of the annotation text."
+Blockly.Msg["CAMERA_ANNOTATE_COLOUR_TITLE"] = "set annotation %1 colour %2"
+Blockly.Msg["CAMERA_ANNOTATE_COLOUR_FOREGROUND"] = "foreground"
+Blockly.Msg["CAMERA_ANNOTATE_COLOUR_BACKGROUND"] = "background"
+Blockly.Msg["CAMERA_ANNOTATE_COLOUR_TOOLTIP"] = "Sets the brightness or the background colour of the annotation text."
+Blockly.Msg["CAMERA_ISO_TITLE"] = "set iso %1"
+Blockly.Msg["CAMERA_ISO_AUTO"] = "auto"
+Blockly.Msg["CAMERA_ISO_TOOLTIP"] = "Sets the apparent ISO setting of the camera."
+Blockly.Msg["CAMERA_SHUTTER_SPEED_TITLE"] = "set shutter speed %1 μs"
+Blockly.Msg["CAMERA_SHUTTER_SPEED_TOOLTIP"] = "Sets the shutter speed of the camera in microseconds."
+Blockly.Msg["CAMERA_BRIGHTNESS_TITLE"] = "set image brightness %1"
+Blockly.Msg["CAMERA_BRIGHTNESS_TOOLTIP"] = "Sets the brightness setting of the camera(0~100)."
+Blockly.Msg["CAMERA_SHARPNESS_TITLE"] = "set image sharpness %1"
+Blockly.Msg["CAMERA_SHARPNESS_TOOLTIP"] = "Sets the sharpness setting of the camera(-100~100)."
+Blockly.Msg["CAMERA_CONTRAST_TITLE"] = "set image contrast %1"
+Blockly.Msg["CAMERA_CONTRAST_TOOLTIP"] = "Sets the contrast setting of the camera(-100~100)."
+Blockly.Msg["CAMERA_SATURATION_TITLE"] = "set image saturation %1"
+Blockly.Msg["CAMERA_SATURATION_TOOLTIP"] = "Sets the saturation setting of the camera(-100~100)."
+Blockly.Msg["CAMERA_AWB_MODE_TITLE"] = "set awb mode %1"
+Blockly.Msg["CAMERA_AWB_MODE_AUTO"] = "auto"
+Blockly.Msg["CAMERA_AWB_MODE_SUNLIGHT"] = "sunlight"
+Blockly.Msg["CAMERA_AWB_MODE_CLOUDY"] = "cloudy"
+Blockly.Msg["CAMERA_AWB_MODE_SHADE"] = "shade"
+Blockly.Msg["CAMERA_AWB_MODE_TUNGSTEN"] = "tungsten"
+Blockly.Msg["CAMERA_AWB_MODE_INCANDESCENT"] = "incandescent"
+Blockly.Msg["CAMERA_AWB_MODE_FLUORESCENT"] = "fluorescent"
+Blockly.Msg["CAMERA_AWB_MODE_FLASH"] = "flash"
+Blockly.Msg["CAMERA_AWB_MODE_HORIZON"] = "horizon"
+Blockly.Msg["CAMERA_AWB_MODE_TOOLTIP"] = "Sets the auto-white-balance mode of the camera."
+Blockly.Msg["CAMERA_EXPOSURE_COMPENSATION_TITLE"] = "set exposure compensation %1"
+Blockly.Msg["CAMERA_EXPOSURE_COMPENSATION_TOOLTIP"] = "Sets the exposure compensation level of the camera(-25~25)."
+Blockly.Msg["CAMERA_EXPOSURE_MODE_TITLE"] = "set exposure mode %1"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_AUTO"] = "auto"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_NIGHT"] = "night"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_NIGHTPREVIEW"] = "night preview"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_BACKLIGHT"] = "backlight"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_SPOTLIGHT"] = "spotlight"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_SPORTS"] = "sports"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_SNOW"] = "snow"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_BEACH"] = "beach"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_VERYLONG"] = "very long"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_FIXEDFPS"] = "fixed fps"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_ANTISHAKE"] = "antishake"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_FIREWORKS"] = "fireworks"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_TOOLTIP"] = "Sets the exposure mode of the camera."
+Blockly.Msg["CAMERA_METER_MODE_TITLE"] = "set metering mode %1"
+Blockly.Msg["CAMERA_METER_MODE_AVERAGE"] = "average"
+Blockly.Msg["CAMERA_METER_MODE_SPOT"] = "spot"
+Blockly.Msg["CAMERA_METER_MODE_BACKLIT"] = "backlit"
+Blockly.Msg["CAMERA_METER_MODE_MATRIX"] = "matrix"
+Blockly.Msg["CAMERA_METER_MODE_TOOLTIP"] = "Sets the metering mode of the camera."
+Blockly.Msg["CAMERA_IMAGE_EFFECT_TITLE"] = "set image effect %1"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_NONE"] = "none"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_NEGATIVE"] = "negative"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_SOLARIZE"] = "solarize"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_SKETCH"] = "sketch"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_DENOISE"] = "denoise"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_EMBOSS"] = "emboss"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_OILPAINT"] = "oilpaint"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_HATCH"] = "hatch"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_GPEN"] = "G pen"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_PASTEL"] = "pastel"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_WATERCOLOR"] = "watercolour"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_FILM"] = "film"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_BLUR"] = "blur"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_SATURATION"] = "saturation"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_COLORSWAP"] = "colour swap"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_WASHEDOUT"] = "washed out"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_POSTERISE"] = "posterise"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_COLORPOINT"] = "colour point"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_COLORBALANCE"] = "colour balance"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_CARTOON"] = "cartoon"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_DEINTERLACE1"] = "deinterlace1"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_DEINTERLACE2"] = "deinterlace2"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_TOOLTIP"] = "Sets the current image effect applied by the camera."
\ No newline at end of file
diff --git a/BlockPi/src/msg/js/zh-hans.js b/BlockPi/src/msg/js/zh-hans.js
index f3a30b3..40ecec1 100644
--- a/BlockPi/src/msg/js/zh-hans.js
+++ b/BlockPi/src/msg/js/zh-hans.js
@@ -437,6 +437,7 @@ Blockly.Msg["PROCEDURES_HUE"] = "290";
Blockly.Msg["GPIOIN_HUE"] = "180";
Blockly.Msg["GPIOOUT_HUE"] = "0";
Blockly.Msg["SENSEHAT_HUE"] = "40";
+Blockly.Msg["CAMERA_HUE"] = "135";
Blockly.Msg["COLOUR_CONVERT_TITLE"] = "将颜色 %1 转成RGB列表"
Blockly.Msg["COLOUR_CONVERT_TOOLTIP"] = "将该颜色转化成RGB数值(0-255)组成的列表。"
@@ -622,4 +623,108 @@ Blockly.Msg["TUBE_SHOW_TOOLTIP"] = "显示字符串,不多于4个字符。"
Blockly.Msg["TUBE_SCROLL_TITLE"] = "%1滚动文本%2延时%3毫秒"
Blockly.Msg["TUBE_SCROLL_TOOLTIP"] = "按给定延时从右往左滚动显示字符串, 250毫秒对应每秒4帧。"
Blockly.Msg["TUBE_CLEAR_TITLE"] = "清空数码管%1"
-Blockly.Msg["TUBE_CLEAR_TOOLTIP"] = "清空数码管显示的内容。"
\ No newline at end of file
+Blockly.Msg["TUBE_CLEAR_TOOLTIP"] = "清空数码管显示的内容。"
+Blockly.Msg["CAMERA_ENABLE_TITLE"] = "%1摄像头"
+Blockly.Msg["CAMERA_ENABLE_ENABLE"] = "启用"
+Blockly.Msg["CAMERA_ENABLE_STOP"] = "停用"
+Blockly.Msg["CAMERA_ENABLE_TOOLTIP"] = "启用或停用摄像头模块。"
+Blockly.Msg["CAMERA_PREVIEW_TITLE"] = "%1预览"
+Blockly.Msg["CAMERA_PREVIEW_OPEN"] = "打开"
+Blockly.Msg["CAMERA_PREVIEW_CLOSE"] = "关闭"
+Blockly.Msg["CAMERA_PREVIEW_TOOLTIP"] = "打开或关闭摄像头预览窗口。"
+Blockly.Msg["CAMERA_CAPTURE_TITLE"] = "拍摄照片%1.%2"
+Blockly.Msg["CAMERA_CAPTURE_TOOLTIP"] = "用摄像头拍摄一张照片,以指定的格式保存在指定的路径/文件名。"
+Blockly.Msg["CAMERA_RECORD_TITLE"] = "摄制视频%1.h264"
+Blockly.Msg["CAMERA_RECORD_TOOLTIP"] = "用摄像头开始拍摄视频,以h264格式保存在指定的路径/文件名。"
+Blockly.Msg["CAMERA_STOP_RECORDING_TITLE"] = "停止摄制视频"
+Blockly.Msg["CAMERA_STOP_RECORDING_TOOLTIP"] = "停止拍摄视频。"
+Blockly.Msg["CAMERA_WEB_STREAM_TITLE"] = "开始网络视频直播,端口:%1"
+Blockly.Msg["CAMERA_WEB_STREAM_TOOLTIP"] = "在你的树莓派IP地址和指定端口开启HTTP视频直播流。使用任意浏览器或者视频播放器打开链接http://树莓派IP:端口/stream.mjpg来观看直播。"
+Blockly.Msg["CAMERA_RESOLUTION_TITLE"] = "设置摄像头分辨率%1x%2"
+Blockly.Msg["CAMERA_RESOLUTION_TOOLTIP"] = "设置拍照、录像和预览的分辨率。"
+Blockly.Msg["CAMERA_FLIP_TITLE"] = "%1翻转摄像头"
+Blockly.Msg["CAMERA_FLIP_H"] = "水平"
+Blockly.Msg["CAMERA_FLIP_V"] = "垂直"
+Blockly.Msg["CAMERA_FLIP_TOOLTIP"] = "设置是否水平/垂直翻转摄像头的输出。"
+Blockly.Msg["CAMERA_ROTATE_TITLE"] = "旋转摄像头%1"
+Blockly.Msg["CAMERA_ROTATE_TOOLTIP"] = "设置当前摄像头图像的旋转方向。"
+Blockly.Msg["CAMERA_FRAMERATE_TITLE"] = "设置摄像头帧率%1"
+Blockly.Msg["CAMERA_FRAMERATE_TOOLTIP"] = "设置录像和预览的帧率(FPS)。"
+Blockly.Msg["CAMERA_ANNOTATE_TEXT_TITLE"] = "添加注释文本%1"
+Blockly.Msg["CAMERA_ANNOTATE_TEXT_TOOLTIP"] = "为所有输出添加一段注释文本。只允许最多32个ASCII字符。"
+Blockly.Msg["CAMERA_ANNOTATE_SIZE_TITLE"] = "设置注释大小%1"
+Blockly.Msg["CAMERA_ANNOTATE_SIZE_TOOLTIP"] = "设置注释文本的字体大小。"
+Blockly.Msg["CAMERA_ANNOTATE_COLOUR_TITLE"] = "设置注释%1颜色%2"
+Blockly.Msg["CAMERA_ANNOTATE_COLOUR_FOREGROUND"] = "文本"
+Blockly.Msg["CAMERA_ANNOTATE_COLOUR_BACKGROUND"] = "背景"
+Blockly.Msg["CAMERA_ANNOTATE_COLOUR_TOOLTIP"] = "设置注释文本的亮度或者背景的颜色。"
+Blockly.Msg["CAMERA_ISO_TITLE"] = "设置ISO%1"
+Blockly.Msg["CAMERA_ISO_AUTO"] = "自动"
+Blockly.Msg["CAMERA_ISO_TOOLTIP"] = "设置摄像头的ISO数值。"
+Blockly.Msg["CAMERA_SHUTTER_SPEED_TITLE"] = "设置快门速度%1微秒"
+Blockly.Msg["CAMERA_SHUTTER_SPEED_TOOLTIP"] = "设置摄像头的快门速度,单位微秒。"
+Blockly.Msg["CAMERA_BRIGHTNESS_TITLE"] = "设置图像亮度%1"
+Blockly.Msg["CAMERA_BRIGHTNESS_TOOLTIP"] = "设置摄像头的亮度设置(0~100)。"
+Blockly.Msg["CAMERA_SHARPNESS_TITLE"] = "设置图像锐度%1"
+Blockly.Msg["CAMERA_SHARPNESS_TOOLTIP"] = "设置摄像头的锐度设置(-100~100)。"
+Blockly.Msg["CAMERA_CONTRAST_TITLE"] = "设置图像对比度%1"
+Blockly.Msg["CAMERA_CONTRAST_TOOLTIP"] = "设置摄像头的对比度设置(-100~100)。"
+Blockly.Msg["CAMERA_SATURATION_TITLE"] = "设置图像饱和度%1"
+Blockly.Msg["CAMERA_SATURATION_TOOLTIP"] = "设置摄像头的饱和度设置(-100~100)。"
+Blockly.Msg["CAMERA_AWB_MODE_TITLE"] = "设置自动白平衡模式%1"
+Blockly.Msg["CAMERA_AWB_MODE_AUTO"] = "自动"
+Blockly.Msg["CAMERA_AWB_MODE_SUNLIGHT"] = "日光"
+Blockly.Msg["CAMERA_AWB_MODE_CLOUDY"] = "多云"
+Blockly.Msg["CAMERA_AWB_MODE_SHADE"] = "阴影"
+Blockly.Msg["CAMERA_AWB_MODE_TUNGSTEN"] = "钨丝灯"
+Blockly.Msg["CAMERA_AWB_MODE_INCANDESCENT"] = "白炽灯"
+Blockly.Msg["CAMERA_AWB_MODE_FLUORESCENT"] = "荧光灯"
+Blockly.Msg["CAMERA_AWB_MODE_FLASH"] = "闪光灯"
+Blockly.Msg["CAMERA_AWB_MODE_HORIZON"] = "地平线"
+Blockly.Msg["CAMERA_AWB_MODE_TOOLTIP"] = "设置摄像头的自动白平衡模式。"
+Blockly.Msg["CAMERA_EXPOSURE_COMPENSATION_TITLE"] = "设置曝光补偿%1"
+Blockly.Msg["CAMERA_EXPOSURE_COMPENSATION_TOOLTIP"] = "设置摄像头的曝光补偿水平(-25~25)。"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_TITLE"] = "设置曝光模式%1"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_AUTO"] = "自动"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_NIGHT"] = "夜间"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_NIGHTPREVIEW"] = "夜间预览"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_BACKLIGHT"] = "逆光"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_SPOTLIGHT"] = "聚光灯"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_SPORTS"] = "运动"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_SNOW"] = "雪景"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_BEACH"] = "沙滩"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_VERYLONG"] = "长曝光"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_FIXEDFPS"] = "固定帧率"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_ANTISHAKE"] = "防抖"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_FIREWORKS"] = "烟火"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_TOOLTIP"] = "设置摄像头的曝光模式。"
+Blockly.Msg["CAMERA_METER_MODE_TITLE"] = "设置测光模式%1"
+Blockly.Msg["CAMERA_METER_MODE_AVERAGE"] = "平均测光"
+Blockly.Msg["CAMERA_METER_MODE_SPOT"] = "点测光"
+Blockly.Msg["CAMERA_METER_MODE_BACKLIT"] = "模拟背光"
+Blockly.Msg["CAMERA_METER_MODE_MATRIX"] = "矩阵测光"
+Blockly.Msg["CAMERA_METER_MODE_TOOLTIP"] = "设置摄像头的测光模式。"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_TITLE"] = "设置图像特效%1"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_NONE"] = "无"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_NEGATIVE"] = "负片"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_SOLARIZE"] = "过曝"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_SKETCH"] = "素描"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_DENOISE"] = "降噪"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_EMBOSS"] = "浮雕"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_OILPAINT"] = "油画"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_HATCH"] = "网格"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_GPEN"] = "G笔"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_PASTEL"] = "粉彩"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_WATERCOLOR"] = "水彩"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_FILM"] = "胶片"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_BLUR"] = "模糊"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_SATURATION"] = "饱和"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_COLORSWAP"] = "换色"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_WASHEDOUT"] = "冲刷"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_POSTERISE"] = "色彩分离"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_COLORPOINT"] = "重点色"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_COLORBALANCE"] = "色彩均衡"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_CARTOON"] = "卡通"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_DEINTERLACE1"] = "反交错1"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_DEINTERLACE2"] = "反交错2"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_TOOLTIP"] = "设置摄像头应用的图像特效。"
\ No newline at end of file
diff --git a/BlockPi/src/msg/js/zh-hant.js b/BlockPi/src/msg/js/zh-hant.js
index c26b371..647c9a1 100644
--- a/BlockPi/src/msg/js/zh-hant.js
+++ b/BlockPi/src/msg/js/zh-hant.js
@@ -441,6 +441,7 @@ Blockly.Msg["PROCEDURES_HUE"] = "290";
Blockly.Msg["GPIOIN_HUE"] = "180";
Blockly.Msg["GPIOOUT_HUE"] = "0";
Blockly.Msg["SENSEHAT_HUE"] = "40";
+Blockly.Msg["CAMERA_HUE"] = "135";
Blockly.Msg["TIME_SLEEP_TITLE"] = "等待%1秒";
Blockly.Msg["TIME_SLEEP_TOOLTIP"] = "等待一段時間。";
@@ -622,4 +623,108 @@ Blockly.Msg["TUBE_SHOW_TOOLTIP"] = "顯示字串,不多於4個字符。"
Blockly.Msg["TUBE_SCROLL_TITLE"] = "%1滾動文本%2延時%3毫秒"
Blockly.Msg["TUBE_SCROLL_TOOLTIP"] = "按給定延時從右往左滾動顯示字串, 250毫秒對應每秒4幀。"
Blockly.Msg["TUBE_CLEAR_TITLE"] = "清空數碼管%1"
-Blockly.Msg["TUBE_CLEAR_TOOLTIP"] = "清空數碼管顯示的內容。"
\ No newline at end of file
+Blockly.Msg["TUBE_CLEAR_TOOLTIP"] = "清空數碼管顯示的內容。"
+Blockly.Msg["CAMERA_ENABLE_TITLE"] = "%1攝像頭"
+Blockly.Msg["CAMERA_ENABLE_ENABLE"] = "啟用"
+Blockly.Msg["CAMERA_ENABLE_STOP"] = "停用"
+Blockly.Msg["CAMERA_ENABLE_TOOLTIP"] = "啟用或停用攝像頭模塊。"
+Blockly.Msg["CAMERA_PREVIEW_TITLE"] = "%1預覽"
+Blockly.Msg["CAMERA_PREVIEW_OPEN"] = "打開"
+Blockly.Msg["CAMERA_PREVIEW_CLOSE"] = "關閉"
+Blockly.Msg["CAMERA_PREVIEW_TOOLTIP"] = "打開或關閉攝像頭預覽窗口。"
+Blockly.Msg["CAMERA_CAPTURE_TITLE"] = "拍攝照片%1.%2"
+Blockly.Msg["CAMERA_CAPTURE_TOOLTIP"] = "用攝像頭拍攝一張照片,以指定的格式保存在指定的路徑/文件名。"
+Blockly.Msg["CAMERA_RECORD_TITLE"] = "攝製視頻%1.h264"
+Blockly.Msg["CAMERA_RECORD_TOOLTIP"] = "用攝像頭開始拍攝視頻,以h264格式保存在指定的路徑/文件名。"
+Blockly.Msg["CAMERA_STOP_RECORDING_TITLE"] = "停止攝製視頻"
+Blockly.Msg["CAMERA_STOP_RECORDING_TOOLTIP"] = "停止拍攝視頻。"
+Blockly.Msg["CAMERA_WEB_STREAM_TITLE"] = "開始網絡視頻直播,端口:%1"
+Blockly.Msg["CAMERA_WEB_STREAM_TOOLTIP"] = "在你的樹莓派IP地址和指定端口開啟HTTP視頻直播流。使用任意瀏覽器或者視頻播放器打開鏈接http://樹莓派IP:端口/stream. mjpg來觀看直播。"
+Blockly.Msg["CAMERA_RESOLUTION_TITLE"] = "設置攝像頭分辨率%1x%2"
+Blockly.Msg["CAMERA_RESOLUTION_TOOLTIP"] = "設置拍照、錄像和預覽的分辨率。"
+Blockly.Msg["CAMERA_FLIP_TITLE"] = "%1翻轉攝像頭"
+Blockly.Msg["CAMERA_FLIP_H"] = "水平"
+Blockly.Msg["CAMERA_FLIP_V"] = "垂直"
+Blockly.Msg["CAMERA_FLIP_TOOLTIP"] = "設置是否水平/垂直翻轉攝像頭的輸出。"
+Blockly.Msg["CAMERA_ROTATE_TITLE"] = "旋轉攝像頭%1"
+Blockly.Msg["CAMERA_ROTATE_TOOLTIP"] = "設置當前攝像頭圖像的旋轉方向。"
+Blockly.Msg["CAMERA_FRAMERATE_TITLE"] = "設置攝像頭幀率%1"
+Blockly.Msg["CAMERA_FRAMERATE_TOOLTIP"] = "設置錄像和預覽的幀率(FPS)。"
+Blockly.Msg["CAMERA_ANNOTATE_TEXT_TITLE"] = "添加註釋文本%1"
+Blockly.Msg["CAMERA_ANNOTATE_TEXT_TOOLTIP"] = "為所有輸出添加一段註釋文本。只允許最多32個ASCII字符。"
+Blockly.Msg["CAMERA_ANNOTATE_SIZE_TITLE"] = "設置註釋大小%1"
+Blockly.Msg["CAMERA_ANNOTATE_SIZE_TOOLTIP"] = "設置註釋文本的字體大小。"
+Blockly.Msg["CAMERA_ANNOTATE_COLOUR_TITLE"] = "設置註釋%1顏色%2"
+Blockly.Msg["CAMERA_ANNOTATE_COLOUR_FOREGROUND"] = "文本"
+Blockly.Msg["CAMERA_ANNOTATE_COLOUR_BACKGROUND"] = "背景"
+Blockly.Msg["CAMERA_ANNOTATE_COLOUR_TOOLTIP"] = "設置註釋文本的亮度或者背景的顏色。"
+Blockly.Msg["CAMERA_ISO_TITLE"] = "設置ISO%1"
+Blockly.Msg["CAMERA_ISO_AUTO"] = "自動"
+Blockly.Msg["CAMERA_ISO_TOOLTIP"] = "設置攝像頭的ISO數值。"
+Blockly.Msg["CAMERA_SHUTTER_SPEED_TITLE"] = "設置快門速度%1微秒"
+Blockly.Msg["CAMERA_SHUTTER_SPEED_TOOLTIP"] = "設置攝像頭的快門速度,單位微秒。"
+Blockly.Msg["CAMERA_BRIGHTNESS_TITLE"] = "設置圖像亮度%1"
+Blockly.Msg["CAMERA_BRIGHTNESS_TOOLTIP"] = "設置攝像頭的亮度設置(0~100)。"
+Blockly.Msg["CAMERA_SHARPNESS_TITLE"] = "設置圖像銳度%1"
+Blockly.Msg["CAMERA_SHARPNESS_TOOLTIP"] = "設置攝像頭的銳度設置(-100~100)。"
+Blockly.Msg["CAMERA_CONTRAST_TITLE"] = "設置圖像對比度%1"
+Blockly.Msg["CAMERA_CONTRAST_TOOLTIP"] = "設置攝像頭的對比度設置(-100~100)。"
+Blockly.Msg["CAMERA_SATURATION_TITLE"] = "設置圖像飽和度%1"
+Blockly.Msg["CAMERA_SATURATION_TOOLTIP"] = "設置攝像頭的飽和度設置(-100~100)。"
+Blockly.Msg["CAMERA_AWB_MODE_TITLE"] = "設置自動白平衡模式%1"
+Blockly.Msg["CAMERA_AWB_MODE_AUTO"] = "自動"
+Blockly.Msg["CAMERA_AWB_MODE_SUNLIGHT"] = "日光"
+Blockly.Msg["CAMERA_AWB_MODE_CLOUDY"] = "多雲"
+Blockly.Msg["CAMERA_AWB_MODE_SHADE"] = "陰影"
+Blockly.Msg["CAMERA_AWB_MODE_TUNGSTEN"] = "鎢絲燈"
+Blockly.Msg["CAMERA_AWB_MODE_INCANDESCENT"] = "白熾燈"
+Blockly.Msg["CAMERA_AWB_MODE_FLUORESCENT"] = "熒光燈"
+Blockly.Msg["CAMERA_AWB_MODE_FLASH"] = "閃光燈"
+Blockly.Msg["CAMERA_AWB_MODE_HORIZON"] = "地平線"
+Blockly.Msg["CAMERA_AWB_MODE_TOOLTIP"] = "設置攝像頭的自動白平衡模式。"
+Blockly.Msg["CAMERA_EXPOSURE_COMPENSATION_TITLE"] = "設置曝光補償%1"
+Blockly.Msg["CAMERA_EXPOSURE_COMPENSATION_TOOLTIP"] = "設置攝像頭的曝光補償水平(-25~25)。"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_TITLE"] = "設置曝光模式%1"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_AUTO"] = "自動"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_NIGHT"] = "夜間"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_NIGHTPREVIEW"] = "夜間預覽"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_BACKLIGHT"] = "逆光"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_SPOTLIGHT"] = "聚光燈"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_SPORTS"] = "運動"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_SNOW"] = "雪景"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_BEACH"] = "沙灘"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_VERYLONG"] = "長曝光"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_FIXEDFPS"] = "固定幀率"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_ANTISHAKE"] = "防抖"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_FIREWORKS"] = "煙火"
+Blockly.Msg["CAMERA_EXPOSURE_MODE_TOOLTIP"] = "設置攝像頭的曝光模式。"
+Blockly.Msg["CAMERA_METER_MODE_TITLE"] = "設置測光模式%1"
+Blockly.Msg["CAMERA_METER_MODE_AVERAGE"] = "平均測光"
+Blockly.Msg["CAMERA_METER_MODE_SPOT"] = "點測光"
+Blockly.Msg["CAMERA_METER_MODE_BACKLIT"] = "模擬背光"
+Blockly.Msg["CAMERA_METER_MODE_MATRIX"] = "矩陣測光"
+Blockly.Msg["CAMERA_METER_MODE_TOOLTIP"] = "設置攝像頭的測光模式。"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_TITLE"] = "設置圖像特效%1"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_NONE"] = "無"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_NEGATIVE"] = "負片"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_SOLARIZE"] = "過曝"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_SKETCH"] = "素描"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_DENOISE"] = "降噪"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_EMBOSS"] = "浮雕"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_OILPAINT"] = "油畫"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_HATCH"] = "網格"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_GPEN"] = "G筆"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_PASTEL"] = "粉彩"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_WATERCOLOR"] = "水彩"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_FILM"] = "膠片"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_BLUR"] = "模糊"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_SATURATION"] = "飽和"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_COLORSWAP"] = "換色"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_WASHEDOUT"] = "沖刷"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_POSTERISE"] = "色彩分離"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_COLORPOINT"] = "重點色"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_COLORBALANCE"] = "色彩均衡"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_CARTOON"] = "卡通"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_DEINTERLACE1"] = "反交錯1"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_DEINTERLACE2"] = "反交錯2"
+Blockly.Msg["CAMERA_IMAGE_EFFECT_TOOLTIP"] = "設置攝像頭應用的圖像特效。"
\ No newline at end of file
diff --git a/BlockPi/src/msg/zh-hans.js b/BlockPi/src/msg/zh-hans.js
index ad430a5..2311bd4 100644
--- a/BlockPi/src/msg/zh-hans.js
+++ b/BlockPi/src/msg/zh-hans.js
@@ -28,6 +28,8 @@ var MSG = {
catGPIOin: "通用输入",
catGPIOout: "通用输出",
catTube: "数码管",
+ catPicamera: "摄像头",
+ catPicameraPro: "专业模式",
listVariable: "列表",
textVariable: "文本",
deviceVariable: "设备",
diff --git a/BlockPi/src/msg/zh-hant.js b/BlockPi/src/msg/zh-hant.js
index b75f026..520e4a7 100644
--- a/BlockPi/src/msg/zh-hant.js
+++ b/BlockPi/src/msg/zh-hant.js
@@ -28,6 +28,8 @@ var MSG = {
catGPIOin: "通用輸入",
catGPIOout: "通用輸出",
catTube: "數碼管",
+ catPicamera: "攝像頭",
+ catPicameraPro: "專業模式",
listVariable: "清單",
textVariable: "文字",
deviceVariable: "設備",
diff --git a/BlockPi/src/script/blocks_compressed.js b/BlockPi/src/script/blocks_compressed.js
index 3e5fed8..b79e891 100644
--- a/BlockPi/src/script/blocks_compressed.js
+++ b/BlockPi/src/script/blocks_compressed.js
@@ -2,7 +2,25 @@
'use strict';
-Blockly.Blocks.colour={};Blockly.Constants={};Blockly.Constants.Colour={};Blockly.Constants.Colour.HUE=20;
+Blockly.Blocks.camera={};Blockly.Constants={};Blockly.Constants.Camera={};Blockly.Constants.Camera.HUE=135;
+Blockly.defineBlocksWithJsonArray([{type:"camera_enable",message0:"%{BKY_CAMERA_ENABLE_TITLE}",args0:[{type:"field_dropdown",name:"DO",options:[["%{BKY_CAMERA_ENABLE_ENABLE}","ENABLE"],["%{BKY_CAMERA_ENABLE_STOP}","STOP"]]}],previousStatement:null,nextStatement:null,colour:"%{BKY_CAMERA_HUE}",tooltip:"%{BKY_CAMERA_ENABLE_TOOLTIP}",helpUrl:""},{type:"camera_preview",message0:"%{BKY_CAMERA_PREVIEW_TITLE}",args0:[{type:"field_dropdown",name:"DO",options:[["%{BKY_CAMERA_PREVIEW_OPEN}","START"],["%{BKY_CAMERA_PREVIEW_CLOSE}",
+"STOP"]]}],previousStatement:null,nextStatement:null,colour:"%{BKY_CAMERA_HUE}",tooltip:"%{BKY_CAMERA_PREVIEW_TOOLTIP}",helpUrl:""},{type:"camera_capture",message0:"%{BKY_CAMERA_CAPTURE_TITLE}",args0:[{type:"input_value",name:"NAME",check:"String"},{type:"field_dropdown",name:"TYPE",options:[["jpg","jpg"],["png","png"],["gif","gif"]]}],inputsInline:!0,previousStatement:null,nextStatement:null,colour:"%{BKY_CAMERA_HUE}",tooltip:"%{BKY_CAMERA_CAPTURE_TOOLTIP}",helpUrl:""},{type:"camera_record",message0:"%{BKY_CAMERA_RECORD_TITLE}",
+args0:[{type:"input_value",name:"NAME",check:"String"}],inputsInline:!0,previousStatement:null,nextStatement:null,colour:"%{BKY_CAMERA_HUE}",tooltip:"%{BKY_CAMERA_RECORD_TOOLTIP}",helpUrl:""},{type:"camera_stop_recording",message0:"%{BKY_CAMERA_STOP_RECORDING_TITLE}",inputsInline:!0,previousStatement:null,nextStatement:null,colour:"%{BKY_CAMERA_HUE}",tooltip:"%{BKY_CAMERA_STOP_RECORDING_TOOLTIP}",helpUrl:""},{type:"camera_web_stream",lastDummyAlign0:"RIGHT",message0:"%{BKY_CAMERA_WEB_STREAM_TITLE}",
+args0:[{type:"field_number",name:"PORT",value:8E3,min:0,max:65535,precision:1}],previousStatement:null,nextStatement:null,colour:"%{BKY_CAMERA_HUE}",tooltip:"%{BKY_CAMERA_WEB_STREAM_TOOLTIP}",helpUrl:""},{type:"camera_resolution",message0:"%{BKY_CAMERA_RESOLUTION_TITLE}",args0:[{type:"field_number",name:"W",value:1280,min:0,precision:1},{type:"field_number",name:"H",value:720,min:0,precision:1}],previousStatement:null,nextStatement:null,colour:"%{BKY_CAMERA_HUE}",tooltip:"%{BKY_CAMERA_RESOLUTION_TOOLTIP}",
+helpUrl:""},{type:"camera_flip",message0:"%{BKY_CAMERA_FLIP_TITLE}",args0:[{type:"field_dropdown",name:"FLIP",options:[["%{BKY_CAMERA_FLIP_H}","hflip"],["%{BKY_CAMERA_FLIP_V}","vflip"]]}],previousStatement:null,nextStatement:null,colour:"%{BKY_CAMERA_HUE}",tooltip:"%{BKY_CAMERA_FLIP_TOOLTIP}",helpUrl:""},{type:"camera_rotate",message0:"%{BKY_CAMERA_ROTATE_TITLE}",args0:[{type:"field_dropdown",name:"DEGREE",options:[["0\u00b0","0"],["90\u00b0","90"],["180\u00b0","180"],["270\u00b0","270"]]}],previousStatement:null,
+nextStatement:null,colour:"%{BKY_CAMERA_HUE}",tooltip:"%{BKY_CAMERA_ROTATE_TOOLTIP}",helpUrl:""},{type:"camera_framerate",message0:"%{BKY_CAMERA_FRAMERATE_TITLE}",args0:[{type:"field_number",name:"FPS",value:30,min:.1,max:90,precision:.1}],previousStatement:null,nextStatement:null,colour:"%{BKY_CAMERA_HUE}",tooltip:"%{BKY_CAMERA_FRAMERATE_TOOLTIP}",helpUrl:""},{type:"camera_annotate_text",message0:"%{BKY_CAMERA_ANNOTATE_TEXT_TITLE}",args0:[{type:"input_value",name:"TEXT",check:"String"}],previousStatement:null,
+nextStatement:null,colour:"%{BKY_CAMERA_HUE}",tooltip:"%{BKY_CAMERA_ANNOTATE_TEXT_TOOLTIP}",helpUrl:""},{type:"camera_annotate_size",message0:"%{BKY_CAMERA_ANNOTATE_SIZE_TITLE}",args0:[{type:"field_number",name:"SIZE",value:32,min:6,max:160,precision:1}],previousStatement:null,nextStatement:null,colour:"%{BKY_CAMERA_HUE}",tooltip:"%{BKY_CAMERA_ANNOTATE_SIZE_TOOLTIP}",helpUrl:""},{type:"camera_annotate_colour",message0:"%{BKY_CAMERA_ANNOTATE_COLOUR_TITLE}",args0:[{type:"field_dropdown",name:"PICK",
+options:[["%{BKY_CAMERA_ANNOTATE_COLOUR_FOREGROUND}","foreground"],["%{BKY_CAMERA_ANNOTATE_COLOUR_BACKGROUND}","background"]]},{type:"field_colour",name:"COLOUR",colour:"#ffffff"}],inputsInline:!0,previousStatement:null,nextStatement:null,colour:"%{BKY_CAMERA_HUE}",tooltip:"%{BKY_CAMERA_ANNOTATE_COLOUR_TOOLTIP}",helpUrl:""},{type:"camera_iso",message0:"%{BKY_CAMERA_ISO_TITLE}",args0:[{type:"field_dropdown",name:"VALUE",options:[["%{BKY_CAMERA_ISO_AUTO}","0"],["100","100"],["200","200"],["320","320"],
+["400","400"],["500","500"],["640","640"],["800","800"]]}],previousStatement:null,nextStatement:null,colour:"%{BKY_CAMERA_HUE}",tooltip:"%{BKY_CAMERA_ISO_TOOLTIP}",helpUrl:""},{type:"camera_shutter_speed",message0:"%{BKY_CAMERA_SHUTTER_SPEED_TITLE}",args0:[{type:"field_number",name:"VALUE",value:0,min:0,max:5E6,precision:1}],previousStatement:null,nextStatement:null,colour:"%{BKY_CAMERA_HUE}",tooltip:"%{BKY_CAMERA_SHUTTER_SPEED_TOOLTIP}",helpUrl:""},{type:"camera_brightness",message0:"%{BKY_CAMERA_BRIGHTNESS_TITLE}",
+args0:[{type:"field_number",name:"VALUE",value:50,min:0,max:100,precision:1}],previousStatement:null,nextStatement:null,colour:"%{BKY_CAMERA_HUE}",tooltip:"%{BKY_CAMERA_BRIGHTNESS_TOOLTIP}",helpUrl:""},{type:"camera_sharpness",message0:"%{BKY_CAMERA_SHARPNESS_TITLE}",args0:[{type:"field_number",name:"VALUE",value:0,min:-100,max:100,precision:1}],previousStatement:null,nextStatement:null,colour:"%{BKY_CAMERA_HUE}",tooltip:"%{BKY_CAMERA_SHARPNESS_TOOLTIP}",helpUrl:""},{type:"camera_contrast",message0:"%{BKY_CAMERA_CONTRAST_TITLE}",
+args0:[{type:"field_number",name:"VALUE",value:0,min:-100,max:100,precision:1}],previousStatement:null,nextStatement:null,colour:"%{BKY_CAMERA_HUE}",tooltip:"%{BKY_CAMERA_CONTRAST_TOOLTIP}",helpUrl:""},{type:"camera_saturation",message0:"%{BKY_CAMERA_SATURATION_TITLE}",args0:[{type:"field_number",name:"VALUE",value:0,min:-100,max:100,precision:1}],previousStatement:null,nextStatement:null,colour:"%{BKY_CAMERA_HUE}",tooltip:"%{BKY_CAMERA_SATURATION_TOOLTIP}",helpUrl:""},{type:"camera_awb_mode",message0:"%{BKY_CAMERA_AWB_MODE_TITLE}",
+args0:[{type:"field_dropdown",name:"MODE",options:[["%{BKY_CAMERA_AWB_MODE_AUTO}","auto"],["%{BKY_CAMERA_AWB_MODE_SUNLIGHT}","sunlight"],["%{BKY_CAMERA_AWB_MODE_CLOUDY}","cloudy"],["%{BKY_CAMERA_AWB_MODE_SHADE}","shade"],["%{BKY_CAMERA_AWB_MODE_TUNGSTEN}","tungsten"],["%{BKY_CAMERA_AWB_MODE_FLUORESCENT}","fluorescent"],["%{BKY_CAMERA_AWB_MODE_INCANDESCENT}","incandescent"],["%{BKY_CAMERA_AWB_MODE_FLASH}","flash"],["%{BKY_CAMERA_AWB_MODE_HORIZON}","horizon"]]}],previousStatement:null,nextStatement:null,
+colour:"%{BKY_CAMERA_HUE}",tooltip:"%{BKY_CAMERA_AWB_MODE_TOOLTIP}",helpUrl:""},{type:"camera_exposure_compensation",message0:"%{BKY_CAMERA_EXPOSURE_COMPENSATION_TITLE}",args0:[{type:"field_number",name:"VALUE",value:0,min:-25,max:25,precision:1}],previousStatement:null,nextStatement:null,colour:"%{BKY_CAMERA_HUE}",tooltip:"%{BKY_CAMERA_EXPOSURE_COMPENSATION_TOOLTIP}",helpUrl:""},{type:"camera_exposure_mode",message0:"%{BKY_CAMERA_EXPOSURE_MODE_TITLE}",args0:[{type:"field_dropdown",name:"MODE",options:[["%{BKY_CAMERA_EXPOSURE_MODE_AUTO}",
+"auto"],["%{BKY_CAMERA_EXPOSURE_MODE_NIGHT}","night"],["%{BKY_CAMERA_EXPOSURE_MODE_NIGHTPREVIEW}","nightpreview"],["%{BKY_CAMERA_EXPOSURE_MODE_BACKLIGHT}","backlight"],["%{BKY_CAMERA_EXPOSURE_MODE_SPOTLIGHT}","spotlight"],["%{BKY_CAMERA_EXPOSURE_MODE_SPORTS}","sports"],["%{BKY_CAMERA_EXPOSURE_MODE_SNOW}","snow"],["%{BKY_CAMERA_EXPOSURE_MODE_BEACH}","beach"],["%{BKY_CAMERA_EXPOSURE_MODE_VERYLONG}","verylong"],["%{BKY_CAMERA_EXPOSURE_MODE_FIXEDFPS}","fixedfps"],["%{BKY_CAMERA_EXPOSURE_MODE_ANTISHAKE}",
+"antishake"],["%{BKY_CAMERA_EXPOSURE_MODE_FIREWORKS}","fireworks"]]}],previousStatement:null,nextStatement:null,colour:"%{BKY_CAMERA_HUE}",tooltip:"%{BKY_CAMERA_EXPOSURE_MODE_TOOLTIP}",helpUrl:""},{type:"camera_meter_mode",message0:"%{BKY_CAMERA_METER_MODE_TITLE}",args0:[{type:"field_dropdown",name:"MODE",options:[["%{BKY_CAMERA_METER_MODE_AVERAGE}","average"],["%{BKY_CAMERA_METER_MODE_SPOT}","spot"],["%{BKY_CAMERA_METER_MODE_BACKLIT}","backlit"],["%{BKY_CAMERA_METER_MODE_MATRIX}","matrix"]]}],previousStatement:null,
+nextStatement:null,colour:"%{BKY_CAMERA_HUE}",tooltip:"%{BKY_CAMERA_METER_MODE_TOOLTIP}",helpUrl:""},{type:"camera_image_effect",message0:"%{BKY_CAMERA_IMAGE_EFFECT_TITLE}",args0:[{type:"field_dropdown",name:"MODE",options:[["%{BKY_CAMERA_IMAGE_EFFECT_NONE}","none"],["%{BKY_CAMERA_IMAGE_EFFECT_NEGATIVE}","negative"],["%{BKY_CAMERA_IMAGE_EFFECT_SOLARIZE}","solarize"],["%{BKY_CAMERA_IMAGE_EFFECT_SKETCH}","sketch"],["%{BKY_CAMERA_IMAGE_EFFECT_DENOISE}","denoise"],["%{BKY_CAMERA_IMAGE_EFFECT_EMBOSS}",
+"emboss"],["%{BKY_CAMERA_IMAGE_EFFECT_OILPAINT}","oilpaint"],["%{BKY_CAMERA_IMAGE_EFFECT_HATCH}","hatch"],["%{BKY_CAMERA_IMAGE_EFFECT_GPEN}","gpen"],["%{BKY_CAMERA_IMAGE_EFFECT_PASTEL}","pastel"],["%{BKY_CAMERA_IMAGE_EFFECT_WATERCOLOR}","watercolor"],["%{BKY_CAMERA_IMAGE_EFFECT_FILM}","film"],["%{BKY_CAMERA_IMAGE_EFFECT_BLUR}","blur"],["%{BKY_CAMERA_IMAGE_EFFECT_SATURATION}","saturation"],["%{BKY_CAMERA_IMAGE_EFFECT_COLORSWAP}","colorswap"],["%{BKY_CAMERA_IMAGE_EFFECT_WASHEDOUT}","washedout"],["%{BKY_CAMERA_IMAGE_EFFECT_POSTERISE}",
+"posterise"],["%{BKY_CAMERA_IMAGE_EFFECT_COLORPOINT}","colorpoint"],["%{BKY_CAMERA_IMAGE_EFFECT_COLORBALANCE}","colorbalance"],["%{BKY_CAMERA_IMAGE_EFFECT_CARTOON}","cartoon"],["%{BKY_CAMERA_IMAGE_EFFECT_DEINTERLACE1}","deinterlace1"],["%{BKY_CAMERA_IMAGE_EFFECT_DEINTERLACE2}","deinterlace2"]]}],previousStatement:null,nextStatement:null,colour:"%{BKY_CAMERA_HUE}",tooltip:"%{BKY_CAMERA_IMAGE_EFFECT_TOOLTIP}",helpUrl:""}]);Blockly.Blocks.colour={};Blockly.Constants.Colour={};Blockly.Constants.Colour.HUE=20;
Blockly.defineBlocksWithJsonArray([{type:"colour_picker",message0:"%1",args0:[{type:"field_colour",name:"COLOUR",colour:"#ff0000"}],output:"Colour",helpUrl:"%{BKY_COLOUR_PICKER_HELPURL}",style:"colour_blocks",tooltip:"%{BKY_COLOUR_PICKER_TOOLTIP}",extensions:["parent_tooltip_when_inline"]},{type:"colour_random",message0:"%{BKY_COLOUR_RANDOM_TITLE}",output:"Colour",helpUrl:"%{BKY_COLOUR_RANDOM_HELPURL}",style:"colour_blocks",tooltip:"%{BKY_COLOUR_RANDOM_TOOLTIP}"},{type:"colour_rgb",message0:"%{BKY_COLOUR_RGB_TITLE} %{BKY_COLOUR_RGB_RED} %1 %{BKY_COLOUR_RGB_GREEN} %2 %{BKY_COLOUR_RGB_BLUE} %3",
args0:[{type:"input_value",name:"RED",check:"Number",align:"RIGHT"},{type:"input_value",name:"GREEN",check:"Number",align:"RIGHT"},{type:"input_value",name:"BLUE",check:"Number",align:"RIGHT"}],output:"Colour",helpUrl:"%{BKY_COLOUR_RGB_HELPURL}",style:"colour_blocks",tooltip:"%{BKY_COLOUR_RGB_TOOLTIP}"},{type:"colour_blend",message0:"%{BKY_COLOUR_BLEND_TITLE} %{BKY_COLOUR_BLEND_COLOUR1} %1 %{BKY_COLOUR_BLEND_COLOUR2} %2 %{BKY_COLOUR_BLEND_RATIO} %3",args0:[{type:"input_value",name:"COLOUR1",check:"Colour",
align:"RIGHT"},{type:"input_value",name:"COLOUR2",check:"Colour",align:"RIGHT"},{type:"input_value",name:"RATIO",check:"Number",align:"RIGHT"}],output:"Colour",helpUrl:"%{BKY_COLOUR_BLEND_HELPURL}",style:"colour_blocks",tooltip:"%{BKY_COLOUR_BLEND_TOOLTIP}"},{type:"colour_convert",message0:"%{BKY_COLOUR_CONVERT_TITLE}",args0:[{type:"input_value",name:"COLOUR",check:"Colour"}],inputsInline:!0,output:"Array",helpUrl:"",style:"colour_blocks",tooltip:"%{BKY_COLOUR_CONVERT_TOOLTIP}"}]);Blockly.Blocks.dictionaries={};Blockly.Constants.Dictionaries={};Blockly.Constants.Dictionaries.HUE=275;
diff --git a/BlockPi/src/script/python_compressed.js b/BlockPi/src/script/python_compressed.js
index ff92ca8..c6c8fe3 100644
--- a/BlockPi/src/script/python_compressed.js
+++ b/BlockPi/src/script/python_compressed.js
@@ -2,7 +2,7 @@
'use strict';
-Blockly.Python=new Blockly.Generator("Python");Blockly.Python.addReservedWords("False,None,True,and,as,assert,break,class,continue,def,del,elif,else,except,exec,finally,for,from,global,if,import,in,is,lambda,nonlocal,not,or,pass,print,raise,return,try,while,with,yield,NotImplemented,Ellipsis,__debug__,quit,exit,copyright,license,credits,ArithmeticError,AssertionError,AttributeError,BaseException,BlockingIOError,BrokenPipeError,BufferError,BytesWarning,ChildProcessError,ConnectionAbortedError,ConnectionError,ConnectionRefusedError,ConnectionResetError,DeprecationWarning,EOFError,Ellipsis,EnvironmentError,Exception,FileExistsError,FileNotFoundError,FloatingPointError,FutureWarning,GeneratorExit,IOError,ImportError,ImportWarning,IndentationError,IndexError,InterruptedError,IsADirectoryError,KeyError,KeyboardInterrupt,LookupError,MemoryError,ModuleNotFoundError,NameError,NotADirectoryError,NotImplemented,NotImplementedError,OSError,OverflowError,PendingDeprecationWarning,PermissionError,ProcessLookupError,RecursionError,ReferenceError,ResourceWarning,RuntimeError,RuntimeWarning,StandardError,StopAsyncIteration,StopIteration,SyntaxError,SyntaxWarning,SystemError,SystemExit,TabError,TimeoutError,TypeError,UnboundLocalError,UnicodeDecodeError,UnicodeEncodeError,UnicodeError,UnicodeTranslateError,UnicodeWarning,UserWarning,ValueError,Warning,ZeroDivisionError,_,__build_class__,__debug__,__doc__,__import__,__loader__,__name__,__package__,__spec__,abs,all,any,apply,ascii,basestring,bin,bool,buffer,bytearray,bytes,callable,chr,classmethod,cmp,coerce,compile,complex,copyright,credits,delattr,dict,dir,divmod,enumerate,eval,exec,execfile,exit,file,filter,float,format,frozenset,getattr,globals,hasattr,hash,help,hex,id,input,int,intern,isinstance,issubclass,iter,len,license,list,locals,long,map,max,memoryview,min,next,object,oct,open,ord,pow,print,property,quit,range,raw_input,reduce,reload,repr,reversed,round,set,setattr,slice,sorted,staticmethod,str,sum,super,tuple,type,unichr,unicode,vars,xrange,ziptime,gpiozero,tm1637,sense_hat,sense_emu,SenseHat,sense,event");
+Blockly.Python=new Blockly.Generator("Python");Blockly.Python.addReservedWords("False,None,True,and,as,assert,break,class,continue,def,del,elif,else,except,exec,finally,for,from,global,if,import,in,is,lambda,nonlocal,not,or,pass,print,raise,return,try,while,with,yield,NotImplemented,Ellipsis,__debug__,quit,exit,copyright,license,credits,ArithmeticError,AssertionError,AttributeError,BaseException,BlockingIOError,BrokenPipeError,BufferError,BytesWarning,ChildProcessError,ConnectionAbortedError,ConnectionError,ConnectionRefusedError,ConnectionResetError,DeprecationWarning,EOFError,Ellipsis,EnvironmentError,Exception,FileExistsError,FileNotFoundError,FloatingPointError,FutureWarning,GeneratorExit,IOError,ImportError,ImportWarning,IndentationError,IndexError,InterruptedError,IsADirectoryError,KeyError,KeyboardInterrupt,LookupError,MemoryError,ModuleNotFoundError,NameError,NotADirectoryError,NotImplemented,NotImplementedError,OSError,OverflowError,PendingDeprecationWarning,PermissionError,ProcessLookupError,RecursionError,ReferenceError,ResourceWarning,RuntimeError,RuntimeWarning,StandardError,StopAsyncIteration,StopIteration,SyntaxError,SyntaxWarning,SystemError,SystemExit,TabError,TimeoutError,TypeError,UnboundLocalError,UnicodeDecodeError,UnicodeEncodeError,UnicodeError,UnicodeTranslateError,UnicodeWarning,UserWarning,ValueError,Warning,ZeroDivisionError,_,__build_class__,__debug__,__doc__,__import__,__loader__,__name__,__package__,__spec__,abs,all,any,apply,ascii,basestring,bin,bool,buffer,bytearray,bytes,callable,chr,classmethod,cmp,coerce,compile,complex,copyright,credits,delattr,dict,dir,divmod,enumerate,eval,exec,execfile,exit,file,filter,float,format,frozenset,getattr,globals,hasattr,hash,help,hex,id,input,int,intern,isinstance,issubclass,iter,len,license,list,locals,long,map,max,memoryview,min,next,object,oct,open,ord,pow,print,property,quit,range,raw_input,reduce,reload,repr,reversed,round,set,setattr,slice,sorted,staticmethod,str,sum,super,tuple,type,unichr,unicode,vars,xrange,ziptime,gpiozero,tm1637,sense_hat,sense_emu,SenseHat,sense,event,camera,Picamera,Color,picamera");
Blockly.Python.ORDER_ATOMIC=0;Blockly.Python.ORDER_COLLECTION=1;Blockly.Python.ORDER_STRING_CONVERSION=1;Blockly.Python.ORDER_MEMBER=2.1;Blockly.Python.ORDER_FUNCTION_CALL=2.2;Blockly.Python.ORDER_EXPONENTIATION=3;Blockly.Python.ORDER_UNARY_SIGN=4;Blockly.Python.ORDER_BITWISE_NOT=4;Blockly.Python.ORDER_MULTIPLICATIVE=5;Blockly.Python.ORDER_ADDITIVE=6;Blockly.Python.ORDER_BITWISE_SHIFT=7;Blockly.Python.ORDER_BITWISE_AND=8;Blockly.Python.ORDER_BITWISE_XOR=9;Blockly.Python.ORDER_BITWISE_OR=10;
Blockly.Python.ORDER_RELATIONAL=11;Blockly.Python.ORDER_LOGICAL_NOT=12;Blockly.Python.ORDER_LOGICAL_AND=13;Blockly.Python.ORDER_LOGICAL_OR=14;Blockly.Python.ORDER_CONDITIONAL=15;Blockly.Python.ORDER_LAMBDA=16;Blockly.Python.ORDER_NONE=99;
Blockly.Python.ORDER_OVERRIDES=[[Blockly.Python.ORDER_FUNCTION_CALL,Blockly.Python.ORDER_MEMBER],[Blockly.Python.ORDER_FUNCTION_CALL,Blockly.Python.ORDER_FUNCTION_CALL],[Blockly.Python.ORDER_MEMBER,Blockly.Python.ORDER_MEMBER],[Blockly.Python.ORDER_MEMBER,Blockly.Python.ORDER_FUNCTION_CALL],[Blockly.Python.ORDER_LOGICAL_NOT,Blockly.Python.ORDER_LOGICAL_NOT],[Blockly.Python.ORDER_LOGICAL_AND,Blockly.Python.ORDER_LOGICAL_AND],[Blockly.Python.ORDER_LOGICAL_OR,Blockly.Python.ORDER_LOGICAL_OR]];
@@ -11,7 +11,19 @@ Blockly.Python.init=function(a){Blockly.Python.PASS=this.INDENT+"pass\n";Blockly
Blockly.Python.finish=function(a){var b=[],c=[],d;for(d in Blockly.Python.definitions_){var e=Blockly.Python.definitions_[d];e.match(/^(from\s+\S+\s+)?import\s+\S+/)?b.push(e):c.push(e)}delete Blockly.Python.definitions_;delete Blockly.Python.functionNames_;Blockly.Python.variableDB_.reset();return(b.join("\n")+"\n\n"+c.join("\n\n")).replace(/\n\n+/g,"\n\n").replace(/\n*$/,"\n\n\n")+a};Blockly.Python.scrubNakedValue=function(a){return a+"\n"};
Blockly.Python.quote_=function(a){a=a.replace(/\\/g,"\\\\").replace(/\n/g,"\\\n");var b="'";-1!==a.indexOf("'")&&(-1===a.indexOf('"')?b='"':a=a.replace(/'/g,"\\'"));return b+a+b};Blockly.Python.multiline_quote_=function(a){a=a.replace(/'''/g,"\\'\\'\\'");return"'''"+a+"'''"};
Blockly.Python.scrub_=function(a,b,c){var d="";if(!a.outputConnection||!a.outputConnection.targetConnection){var e=a.getCommentText();e&&(e=Blockly.utils.string.wrap(e,Blockly.Python.COMMENT_WRAP-3),d+=Blockly.Python.prefixLines(e+"\n","# "));for(var f=0;fc?"int("+a+" - "+-c+")":"int("+a+")",d&&(a="-"+a));return a};Blockly.Python.colour={};Blockly.Python.colour_picker=function(a){return[Blockly.Python.quote_(a.getFieldValue("COLOUR")),Blockly.Python.ORDER_ATOMIC]};Blockly.Python.colour_random=function(a){Blockly.Python.definitions_.import_random="import random";return["'#%06x' % random.randint(0, 2**24 - 1)",Blockly.Python.ORDER_FUNCTION_CALL]};
+c?"":Blockly.Python.blockToCode(a);return d+b+c};Blockly.Python.getAdjustedInt=function(a,b,c,d){c=c||0;a.workspace.options.oneBasedIndex&&c--;var e=a.workspace.options.oneBasedIndex?"1":"0";a=Blockly.Python.valueToCode(a,b,c?Blockly.Python.ORDER_ADDITIVE:Blockly.Python.ORDER_NONE)||e;Blockly.isNumber(a)?(a=parseInt(a,10)+c,d&&(a=-a)):(a=0c?"int("+a+" - "+-c+")":"int("+a+")",d&&(a="-"+a));return a};Blockly.Python.camera={};Blockly.Python.camera_enable=function(a){a=a.getFieldValue("DO");if("ENABLE"==a)return Blockly.Python.definitions_.from_picamera_import_PiCamera="from picamera import PiCamera","camera = PiCamera()\n";if("STOP"==a)return"camera.close()\n"};Blockly.Python.camera_preview=function(a){a=a.getFieldValue("DO");if("START"==a)return"camera.start_preview(fullscreen=False, window=(0,0,800,600))\n";if("STOP"==a)return"camera.stop_preview()\n"};
+Blockly.Python.camera_capture=function(a){var b=Blockly.Python.valueToCode(a,"NAME",Blockly.Python.ORDER_NONE);a=a.getFieldValue("TYPE");return"camera.capture("+b+"+'."+a+"')\n"};Blockly.Python.camera_record=function(a){return"camera.start_recording("+Blockly.Python.valueToCode(a,"NAME",Blockly.Python.ORDER_ATOMIC)+"+'.h264')\n"};Blockly.Python.camera_stop_recording=function(a){return"camera.stop_recording()\n"};
+Blockly.Python.camera_web_stream=function(a){Blockly.Python.definitions_.import_io="import io";Blockly.Python.definitions_.import_logging="import logging";Blockly.Python.definitions_.import_socketserver="import socketserver";Blockly.Python.definitions_.from_threading_import_Condition="from threading import Condition";Blockly.Python.definitions_.from_http_import_server="from http import server";var b=Blockly.Python.provideFunction_("picamera_webstream",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+
+"(camera, port):"," class StreamingOutput(object):"," def __init__(self):"," self.frame = None"," self.buffer = io.BytesIO()"," self.condition = Condition()"," def write(self, buf):"," if buf.startswith(b'\\xff\\xd8'):"," self.buffer.truncate()"," with self.condition:"," self.frame = self.buffer.getvalue()"," self.condition.notify_all()"," self.buffer.seek(0)"," return self.buffer.write(buf)",""," class StreamingHandler(server.BaseHTTPRequestHandler):",
+" def do_GET(self):"," if self.path == '/stream.mjpg':"," self.send_response(200)"," self.send_header('Age', 0)"," self.send_header('Cache-Control', 'no-cache, private')"," self.send_header('Pragma', 'no-cache')"," self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')"," self.end_headers()"," try:"," while True:"," with output.condition:"," output.condition.wait()"," frame = output.frame",
+" self.wfile.write(b'--FRAME\\r\\n')"," self.send_header('Content-Type', 'image/jpeg')"," self.send_header('Content-Length', len(frame))"," self.end_headers()"," self.wfile.write(frame)"," self.wfile.write(b'\\r\\n')"," except Exception as e:"," logging.warning('Removed streaming client %s: %s', self.client_address, str(e))"," else:"," self.send_error(404)"," self.end_headers()",""," class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):",
+" allow_reuse_address = True"," daemon_threads = True",""," output = StreamingOutput()"," camera.start_recording(output, format='mjpeg')"," try:"," piserver = StreamingServer(('', port), StreamingHandler)"," piserver.serve_forever()"," finally:"," camera.stop_recording()"," camera.close()"]);a=a.getFieldValue("PORT");return b+"(camera, "+a+")\n"};
+Blockly.Python.camera_resolution=function(a){var b=a.getFieldValue("W");a=a.getFieldValue("H");return"camera.resolution = ("+b+", "+a+")\n"};Blockly.Python.camera_flip=function(a){return"camera."+a.getFieldValue("FLIP")+" = True\n"};Blockly.Python.camera_rotate=function(a){return"camera.rotation = "+a.getFieldValue("DEGREE")+"\n"};Blockly.Python.camera_framerate=function(a){return"camera.framerate = "+a.getFieldValue("FPS")+"\n"};
+Blockly.Python.camera_annotate_text=function(a){return"camera.annotate_text = "+(Blockly.Python.valueToCode(a,"TEXT",Blockly.Python.ORDER_NONE)||"''")+"\n"};Blockly.Python.camera_annotate_size=function(a){return"camera.annotate_size = "+a.getFieldValue("SIZE")+"\n"};
+Blockly.Python.camera_annotate_colour=function(a){Blockly.Python.definitions_.from_picamera_import_Color="from picamera import Color";var b=a.getFieldValue("PICK");a=Blockly.Python.quote_(a.getFieldValue("COLOUR"));return"camera.annotate_"+b+" = Color("+a+")\n"};Blockly.Python.camera_iso=function(a){return"camera.iso = "+a.getFieldValue("VALUE")+"\n"};Blockly.Python.camera_shutter_speed=function(a){return"camera.shutter_speed = "+a.getFieldValue("VALUE")+"\n"};
+Blockly.Python.camera_brightness=function(a){return"camera.brightness = "+a.getFieldValue("VALUE")+"\n"};Blockly.Python.camera_sharpness=function(a){return"camera.sharpness = "+a.getFieldValue("VALUE")+"\n"};Blockly.Python.camera_contrast=function(a){return"camera.contrast = "+a.getFieldValue("VALUE")+"\n"};Blockly.Python.camera_saturation=function(a){return"camera.saturation = "+a.getFieldValue("VALUE")+"\n"};
+Blockly.Python.camera_awb_mode=function(a){return"camera.awb_mode = "+Blockly.Python.quote_(a.getFieldValue("MODE"))+"\n"};Blockly.Python.camera_exposure_compensation=function(a){return"camera.exposure_compensation = "+a.getFieldValue("VALUE")+"\n"};Blockly.Python.camera_exposure_mode=function(a){return"camera.exposure_mode = "+Blockly.Python.quote_(a.getFieldValue("MODE"))+"\n"};
+Blockly.Python.camera_meter_mode=function(a){return"camera.meter_mode = "+Blockly.Python.quote_(a.getFieldValue("MODE"))+"\n"};Blockly.Python.camera_image_effect=function(a){return"camera.image_effect = "+Blockly.Python.quote_(a.getFieldValue("MODE"))+"\n"};Blockly.Python.colour={};Blockly.Python.colour_picker=function(a){return[Blockly.Python.quote_(a.getFieldValue("COLOUR")),Blockly.Python.ORDER_ATOMIC]};Blockly.Python.colour_random=function(a){Blockly.Python.definitions_.import_random="import random";return["'#%06x' % random.randint(0, 2**24 - 1)",Blockly.Python.ORDER_FUNCTION_CALL]};
Blockly.Python.colour_rgb=function(a){var b=Blockly.Python.provideFunction_("colour_rgb",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(r, g, b):"," r = round(min(100, max(0, r)) * 2.55)"," g = round(min(100, max(0, g)) * 2.55)"," b = round(min(100, max(0, b)) * 2.55)"," return '#%02x%02x%02x' % (r, g, b)"]),c=Blockly.Python.valueToCode(a,"RED",Blockly.Python.ORDER_NONE)||0,d=Blockly.Python.valueToCode(a,"GREEN",Blockly.Python.ORDER_NONE)||0;a=Blockly.Python.valueToCode(a,"BLUE",Blockly.Python.ORDER_NONE)||
0;return[b+"("+c+", "+d+", "+a+")",Blockly.Python.ORDER_FUNCTION_CALL]};
Blockly.Python.colour_blend=function(a){var b=Blockly.Python.provideFunction_("colour_blend",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(colour1, colour2, ratio):"," r1, r2 = int(colour1[1:3], 16), int(colour2[1:3], 16)"," g1, g2 = int(colour1[3:5], 16), int(colour2[3:5], 16)"," b1, b2 = int(colour1[5:7], 16), int(colour2[5:7], 16)"," ratio = min(1, max(0, ratio))"," r = round(r1 * (1 - ratio) + r2 * ratio)"," g = round(g1 * (1 - ratio) + g2 * ratio)"," b = round(b1 * (1 - ratio) + b2 * ratio)",
diff --git a/README.md b/README.md
index a03b41c..deb8e47 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@ A visual programming editor app for [Raspberry Pi](https://www.raspberry.org), b
- 完整的Blockly移植到树莓派上,完全免费使用。Full Blockly features on RPi, free to use.
-- 集成树莓派GPIO控制,支持[Sense HAT](https://www.raspberrypi.org/products/sense-hat/),未来支持更多树莓派外设和功能。Build-in GPIO control and [Sense HAT]([https://www.raspberrypi.org/products/sense-hat/) support, and more functions in the future.
+- 集成树莓派GPIO控制,支持[Sense HAT](https://www.raspberrypi.org/products/sense-hat/)和CSI摄像头,未来支持更多树莓派外设和功能。Build-in GPIO control, [Sense HAT]([https://www.raspberrypi.org/products/sense-hat/) and CSI Picamera support, and more functions in the future.
- 程序可直接在应用内运行,同时可转化成Python代码,方便学习Python。Code runs in the app, and can be convert to Python. Helpful to learn Python.
@@ -39,7 +39,7 @@ If not, please make sure your Linux-based RPi system have Nodejs v12+ and Python
- 或者使用用终端命令:Or you can use command in shell:
```shell
-sudo dpkg -i blockpi_1.0.2_armv7l.deb
+sudo dpkg -i blockpi_1.1.3_armv7l.deb
```
注意自己的文件名。Pay attention to your file name.
@@ -72,7 +72,7 @@ to install them and then try the dpkg command again.
```shell
sudo apt update
-sudo apt install python3-gpiozero sense-hat python3-sense-emu sense-emu-tools
+sudo apt install python3-gpiozero sense-hat python3-sense-emu sense-emu-tools python3-picamera
```
### Windows x64
@@ -128,7 +128,7 @@ yarn build:generator
yarn start
```
-打包发行Win x64版本/Pack and build Win x64 version:
+打包发行Windows版本/Pack and build Windows version:
```shell
yarn dist:win
diff --git a/blocks/camera.js b/blocks/camera.js
new file mode 100644
index 0000000..9b4c334
--- /dev/null
+++ b/blocks/camera.js
@@ -0,0 +1,728 @@
+'use strict';
+
+goog.provide('Blockly.Blocks.camera'); // Deprecated.
+goog.provide('Blockly.Constants.Camera');
+
+Blockly.Constants.Camera.HUE = 135;
+
+Blockly.defineBlocksWithJsonArray(
+ [{
+ "type": "camera_enable",
+ "message0": "%{BKY_CAMERA_ENABLE_TITLE}",
+ "args0": [
+ {
+ "type": "field_dropdown",
+ "name": "DO",
+ "options": [
+ [
+ "%{BKY_CAMERA_ENABLE_ENABLE}",
+ "ENABLE"
+ ],
+ [
+ "%{BKY_CAMERA_ENABLE_STOP}",
+ "STOP"
+ ]
+ ]
+ }
+ ],
+ "previousStatement": null,
+ "nextStatement": null,
+ "colour": "%{BKY_CAMERA_HUE}",
+ "tooltip": "%{BKY_CAMERA_ENABLE_TOOLTIP}",
+ "helpUrl": ""
+ },
+ {
+ "type": "camera_preview",
+ "message0": "%{BKY_CAMERA_PREVIEW_TITLE}",
+ "args0": [
+ {
+ "type": "field_dropdown",
+ "name": "DO",
+ "options": [
+ [
+ "%{BKY_CAMERA_PREVIEW_OPEN}",
+ "START"
+ ],
+ [
+ "%{BKY_CAMERA_PREVIEW_CLOSE}",
+ "STOP"
+ ]
+ ]
+ }
+ ],
+ "previousStatement": null,
+ "nextStatement": null,
+ "colour": "%{BKY_CAMERA_HUE}",
+ "tooltip": "%{BKY_CAMERA_PREVIEW_TOOLTIP}",
+ "helpUrl": ""
+ },
+ {
+ "type": "camera_capture",
+ "message0": "%{BKY_CAMERA_CAPTURE_TITLE}",
+ "args0": [
+ {
+ "type": "input_value",
+ "name": "NAME",
+ "check": "String"
+ },
+ {
+ "type": "field_dropdown",
+ "name": "TYPE",
+ "options": [
+ [
+ "jpg",
+ "jpg"
+ ],
+ [
+ "png",
+ "png"
+ ],
+ [
+ "gif",
+ "gif"
+ ]
+ ]
+ }
+ ],
+ "inputsInline": true,
+ "previousStatement": null,
+ "nextStatement": null,
+ "colour": "%{BKY_CAMERA_HUE}",
+ "tooltip": "%{BKY_CAMERA_CAPTURE_TOOLTIP}",
+ "helpUrl": ""
+ },
+ {
+ "type": "camera_record",
+ "message0": "%{BKY_CAMERA_RECORD_TITLE}",
+ "args0": [
+ {
+ "type": "input_value",
+ "name": "NAME",
+ "check": "String"
+ }
+ ],
+ "inputsInline": true,
+ "previousStatement": null,
+ "nextStatement": null,
+ "colour": "%{BKY_CAMERA_HUE}",
+ "tooltip": "%{BKY_CAMERA_RECORD_TOOLTIP}",
+ "helpUrl": ""
+ },
+ {
+ "type": "camera_stop_recording",
+ "message0": "%{BKY_CAMERA_STOP_RECORDING_TITLE}",
+ "inputsInline": true,
+ "previousStatement": null,
+ "nextStatement": null,
+ "colour": "%{BKY_CAMERA_HUE}",
+ "tooltip": "%{BKY_CAMERA_STOP_RECORDING_TOOLTIP}",
+ "helpUrl": ""
+ },
+ {
+ "type": "camera_web_stream",
+ "lastDummyAlign0": "RIGHT",
+ "message0": "%{BKY_CAMERA_WEB_STREAM_TITLE}",
+ "args0": [
+ {
+ "type": "field_number",
+ "name": "PORT",
+ "value": 8000,
+ "min": 0,
+ "max": 65535,
+ "precision": 1
+ }
+ ],
+ "previousStatement": null,
+ "nextStatement": null,
+ "colour": "%{BKY_CAMERA_HUE}",
+ "tooltip": "%{BKY_CAMERA_WEB_STREAM_TOOLTIP}",
+ "helpUrl": ""
+ },
+ {
+ "type": "camera_resolution",
+ "message0": "%{BKY_CAMERA_RESOLUTION_TITLE}",
+ "args0": [
+ {
+ "type": "field_number",
+ "name": "W",
+ "value": 1280,
+ "min": 0,
+ "precision": 1
+ },
+ {
+ "type": "field_number",
+ "name": "H",
+ "value": 720,
+ "min": 0,
+ "precision": 1
+ }
+ ],
+ "previousStatement": null,
+ "nextStatement": null,
+ "colour": "%{BKY_CAMERA_HUE}",
+ "tooltip": "%{BKY_CAMERA_RESOLUTION_TOOLTIP}",
+ "helpUrl": ""
+ },
+ {
+ "type": "camera_flip",
+ "message0": "%{BKY_CAMERA_FLIP_TITLE}",
+ "args0": [
+ {
+ "type": "field_dropdown",
+ "name": "FLIP",
+ "options": [
+ [
+ "%{BKY_CAMERA_FLIP_H}",
+ "hflip"
+ ],
+ [
+ "%{BKY_CAMERA_FLIP_V}",
+ "vflip"
+ ]
+ ]
+ }
+ ],
+ "previousStatement": null,
+ "nextStatement": null,
+ "colour": "%{BKY_CAMERA_HUE}",
+ "tooltip": "%{BKY_CAMERA_FLIP_TOOLTIP}",
+ "helpUrl": ""
+ },
+ {
+ "type": "camera_rotate",
+ "message0": "%{BKY_CAMERA_ROTATE_TITLE}",
+ "args0": [
+ {
+ "type": "field_dropdown",
+ "name": "DEGREE",
+ "options": [
+ [
+ "0°",
+ "0"
+ ],
+ [
+ "90°",
+ "90"
+ ],
+ [
+ "180°",
+ "180"
+ ],
+ [
+ "270°",
+ "270"
+ ]
+ ]
+ }
+ ],
+ "previousStatement": null,
+ "nextStatement": null,
+ "colour": "%{BKY_CAMERA_HUE}",
+ "tooltip": "%{BKY_CAMERA_ROTATE_TOOLTIP}",
+ "helpUrl": ""
+ },
+ {
+ "type": "camera_framerate",
+ "message0": "%{BKY_CAMERA_FRAMERATE_TITLE}",
+ "args0": [
+ {
+ "type": "field_number",
+ "name": "FPS",
+ "value": 30,
+ "min": 0.1,
+ "max": 90,
+ "precision": 0.1
+ }
+ ],
+ "previousStatement": null,
+ "nextStatement": null,
+ "colour": "%{BKY_CAMERA_HUE}",
+ "tooltip": "%{BKY_CAMERA_FRAMERATE_TOOLTIP}",
+ "helpUrl": ""
+ },
+ {
+ "type": "camera_annotate_text",
+ "message0": "%{BKY_CAMERA_ANNOTATE_TEXT_TITLE}",
+ "args0": [
+ {
+ "type": "input_value",
+ "name": "TEXT",
+ "check": "String"
+ }
+ ],
+ "previousStatement": null,
+ "nextStatement": null,
+ "colour": "%{BKY_CAMERA_HUE}",
+ "tooltip": "%{BKY_CAMERA_ANNOTATE_TEXT_TOOLTIP}",
+ "helpUrl": ""
+ },
+ {
+ "type": "camera_annotate_size",
+ "message0": "%{BKY_CAMERA_ANNOTATE_SIZE_TITLE}",
+ "args0": [
+ {
+ "type": "field_number",
+ "name": "SIZE",
+ "value": 32,
+ "min": 6,
+ "max": 160,
+ "precision": 1
+ }
+ ],
+ "previousStatement": null,
+ "nextStatement": null,
+ "colour": "%{BKY_CAMERA_HUE}",
+ "tooltip": "%{BKY_CAMERA_ANNOTATE_SIZE_TOOLTIP}",
+ "helpUrl": ""
+ },
+ {
+ "type": "camera_annotate_colour",
+ "message0": "%{BKY_CAMERA_ANNOTATE_COLOUR_TITLE}",
+ "args0": [
+ {
+ "type": "field_dropdown",
+ "name": "PICK",
+ "options": [
+ [
+ "%{BKY_CAMERA_ANNOTATE_COLOUR_FOREGROUND}",
+ "foreground"
+ ],
+ [
+ "%{BKY_CAMERA_ANNOTATE_COLOUR_BACKGROUND}",
+ "background"
+ ]
+ ]
+ },
+ {
+ "type": "field_colour",
+ "name": "COLOUR",
+ "colour": "#ffffff"
+ }
+ ],
+ "inputsInline": true,
+ "previousStatement": null,
+ "nextStatement": null,
+ "colour": "%{BKY_CAMERA_HUE}",
+ "tooltip": "%{BKY_CAMERA_ANNOTATE_COLOUR_TOOLTIP}",
+ "helpUrl": ""
+ },
+ {
+ "type": "camera_iso",
+ "message0": "%{BKY_CAMERA_ISO_TITLE}",
+ "args0": [
+ {
+ "type": "field_dropdown",
+ "name": "VALUE",
+ "options": [
+ [
+ "%{BKY_CAMERA_ISO_AUTO}",
+ "0"
+ ],
+ [
+ "100",
+ "100"
+ ],
+ [
+ "200",
+ "200"
+ ],
+ [
+ "320",
+ "320"
+ ],
+ [
+ "400",
+ "400"
+ ],
+ [
+ "500",
+ "500"
+ ],
+ [
+ "640",
+ "640"
+ ],
+ [
+ "800",
+ "800"
+ ]
+ ]
+ }
+ ],
+ "previousStatement": null,
+ "nextStatement": null,
+ "colour": "%{BKY_CAMERA_HUE}",
+ "tooltip": "%{BKY_CAMERA_ISO_TOOLTIP}",
+ "helpUrl": ""
+ },
+ {
+ "type": "camera_shutter_speed",
+ "message0": "%{BKY_CAMERA_SHUTTER_SPEED_TITLE}",
+ "args0": [
+ {
+ "type": "field_number",
+ "name": "VALUE",
+ "value": 0,
+ "min": 0,
+ "max": 5000000,
+ "precision": 1
+ }
+ ],
+ "previousStatement": null,
+ "nextStatement": null,
+ "colour": "%{BKY_CAMERA_HUE}",
+ "tooltip": "%{BKY_CAMERA_SHUTTER_SPEED_TOOLTIP}",
+ "helpUrl": ""
+ },
+ {
+ "type": "camera_brightness",
+ "message0": "%{BKY_CAMERA_BRIGHTNESS_TITLE}",
+ "args0": [
+ {
+ "type": "field_number",
+ "name": "VALUE",
+ "value": 50,
+ "min": 0,
+ "max": 100,
+ "precision": 1
+ }
+ ],
+ "previousStatement": null,
+ "nextStatement": null,
+ "colour": "%{BKY_CAMERA_HUE}",
+ "tooltip": "%{BKY_CAMERA_BRIGHTNESS_TOOLTIP}",
+ "helpUrl": ""
+ },
+ {
+ "type": "camera_sharpness",
+ "message0": "%{BKY_CAMERA_SHARPNESS_TITLE}",
+ "args0": [
+ {
+ "type": "field_number",
+ "name": "VALUE",
+ "value": 0,
+ "min": -100,
+ "max": 100,
+ "precision": 1
+ }
+ ],
+ "previousStatement": null,
+ "nextStatement": null,
+ "colour": "%{BKY_CAMERA_HUE}",
+ "tooltip": "%{BKY_CAMERA_SHARPNESS_TOOLTIP}",
+ "helpUrl": ""
+ },
+ {
+ "type": "camera_contrast",
+ "message0": "%{BKY_CAMERA_CONTRAST_TITLE}",
+ "args0": [
+ {
+ "type": "field_number",
+ "name": "VALUE",
+ "value": 0,
+ "min": -100,
+ "max": 100,
+ "precision": 1
+ }
+ ],
+ "previousStatement": null,
+ "nextStatement": null,
+ "colour": "%{BKY_CAMERA_HUE}",
+ "tooltip": "%{BKY_CAMERA_CONTRAST_TOOLTIP}",
+ "helpUrl": ""
+ },
+ {
+ "type": "camera_saturation",
+ "message0": "%{BKY_CAMERA_SATURATION_TITLE}",
+ "args0": [
+ {
+ "type": "field_number",
+ "name": "VALUE",
+ "value": 0,
+ "min": -100,
+ "max": 100,
+ "precision": 1
+ }
+ ],
+ "previousStatement": null,
+ "nextStatement": null,
+ "colour": "%{BKY_CAMERA_HUE}",
+ "tooltip": "%{BKY_CAMERA_SATURATION_TOOLTIP}",
+ "helpUrl": ""
+ },
+ {
+ "type": "camera_awb_mode",
+ "message0": "%{BKY_CAMERA_AWB_MODE_TITLE}",
+ "args0": [
+ {
+ "type": "field_dropdown",
+ "name": "MODE",
+ "options": [
+ [
+ "%{BKY_CAMERA_AWB_MODE_AUTO}",
+ "auto"
+ ],
+ [
+ "%{BKY_CAMERA_AWB_MODE_SUNLIGHT}",
+ "sunlight"
+ ],
+ [
+ "%{BKY_CAMERA_AWB_MODE_CLOUDY}",
+ "cloudy"
+ ],
+ [
+ "%{BKY_CAMERA_AWB_MODE_SHADE}",
+ "shade"
+ ],
+ [
+ "%{BKY_CAMERA_AWB_MODE_TUNGSTEN}",
+ "tungsten"
+ ],
+ [
+ "%{BKY_CAMERA_AWB_MODE_FLUORESCENT}",
+ "fluorescent"
+ ],
+ [
+ "%{BKY_CAMERA_AWB_MODE_INCANDESCENT}",
+ "incandescent"
+ ],
+ [
+ "%{BKY_CAMERA_AWB_MODE_FLASH}",
+ "flash"
+ ],
+ [
+ "%{BKY_CAMERA_AWB_MODE_HORIZON}",
+ "horizon"
+ ]
+ ]
+ }
+ ],
+ "previousStatement": null,
+ "nextStatement": null,
+ "colour": "%{BKY_CAMERA_HUE}",
+ "tooltip": "%{BKY_CAMERA_AWB_MODE_TOOLTIP}",
+ "helpUrl": ""
+ },
+ {
+ "type": "camera_exposure_compensation",
+ "message0": "%{BKY_CAMERA_EXPOSURE_COMPENSATION_TITLE}",
+ "args0": [
+ {
+ "type": "field_number",
+ "name": "VALUE",
+ "value": 0,
+ "min": -25,
+ "max": 25,
+ "precision": 1
+ }
+ ],
+ "previousStatement": null,
+ "nextStatement": null,
+ "colour": "%{BKY_CAMERA_HUE}",
+ "tooltip": "%{BKY_CAMERA_EXPOSURE_COMPENSATION_TOOLTIP}",
+ "helpUrl": ""
+ },
+ {
+ "type": "camera_exposure_mode",
+ "message0": "%{BKY_CAMERA_EXPOSURE_MODE_TITLE}",
+ "args0": [
+ {
+ "type": "field_dropdown",
+ "name": "MODE",
+ "options": [
+ [
+ "%{BKY_CAMERA_EXPOSURE_MODE_AUTO}",
+ "auto"
+ ],
+ [
+ "%{BKY_CAMERA_EXPOSURE_MODE_NIGHT}",
+ "night"
+ ],
+ [
+ "%{BKY_CAMERA_EXPOSURE_MODE_NIGHTPREVIEW}",
+ "nightpreview"
+ ],
+ [
+ "%{BKY_CAMERA_EXPOSURE_MODE_BACKLIGHT}",
+ "backlight"
+ ],
+ [
+ "%{BKY_CAMERA_EXPOSURE_MODE_SPOTLIGHT}",
+ "spotlight"
+ ],
+ [
+ "%{BKY_CAMERA_EXPOSURE_MODE_SPORTS}",
+ "sports"
+ ],
+ [
+ "%{BKY_CAMERA_EXPOSURE_MODE_SNOW}",
+ "snow"
+ ],
+ [
+ "%{BKY_CAMERA_EXPOSURE_MODE_BEACH}",
+ "beach"
+ ],
+ [
+ "%{BKY_CAMERA_EXPOSURE_MODE_VERYLONG}",
+ "verylong"
+ ],
+ [
+ "%{BKY_CAMERA_EXPOSURE_MODE_FIXEDFPS}",
+ "fixedfps"
+ ],
+ [
+ "%{BKY_CAMERA_EXPOSURE_MODE_ANTISHAKE}",
+ "antishake"
+ ],
+ [
+ "%{BKY_CAMERA_EXPOSURE_MODE_FIREWORKS}",
+ "fireworks"
+ ]
+ ]
+ }
+ ],
+ "previousStatement": null,
+ "nextStatement": null,
+ "colour": "%{BKY_CAMERA_HUE}",
+ "tooltip": "%{BKY_CAMERA_EXPOSURE_MODE_TOOLTIP}",
+ "helpUrl": ""
+ },
+ {
+ "type": "camera_meter_mode",
+ "message0": "%{BKY_CAMERA_METER_MODE_TITLE}",
+ "args0": [
+ {
+ "type": "field_dropdown",
+ "name": "MODE",
+ "options": [
+ [
+ "%{BKY_CAMERA_METER_MODE_AVERAGE}",
+ "average"
+ ],
+ [
+ "%{BKY_CAMERA_METER_MODE_SPOT}",
+ "spot"
+ ],
+ [
+ "%{BKY_CAMERA_METER_MODE_BACKLIT}",
+ "backlit"
+ ],
+ [
+ "%{BKY_CAMERA_METER_MODE_MATRIX}",
+ "matrix"
+ ]
+ ]
+ }
+ ],
+ "previousStatement": null,
+ "nextStatement": null,
+ "colour": "%{BKY_CAMERA_HUE}",
+ "tooltip": "%{BKY_CAMERA_METER_MODE_TOOLTIP}",
+ "helpUrl": ""
+ },
+ {
+ "type": "camera_image_effect",
+ "message0": "%{BKY_CAMERA_IMAGE_EFFECT_TITLE}",
+ "args0": [
+ {
+ "type": "field_dropdown",
+ "name": "MODE",
+ "options": [
+ [
+ "%{BKY_CAMERA_IMAGE_EFFECT_NONE}",
+ "none"
+ ],
+ [
+ "%{BKY_CAMERA_IMAGE_EFFECT_NEGATIVE}",
+ "negative"
+ ],
+ [
+ "%{BKY_CAMERA_IMAGE_EFFECT_SOLARIZE}",
+ "solarize"
+ ],
+ [
+ "%{BKY_CAMERA_IMAGE_EFFECT_SKETCH}",
+ "sketch"
+ ],
+ [
+ "%{BKY_CAMERA_IMAGE_EFFECT_DENOISE}",
+ "denoise"
+ ],
+ [
+ "%{BKY_CAMERA_IMAGE_EFFECT_EMBOSS}",
+ "emboss"
+ ],
+ [
+ "%{BKY_CAMERA_IMAGE_EFFECT_OILPAINT}",
+ "oilpaint"
+ ],
+ [
+ "%{BKY_CAMERA_IMAGE_EFFECT_HATCH}",
+ "hatch"
+ ],
+ [
+ "%{BKY_CAMERA_IMAGE_EFFECT_GPEN}",
+ "gpen"
+ ],
+ [
+ "%{BKY_CAMERA_IMAGE_EFFECT_PASTEL}",
+ "pastel"
+ ],
+ [
+ "%{BKY_CAMERA_IMAGE_EFFECT_WATERCOLOR}",
+ "watercolor"
+ ],
+ [
+ "%{BKY_CAMERA_IMAGE_EFFECT_FILM}",
+ "film"
+ ],
+ [
+ "%{BKY_CAMERA_IMAGE_EFFECT_BLUR}",
+ "blur"
+ ],
+ [
+ "%{BKY_CAMERA_IMAGE_EFFECT_SATURATION}",
+ "saturation"
+ ],
+ [
+ "%{BKY_CAMERA_IMAGE_EFFECT_COLORSWAP}",
+ "colorswap"
+ ],
+ [
+ "%{BKY_CAMERA_IMAGE_EFFECT_WASHEDOUT}",
+ "washedout"
+ ],
+ [
+ "%{BKY_CAMERA_IMAGE_EFFECT_POSTERISE}",
+ "posterise"
+ ],
+ [
+ "%{BKY_CAMERA_IMAGE_EFFECT_COLORPOINT}",
+ "colorpoint"
+ ],
+ [
+ "%{BKY_CAMERA_IMAGE_EFFECT_COLORBALANCE}",
+ "colorbalance"
+ ],
+ [
+ "%{BKY_CAMERA_IMAGE_EFFECT_CARTOON}",
+ "cartoon"
+ ],
+ [
+ "%{BKY_CAMERA_IMAGE_EFFECT_DEINTERLACE1}",
+ "deinterlace1"
+ ],
+ [
+ "%{BKY_CAMERA_IMAGE_EFFECT_DEINTERLACE2}",
+ "deinterlace2"
+ ]
+ ]
+ }
+ ],
+ "previousStatement": null,
+ "nextStatement": null,
+ "colour": "%{BKY_CAMERA_HUE}",
+ "tooltip": "%{BKY_CAMERA_IMAGE_EFFECT_TOOLTIP}",
+ "helpUrl": ""
+ }]
+);
diff --git a/build/release-notes.md b/build/release-notes.md
index 390fdb8..af7f836 100644
--- a/build/release-notes.md
+++ b/build/release-notes.md
@@ -1,3 +1,8 @@
+# 1.1.3
+
+Add a new category of Picamera blocks.\
+新增摄像头积木模块。
+
# 1.1.2
Add a new category of digital tube blocks.\
diff --git a/generators/python.js b/generators/python.js
index de3be6a..3ed10fa 100644
--- a/generators/python.js
+++ b/generators/python.js
@@ -80,7 +80,7 @@ Blockly.Python.addReservedWords(
'next,object,oct,open,ord,pow,print,property,quit,range,raw_input,reduce,' +
'reload,repr,reversed,round,set,setattr,slice,sorted,staticmethod,str,' +
'sum,super,tuple,type,unichr,unicode,vars,xrange,zip' +
- 'time,gpiozero,tm1637,sense_hat,sense_emu,SenseHat,sense,event'
+ 'time,gpiozero,tm1637,sense_hat,sense_emu,SenseHat,sense,event,camera,Picamera,Color,picamera'
);
/**
diff --git a/generators/python/camera.js b/generators/python/camera.js
new file mode 100644
index 0000000..89207f8
--- /dev/null
+++ b/generators/python/camera.js
@@ -0,0 +1,199 @@
+'use strict';
+
+goog.provide('Blockly.Python.camera');
+
+goog.require('Blockly.Python');
+
+Blockly.Python['camera_enable'] = function (block) {
+ var dropdown_do = block.getFieldValue('DO');
+ if (dropdown_do == 'ENABLE') {
+ Blockly.Python.definitions_['from_picamera_import_PiCamera'] = 'from picamera import PiCamera';
+ return 'camera = PiCamera()\n';
+ } else if (dropdown_do == 'STOP') {
+ return 'camera.close()\n';
+ }
+};
+
+Blockly.Python['camera_preview'] = function(block) {
+ var dropdown_do = block.getFieldValue('DO');
+ if (dropdown_do == 'START') {
+ return 'camera.start_preview(fullscreen=False, window=(0,0,800,600))\n';
+ } else if (dropdown_do == 'STOP') {
+ return 'camera.stop_preview()\n';
+ }
+};
+
+Blockly.Python['camera_capture'] = function(block) {
+ var name = Blockly.Python.valueToCode(block, 'NAME', Blockly.Python.ORDER_NONE);
+ var type = block.getFieldValue('TYPE');
+ return 'camera.capture(' + name + '+\'.' + type + '\')\n';
+};
+
+Blockly.Python['camera_record'] = function(block) {
+ var name = Blockly.Python.valueToCode(block, 'NAME', Blockly.Python.ORDER_ATOMIC);
+ return 'camera.start_recording(' + name + '+\'.h264\'' + ')\n';
+};
+
+Blockly.Python['camera_stop_recording'] = function(block) {
+ return 'camera.stop_recording()\n';
+};
+
+Blockly.Python['camera_web_stream'] = function (block) {
+ Blockly.Python.definitions_['import_io'] = 'import io';
+ Blockly.Python.definitions_['import_logging'] = 'import logging';
+ Blockly.Python.definitions_['import_socketserver'] = 'import socketserver';
+ Blockly.Python.definitions_['from_threading_import_Condition'] = 'from threading import Condition';
+ Blockly.Python.definitions_['from_http_import_server'] = 'from http import server';
+ var functionName = Blockly.Python.provideFunction_(
+ 'picamera_webstream',
+ ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(camera, port):',
+ ' class StreamingOutput(object):',
+ ' def __init__(self):',
+ ' self.frame = None',
+ ' self.buffer = io.BytesIO()',
+ ' self.condition = Condition()',
+ ' def write(self, buf):',
+ ' if buf.startswith(b\'\\xff\\xd8\'):',
+ ' self.buffer.truncate()',
+ ' with self.condition:',
+ ' self.frame = self.buffer.getvalue()',
+ ' self.condition.notify_all()',
+ ' self.buffer.seek(0)',
+ ' return self.buffer.write(buf)',
+ '',
+ ' class StreamingHandler(server.BaseHTTPRequestHandler):',
+ ' def do_GET(self):',
+ ' if self.path == \'/stream.mjpg\':',
+ ' self.send_response(200)',
+ ' self.send_header(\'Age\', 0)',
+ ' self.send_header(\'Cache-Control\', \'no-cache, private\')',
+ ' self.send_header(\'Pragma\', \'no-cache\')',
+ ' self.send_header(\'Content-Type\', \'multipart/x-mixed-replace; boundary=FRAME\')',
+ ' self.end_headers()',
+ ' try:',
+ ' while True:',
+ ' with output.condition:',
+ ' output.condition.wait()',
+ ' frame = output.frame',
+ ' self.wfile.write(b\'--FRAME\\r\\n\')',
+ ' self.send_header(\'Content-Type\', \'image/jpeg\')',
+ ' self.send_header(\'Content-Length\', len(frame))',
+ ' self.end_headers()',
+ ' self.wfile.write(frame)',
+ ' self.wfile.write(b\'\\r\\n\')',
+ ' except Exception as e:',
+ ' logging.warning(\'Removed streaming client %s: %s\', self.client_address, str(e))',
+ ' else:',
+ ' self.send_error(404)',
+ ' self.end_headers()',
+ '',
+ ' class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):',
+ ' allow_reuse_address = True',
+ ' daemon_threads = True',
+ '',
+ ' output = StreamingOutput()',
+ ' camera.start_recording(output, format=\'mjpeg\')',
+ ' try:',
+ ' piserver = StreamingServer((\'\', port), StreamingHandler)',
+ ' piserver.serve_forever()',
+ ' finally:',
+ ' camera.stop_recording()',
+ ' camera.close()'
+ ]
+ );
+ var port = block.getFieldValue('PORT');
+ return functionName + '(camera, ' + port + ')\n';
+};
+
+Blockly.Python['camera_resolution'] = function(block) {
+ var w = block.getFieldValue('W');
+ var h = block.getFieldValue('H');
+ return 'camera.resolution = (' + w + ', ' + h + ')\n';
+};
+
+Blockly.Python['camera_flip'] = function(block) {
+ var flip = block.getFieldValue('FLIP');
+ return 'camera.' + flip + ' = True\n';
+};
+
+Blockly.Python['camera_rotate'] = function(block) {
+ var degree = block.getFieldValue('DEGREE');
+ return 'camera.rotation = ' + degree + '\n';
+};
+
+Blockly.Python['camera_framerate'] = function(block) {
+ var fps = block.getFieldValue('FPS');
+ return 'camera.framerate = ' + fps + '\n';
+};
+
+Blockly.Python['camera_annotate_text'] = function(block) {
+ var text = Blockly.Python.valueToCode(block, 'TEXT', Blockly.Python.ORDER_NONE) || '\'\'';
+ return 'camera.annotate_text = ' + text + '\n';
+};
+
+Blockly.Python['camera_annotate_size'] = function(block) {
+ var size = block.getFieldValue('SIZE');
+ return 'camera.annotate_size = ' + size + '\n';
+};
+
+Blockly.Python['camera_annotate_colour'] = function (block) {
+ Blockly.Python.definitions_['from_picamera_import_Color'] = 'from picamera import Color';
+ var pick = block.getFieldValue('PICK');
+ var colour = Blockly.Python.quote_(block.getFieldValue('COLOUR'));
+ return 'camera.annotate_' + pick + ' = Color(' + colour + ')\n';
+};
+
+Blockly.Python['camera_iso'] = function(block) {
+ var value = block.getFieldValue('VALUE');
+ return 'camera.iso = ' + value + '\n';
+};
+
+Blockly.Python['camera_shutter_speed'] = function(block) {
+ var value = block.getFieldValue('VALUE');
+ return 'camera.shutter_speed = ' + value + '\n';
+};
+
+Blockly.Python['camera_brightness'] = function(block) {
+ var value = block.getFieldValue('VALUE');
+ return 'camera.brightness = ' + value + '\n';
+};
+
+Blockly.Python['camera_sharpness'] = function(block) {
+ var value = block.getFieldValue('VALUE');
+ return 'camera.sharpness = ' + value + '\n';
+};
+
+Blockly.Python['camera_contrast'] = function(block) {
+ var value = block.getFieldValue('VALUE');
+ return 'camera.contrast = ' + value + '\n';
+};
+
+Blockly.Python['camera_saturation'] = function(block) {
+ var value = block.getFieldValue('VALUE');
+ return 'camera.saturation = ' + value + '\n';
+};
+
+Blockly.Python['camera_awb_mode'] = function(block) {
+ var mode = Blockly.Python.quote_(block.getFieldValue('MODE'));
+ return 'camera.awb_mode = ' + mode + '\n';
+};
+
+Blockly.Python['camera_exposure_compensation'] = function(block) {
+ var value = block.getFieldValue('VALUE');
+ return 'camera.exposure_compensation = ' + value + '\n';
+};
+
+Blockly.Python['camera_exposure_mode'] = function(block) {
+ var mode = Blockly.Python.quote_(block.getFieldValue('MODE'));
+ return 'camera.exposure_mode = ' + mode + '\n';
+};
+
+Blockly.Python['camera_meter_mode'] = function(block) {
+ var mode = Blockly.Python.quote_(block.getFieldValue('MODE'));
+ return 'camera.meter_mode = ' + mode + '\n';
+};
+
+Blockly.Python['camera_image_effect'] = function(block) {
+ var mode = Blockly.Python.quote_(block.getFieldValue('MODE'));
+ return 'camera.image_effect = ' + mode + '\n';
+};
\ No newline at end of file
diff --git a/package.json b/package.json
index 12bfda8..bffaf17 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "blockpi",
- "version": "1.1.2",
+ "version": "1.1.3",
"description": "A visual programming editor for Raspberry Pi",
"main": "BlockPi/main.js",
"scripts": {
@@ -92,7 +92,8 @@
"python3-gpiozero",
"sense-hat",
"python3-sense-emu",
- "sense-emu-tools"
+ "sense-emu-tools",
+ "python3-picamera"
]
}
}