Azure functionsでpngを返す

var d3 = require('d3');
var fabric = require('fabric').fabric;
const {
    JSDOM
} = require('jsdom')
const fs = require('fs');

module.exports = async function (context, req) {
    

    var canvas = new fabric.Canvas('test_canvas');
    canvas.setWidth(500);
    canvas.setHeight(500);

    const document = new JSDOM().window.document
    datasets = [{
            date: "2020-04-01T07:07:14.150Z",
            value: 101
        },
        {
            date: "2020-04-01T07:08:24.150Z",
            value: 108
        },
        {
            date: "2020-04-01T07:09:34.150Z",
            value: 99
        },
        {
            date: "2020-04-01T07:10:44.150Z",
            value: 110
        },
        {
            date: "2020-04-01T07:11:54.150Z",
            value: 100
        },
        {
            date: "2020-04-01T07:12:14.150Z",
            value: 149
        },
        {
            date: "2020-04-01T07:13:24.150Z",
            value: 80
        },
        {
            date: "2020-04-01T07:14:34.150Z",
            value: 100
        },
        {
            date: "2020-04-01T07:15:44.150Z",
            value: 110
        },
        {
            date: "2020-04-01T07:16:54.150Z",
            value: 117
        },
        {
            date: "2020-04-01T07:17:14.150Z",
            value: 112
        },
        {
            date: "2020-04-01T07:18:24.150Z",
            value: 101
        },
        {
            date: "2020-04-01T07:19:34.150Z",
            value: 111
        },
        {
            date: "2020-04-01T07:20:44.150Z",
            value: 107
        },
        {
            date: "2020-04-01T07:21:54.150Z",
            value: 108
        },

    ]



    var w = 400; // 幅 (マージン部分は除く)
    var h = 300; // 高さ (マージン部分は除く)
    var margin = {
        left: 50,
        top: 20,
        bottom: 50,
        right: 20
    };


    // x軸の目盛りの表示フォーマット
    let format = d3.timeFormat("%H:%M");

    datasets = datasets.map(function (d) {
        let timeparser = d3.timeParse("%Y-%m-%dT%H:%M:%S.%LZ");
        // 日付のデータをパース
        return {
            date: timeparser(d.date),
            value: d.value
        };
    });

    // (a) svg 要素の追加
    var g = d3.select(document.body).append('svg')
        .attr('xmlns', 'http://www.w3.org/2000/svg')
        .attr('width', w + margin.left + margin.right) // svg 要素の幅
        .attr('height', h + margin.top + margin.bottom) // svg 要素の高さ
        .append('g')
        .attr('fill', 'none')
        .attr('transform', `translate(${margin.left}, ${margin.top})`);

    // (b) スケールの定義
    var x = d3.scaleTime()
        // 最小値と最大値を指定しX軸の領域を設定する
        .domain([
            // データ内の日付の最小値を取得
            d3.min(datasets, function (d) {
                return d.date;
            }),
            // データ内の日付の最大値を取得
            d3.max(datasets, function (d) {
                return d.date;
            })
        ])
        .range([0, w]);

    var y = d3.scaleLinear().range([0, h]).domain([
        // 0を最小値として設定
        // データ内のvalueの最大値を取得
        d3.max(datasets, function (d) {
            return d.value;
        }),
        0
    ]);


    // (c) 軸の定義
    let xTicks = 6;
    var xAxis = d3.axisBottom(x)
        // グラフの目盛りの数を設定
        .ticks(xTicks)
        // 目盛りの表示フォーマットを設定
        .tickFormat(format);
    var yAxis = d3.axisLeft(y)
        .tickSize(0)
        .tickFormat(function (d) {
            if (d < 1000) return d;
            else return d / 1000 + "K"
        });

    // (d1) 横軸の追加
    g.append('g')
        .attr('transform', `translate(0, ${h})`)
        .call(xAxis)


    // (d2) 縦軸の追加
    g.append('g')
        .call(yAxis)
        .append('text') // 縦軸のラベル
        .attr('transform', 'rotate(-90)')

    // 折れ線の作成関数
    var createLine = d3.line()
        // lineのX軸をセット
        .x(function (d) {
            return x(d.date);
        })
        // lineのY軸をセット
        .y(function (d) {
            return y(d.value);
        })
        // カーブを設定
        .curve(d3.curveCatmullRom.alpha(0.4));

    // (e) 折れ線の追加
    g.append('path')
        .attr('d', createLine(datasets))
        .attr('stroke', 'rgb(133, 167, 204)')
        .attr('fill', 'rgb(133, 167, 204)')
        .attr("stroke-dashoffset", 0)
        .attr("stroke-dasharray", 0)
        .attr('stroke-width', '2')
        .datum(datasets);

    var svg_t = document.body.innerHTML;

    fabric.loadSVGFromString(svg_t, function (objects, options) {
        var obj, stream;

        obj = fabric.util.groupSVGElements(objects, options);
        canvas.add(obj).renderAll();
        stream = canvas.createPNGStream();
        const dest = fs.createWriteStream(
                __dirname + "/dest.png"
              );

        let buffs =[];
        stream.on('data', function (chunk) {
            buffs.push(chunk);
            dest.write(chunk);
        });

        stream.on('end', function () {
            dest.end()
            context.res = {
                status: 200,
                body: Buffer.concat(buffs),
                "headers": {
                    "Content-Type": "image/png"
                }
            };
        });
    });

        
};

pythonでseleniumを動かすときにハマったこと

chromedriverのpathが間違っていた

selenium.common.exceptions.WebDriverException: Message: '' executable may have wrong permissions. Please see https://sites.google.com/a/chromium.org/chromedriver/home

options.add_argument("--disable-dev-shm-usage")を追加し回避

selenium.common.exceptions.WebDriverException: Message: unknown error: Chrome failed to start: exited abnormally.
  (unknown error: DevToolsActivePort file doesn't exist)
  (The process started from chrome location /usr/bin/google-chrome is no longer running, so ChromeDriver is assuming that Chrome has crashed.)

最終的なコード
chromedriverは同じフォルダーにおいている

import time
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import os


options =  Options();
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
driver = webdriver.Chrome(executable_path=os.getcwd() +"/chromedriver", options=options)
driver.get('https://www.google.com/')
time.sleep(5)
search_box = driver.find_element_by_name("q")
search_box.send_keys('ChromeDriver')
search_box.submit()
time.sleep(5)
driver.quit()

CandidateListを取得する

IMEのCandidateListを取得する方法

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApp1
{
    /// <summary>
    /// Interaction logic for Page3.xaml
    /// </summary>
    public partial class Page3 : Page
    {
        public Page3()
        {
            InitializeComponent();
        }
        public class Win32
        {

            [DllImport("user32.dll")]
            public static extern IntPtr DefWindowProc(IntPtr hWnd, uint Msg, uint wParam, IntPtr lPara);


            [DllImport("imm32.dll", SetLastError = true)]
            public static extern IntPtr ImmGetContext(IntPtr hWnd);

            [DllImport("Imm32.dll")]
            public static extern long ImmReleaseContext(IntPtr hWnd, IntPtr hIMC);


            [DllImport("imm32.dll")]
            public static extern int ImmGetCandidateList(IntPtr hIMC, int iIndex, byte[] lpCandidateList, int iBuffLen);

            [DllImport("Imm32.dll")]
            public static extern int ImmNotifyIME(IntPtr hIMC, IntPtr dwAction, IntPtr dwIndex, IntPtr dwValue);

        }

        const int WM_APP = 0x8000;
        const int WM_CLOSE = 0x0010;

        const int GWL_WNDPROC = -4;

        //  WM_IME_

        const int WM_IME_CHAR = 0x0286;
        const int WM_IME_COMPOSITION = 0x010f;
        const int WM_IME_COMPOSITIONFULL = 0x0284;
        const int WM_IME_CONTROL = 0x0283;
        const int WM_IME_ENDCOMPOSITION = 0x010e;
        const int WM_IME_KEYDOWN = 0x0290;
        //  const int WM_IME_KEYLAST = 0x010f;
        const int WM_IME_KEYUP = 0x0291;
        const int WM_IME_NOTIFY = 0x0282;
        const int WM_IME_REPORT = 0x0280;
        const int WM_IME_REQUEST = 0x0288;
        const int WM_IME_SELECT = 0x0285;
        const int WM_IME_SETCONTEXT = 0x0281;
        const int WM_IME_STARTCOMPOSITION = 0x010d;

        //  WM_IME_SETCONTEXT lParam

        const int ISC_SHOWUICOMPOSITIONWINDOW = -2147483648;
        const int ISC_SHOWUIGUIDWINDOW = -2147483648;
        const int ISC_SHOWUISOFTKBD = -2147483648;
        const int ISC_SHOWUICANDIDATEWINDOW = 0x0001;
        const int ISC_SHOWUIALLCANDIDATEWINDOW = 0x000F;

        //  WM_IME_NOTIFY  wParam

        const int IMN_CHANGECANDIDATE = 0x0003;
        const int IMN_OPENCANDIDATE = 0x0005;
        const int IMN_SETCONVERSIONMODE = 0x0006;
        const int IMN_SETOPENSTATUS = 0x0008;
        const int IMN_SETCOMPOSITIONFONT = 0x000A;    // 10
        const int IMN_SETCOMPOSITIONWINDOW = 0x000B;  // 11

        const int GCS_COMPSTR = 0x0008;
        const int GCS_RESULTSTR = 0x0800;
        const int GCS_RESULTREADSTR = 0x0200;
        const int GCS_COMPREADSTR = 0x0001;

        //  ImmNotifyIMe  dwAction

        const int NI_CHANGECANDIDATELIST = 0x0013; //  現在選択している候補を変更した ( dwIndex:変更リストのインデックス  dwValue:使わない)                                                 (dwIndex:変更リストのインデックス
        const int NI_CLOSECANDIDATE = 0x0011;       //候補リストをクローズした  (dwValue:使わない)
        const int NI_COMPOSITIONSTR = 0x0015;   //   変換文字列を操作する (具体的な操作はdwIndexで指定する)
        const int NI_IMEMENUSELECTED = 0x0018;   //  指定のメニューのハンドル (dwIndex:メニューID dwValue:アプリケーション定義の値)
        const int NI_OPENCANDIDATE = 0x0010;     // 候補リストをオープン
        const int NI_SELECTCANDIDATESTR = 0x0012;  // 候補の一つを選択した (dwIndex:候補リストのインデックス  dwValue:選択した単語のインデックス)
        const int NI_SETCANDIDATE_PAGESIZE = 0x0017;  // 候補リストのページサイズを変更した(dwValue:0~31の数値)
        const int NI_SETCANDIDATE_PAGESTART = 0x0016;   // 候補リストを設定した (dwIndex:候補リストを指定する0~31の値)

        //  ImmNotifyIME  dwIndexの定数

        const int CPS_CANCEL = 0x0004;   //   変換文字列をクリアする
        const int CPS_COMPLETE = 0x0001;  //  変換文字列を確定文字にする
        const int CPS_CONVERT = 0x0002;  //   次の候補に変換する
        const int CPS_REVERT = 0x0003;  //   変換文字列を取り消し、確定前確定前に戻す

        //  ImmAssociateContextEx  dwFlags

        const int IACE_CHILDREN = 0x0001;
        const int IACE_DEFAULT = 0x0010;
        const int IACE_IGNORENOCONTEXT = 0x0020;


        int ItextLength = 0;

        IntPtr Hwnd;

        private string Us100ConverterStr2(byte[] str, int start, int byteNum)
        {
            if (byteNum + start > str.Length)
            {
                byteNum = str.Length - start;
            }

            byte[] str2 = new byte[byteNum];

            for (int cnt = 0; cnt < byteNum; cnt++)
            {
                str2[cnt] = str[cnt + start];
            }

            return Encoding.Default.GetString(str2);
        }

        private void WindowMain_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            InputMethod.Current.ImeState = InputMethodState.On;

            TextBoxInput.Focus();

        }

        private void WindowMain_Loaded(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("WindowMain Loaded ");

            var helper = new WindowInteropHelper(Application.Current.MainWindow);

            Hwnd = helper.Handle;

            HwndSource source = HwndSource.FromHwnd(Hwnd);

            source.AddHook(new HwndSourceHook(WndProc));


            //  IME Default CandidateWindow を隠す Start (非表示にするとImmGetCandidateList のサイズが設定される)

            var lp = ~ISC_SHOWUICANDIDATEWINDOW;

            var lParam = new IntPtr(lp);

            Win32.DefWindowProc(helper.Handle, WM_IME_SETCONTEXT, 1, lParam);   //  3 para は zero 以外

            //  IME Default CandidateWindow を隠す End 
        }



        public IntPtr WndProc(IntPtr hwnd, int imsg, IntPtr wParam, IntPtr lParam, ref bool bhandled)
        {
            switch (imsg)
            {
                case WM_IME_NOTIFY:    //  0x0282

                    Debug.WriteLine("WndProc  NOTIFY : " + wParam.ToString("0") + " : " + lParam.ToString("0"));

                    switch ((int)wParam)
                    {
                        case IMN_CHANGECANDIDATE:  //  0x0003

                            ItextLength = TextBoxInput.Text.Length;

                            bhandled = true;

                            var himc = Win32.ImmGetContext(hwnd);

                            var isize = Win32.ImmGetCandidateList(himc, 0, null, 0);

                            if (isize > 0)
                            {
                                Debug.WriteLine("CandidateChange  isize : " + isize.ToString("0"));

                                byte[] bytebuf = new byte[isize];

                                ListBoxA.Items.Clear();

                                Win32.ImmGetCandidateList(himc, 0, bytebuf, (int)isize);

                                int icount = System.BitConverter.ToInt32(bytebuf, 8);

                                for (int cnt = 0; cnt < icount; cnt++)
                                {
                                    int iOffset = System.BitConverter.ToInt32(bytebuf, cnt * 4 + 24);

                                    int len = 0;

                                    while (bytebuf[iOffset + len] != '\0')
                                    {
                                        len++;
                                    }

                                    ListBoxA.Items.Add(Us100ConverterStr2(bytebuf, iOffset, len));
                                }

                                Win32.ImmReleaseContext(hwnd, himc);
                            }

                            break;

                        default:

                            Debug.WriteLine("WM_IME_NOTIFY 3 以外 : " + wParam.ToString("0") + lParam.ToString("0"));

                            break;
                    }

                    break;

                default:

                    break;

            }

            if (!bhandled)
            {
                Win32.DefWindowProc(hwnd, (uint)imsg, (uint)wParam, lParam);
            }

            return IntPtr.Zero;
        }

        private void ListBoxA_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var iidx = ListBoxA.SelectedIndex;

            if (iidx >= 0)
            {
                var slist = ListBoxA.Items[iidx].ToString();

                TextBoxInput.Text = TextBoxInput.Text + slist;

                var himc = Win32.ImmGetContext(Hwnd);

                Win32.ImmNotifyIME(himc, (IntPtr)NI_SELECTCANDIDATESTR, (IntPtr)iidx, IntPtr.Zero);

                Win32.ImmReleaseContext(Hwnd, himc);

            }
        }
    }
}