首页 文章

从Mathematica上传图片到Imgur

提问于
浏览
52

这是对所有 mathematica 标记粉丝的挑战 . 让我们通过创建imgur上传器将图像插入Mathematica的SO帖子中更加方便 .

我们如何创建一个将光栅化其参数的函数 imgur[g_] (确保最终大小不超过StackOverflow帖子的宽度),将其转换为PNG,将其上传到imgur,然后返回准备粘贴的MarkDown行等如 ![Mathematica graphic](http://i.imgur.com/ZENa4.jpg)

有用的参考:

我没有调整后一种方法来上传图像而不先将其导出到文件中 .


Warning, use with care! StackOverflow使用separate imgur installation无限期保留图像 . 如果你使用主要的imgur,the images will disappear after 6 months if no one views them . 不幸的是,截至2011年11月,似乎有no official way以编程方式将图像上传到StackOverflow .


Update: See below直接上传到StackOverflow的解决方案 .

3 回答

  • 13

    一只小鸟刚刚告诉我这个问题的Mathematica解决方案(底层实现仍然使用JLink,但这个答案隐藏了所有与java相关的代码):

    imgur[expr_] := Module[
     {url, key, image, data, xml, imgurUrl},
     url = "http://api.imgur.com/2/upload";
     key = "c07bc3fb59ef878d5e23a0c4972fbb29";
     image = Fold[ExportString, expr, {"PNG", "Base64"}];
     xml = Import[url, 
      "XML", "RequestMethod" -> "POST", 
      "RequestParameters" -> {"key" -> key, "image" -> image}];
     imgurUrl = Cases[xml, XMLElement["original", {}, {string_}] :> string, 
      Infinity][[1]];
     "![Mathematica graphic](" <> imgurUrl <> ")"
    ]
    

    这仅是V8, XML 导入选项 "RequestMethod""RequestParameters" 未记录和实验(因此可能会更改) .

  • 16

    Note: 使用此功能here获取现成的调色板 .


    Arnoud的解决方案让我兴奋和不耐烦,所以这里有一个改进 . 没有研究他的代码,我不可能做到这一点 . 这个版本似乎更可靠,更不容易出现超时错误,但老实说,我根本不懂Java,所以欢迎任何改进 .

    最重要的是:这个版本直接上传到 stack.imgur.com ,所以在StackOverflow上使用它是安全的,不必担心上传的图像会在一段时间后消失 .

    我提供三个功能:

    • stackImage 上传表达式,导出为PNG,并返回URL

    • stackMarkdown 返回markdown,准备复制

    • stackCopyMarkdown 将降价复制到剪贴板

    下一步:创建一个调色板按钮,自动为笔记本中的选定图形执行此操作 . 对代码的改进非常受欢迎 .


    Needs["JLink`"]
    
    
    stackImage::httperr = "Server returned respose code: `1`";
    stackImage::err = "Server returner error: `1`";
    
    stackImage[g_] :=
     Module[
      {getVal, url, client, method, data, partSource, part, entity, code, 
       response, error, result},
    
      (* this function attempts to parse the response fro the SO server *)
      getVal[res_, key_String] :=
       With[{k = "var " <> key <> " = "},
        StringTrim[
         First@StringCases[First@Select[res, StringMatchQ[#, k ~~ ___] &], 
           k ~~ v___ ~~ ";" :> v],
         "'"]
        ];
    
      data = ExportString[g, "PNG"];
    
      JavaBlock[
        url = "https://stackoverflow.com/upload/image";
        client = JavaNew["org.apache.commons.httpclient.HttpClient"];
        method = JavaNew["org.apache.commons.httpclient.methods.PostMethod", url];
        partSource = JavaNew["org.apache.commons.httpclient.methods.multipart.ByteArrayPartSource", "mmagraphics.png", MakeJavaObject[data]@toCharArray[]];
        part = JavaNew["org.apache.commons.httpclient.methods.multipart.FilePart", "name", partSource];
        part@setContentType["image/png"];
        entity = JavaNew["org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity", {part}, method@getParams[]];
        method@setRequestEntity[entity];
        code = client@executeMethod[method];
        response = method@getResponseBodyAsString[];
      ]
    
      If[code =!= 200, Message[stackImage::httperr, code]; Return[$Failed]];
      response = StringTrim /@ StringSplit[response, "\n"];
    
      error = getVal[response, "error"];
      result = getVal[response, "result"];
      If[StringMatchQ[result, "http*"],
       result,
       Message[stackImage::err, error]; $Failed]
      ]
    
    
    stackMarkdown[g_] := "![Mathematica graphics](" <> stackImage[g] <> ")"
    
    
    stackCopyMarkdown[g_] := Module[{nb, markdown},
      markdown = Check[stackMarkdown[g], $Failed];
      If[markdown =!= $Failed,
       nb = NotebookCreate[Visible -> False];
       NotebookWrite[nb, Cell[markdown, "Text"]];
       SelectionMove[nb, All, Notebook];
       FrontEndTokenExecute[nb, "Copy"];
       NotebookClose[nb];
       ]
      ]
    

    Update:

    这是一个按钮,显示选择的预览,并提供上传(或取消) . 它需要定义先前的功能 .

    Button["Upload to SO",
     Module[{cell = NotebookRead@InputNotebook[], img},
      If[cell =!= {}, img = Rasterize[cell];
       MessageDialog[
        Column[{"Upload image to StackExchange sites?", 
          img}], {"Upload and copy MarkDown" :> stackCopyMarkdown[img], 
         "Cancel" :> Null}, WindowTitle -> "Upload to StackExchange"]]]]
    

    不幸的是我无法将按钮放在调色板( CreatePalette )中,因为调色板尺寸会影响光栅化 . 欢迎解决这个问题 .

    Update 2:

    基于this question的答案,这是一个仅适用于Windows的调色板按钮:

    button = Button["Upload to SO",
      Module[{sel},
       FrontEndExecute[
        FrontEndToken[FrontEnd`SelectedNotebook[], "CopySpecial", "MGF"]];
       sel = Cases[NotebookGet@ClipboardNotebook[], 
         RasterBox[data_, ___] :> 
          Image[data, "Byte", ColorSpace -> "RGB", Magnification -> 1], 
         Infinity];
       If[sel =!= {},
        With[{img = First[sel]},
         MessageDialog[
          Column[{"Upload image to StackExchange sites?", 
            img}], {"Upload and copy MarkDown" :> stackCopyMarkdown[img], 
           "Cancel" :> Null}, WindowTitle -> "Upload to StackExchange"]
         ]
        ]
       ]
      ]
    
    CreatePalette[button]
    

    警告:即使您在预览框中单击取消,它也会破坏剪贴板内容 .

  • 12

    注意:这是使用我的匿名密钥匿名imgur上传器 . imgur网站将上传限制为每小时上传50次,这应该是正常的,但如果很多人同时尝试这可能会导致问题 . 所以请在这里获取您自己的匿名密钥:

    http://imgur.com/register/api_anon

    然后用自己的密钥替换下面代码中的密钥(谢谢!) .

    代码中最棘手的部分是从Mathematica表达式到PNG图像到Base64编码到URL编码的转换 . 大约有1000种方法可以做错,我想我设法尝试了所有这些方法 .

    代码分为几个部分:

    • 构造POST网址

    • Build HTTP连接

    • 发送POST网址

    • 回读结果,即XML

    • 从XML中提取imgur url

    • 将imgur url格式化为markdown(或作为Mathematica Hyperlink 函数) .

    这是代码:

    imgur[expr_] :=
     Module[{url, key, image, data, jUrl, jConn, jWriter, jInput, buffer,
       byte, xml, imgurUrl},
      Needs["JLink`"];
      JLink`JavaBlock[
       JLink`LoadJavaClass["java.net.URLEncoder"];
       url = "http://api.imgur.com/2/upload";
       key = "c07bc3fb59ef878d5e23a0c4972fbb29";
       image = ExportString[ExportString[expr, "PNG"], "Base64"];
       data =
        URLEncoder`encode["key"   , "UTF-8"] <> "=" <>
        URLEncoder`encode[ key    , "UTF-8"] <> "&" <>
        URLEncoder`encode["image" , "UTF-8"] <> "=" <>
        URLEncoder`encode[ image  , "UTF-8"] ;
       jUrl = JLink`JavaNew["java.net.URL", url];
       jConn = jUrl@openConnection[];
       jConn@setDoOutput[True];
       jWriter =
        JLink`JavaNew["java.io.OutputStreamWriter",
         jConn@getOutputStream[]];
       jWriter@write[data];
       jWriter@flush[];
       jInput = jConn@getInputStream[];
       buffer = {};
       While[(byte = jInput@read[]; byte >= 0), AppendTo[buffer, byte]];
       ];
      xml = ImportString[FromCharacterCode[buffer], "XML"];
      imgurUrl =
       Cases[xml,
         XMLElement["original", {}, {string_}] :>
          string, \[Infinity]][[1]];
      "![Mathematica graphic](" <> imgurUrl <> ")"
      ]
    

    测试:

    In[]:= g = Graphics[{Blue, Disk[]}, PlotRange -> 1.2, ImageSize -> Small];
           pic = Overlay[{Blur[Binarize@g, 10], g}];
           imgur[pic]
    
    Out[]= ![Mathematica graphic](http://i.imgur.com/eGOlL.png)
    

    而实际形象:

    Mathematica graphic

相关问题