Prześlij zdjęcia do Imgur z Mathematica

Oto wyzwanie dla wszystkich mathematica obserwujących tag. Uczyńmy to o wiele wygodniejsze wstawianie obrazów do posta z Mathematica, tworząc Imgur uploader.

Jak możemy utworzyć funkcję imgur[g_], która będzie rasteryzować swój argument (upewniając się, że ostateczny rozmiar nie jest szerszy niż szerokość postów Stoskoverflow), przekonwertować go do PNG, przesłać do imgur i zwrócić gotowy do wklejenia MarkDown wiersz, taki jak ![Mathematica graphic](http://i.imgur.com/ZENa4.jpg) ?

Przydatne Bibliografia:

Nie udało mi się dostosować tej ostatniej metody do przesyłania obrazu bez uprzedniego eksportowania go do pliku.


Uwaga, używaj ostrożnie! StackOverflow używa oddzielnego imgur instalacja , która przechowuje obrazy w nieskończoność. Jeśli użyjesz głównego imgur, obrazy znikną po 6 miesiącach, jeśli nikt ich nie obejrzy. Niestety od listopada 2011 roku wydaje się, że nie ma oficjalnego sposobu , aby programowo przesyłać obrazy do StackOverflow.


Aktualizacja: zobacz poniżej rozwiązanie do bezpośredniego przesyłania do StackOverflow .

Author: Szabolcs, 2011-11-07

3 answers

Mały ptaszek właśnie poinformował mnie o Mathematica rozwiązanie tego pytania (podstawowa implementacja nadal używa Jlinka, ale ta odpowiedź ukrywa cały kod związany z Javą):

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 <> ")"
]

Jest to tylko Wersja V8, a Opcje importu XML "RequestMethod" i "RequestParameters" są nieudokumentowane i eksperymentalne (i dlatego mogą ulec zmianie).

 16
Author: Arnoud Buzing,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-01 17:32:59

Uwaga: Pobierz gotową paletę z tą funkcjonalnością tutaj .


Rozwiązanie Arnouda mnie podnieciło i zniecierpliwiło, więc oto ulepszenie. Nie zrobiłbym tego bez przestudiowania jego kodu. Ta wersja wydaje się być nieco bardziej niezawodna i mniej podatna na błędy timeoutu, ale szczerze mówiąc, nie znam w ogóle Javy, więc wszelkie ulepszenia są mile widziane.

Najważniejsze: ta wersja ładuje się bezpośrednio do stack.imgur.com, więc jest bezpiecznie używać tutaj w StackOverflow, bez obawy, że przesłane zdjęcia znikną po pewnym czasie.

Udostępniam trzy funkcje:

  • stackImage przesyła wyrażenie wyeksportowane jako PNG i zwraca adres URL
  • stackMarkdown zwraca markdown, gotowy do skopiowania
  • stackCopyMarkdown kopiuje markdown do schowka

Następny krok: Utwórz przycisk palety, który zrobi to automatycznie dla wybranej grafiki w notatniku. Ulepszenia w kodzie są bardzo Witam.


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:

Oto przycisk, który wyświetli podgląd wyboru i zaoferuje przesłanie (lub anulowanie). Wymaga zdefiniowania poprzednich funkcji.

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"]]]]

Niestety nie mogę umieścić przycisku w palecie (CreatePalette), ponieważ wymiary palety będą miały wpływ na rasteryzację. Rozwiązania tego problemu są mile widziane.

Aktualizacja 2:

Na podstawie odpowiedzi na to pytanie , oto działający przycisk palety tylko dla systemu 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]

Ostrzeżenie: niszczy zawartość schowka, nawet jeśli klikniesz Anuluj w oknie podglądu.

 13
Author: Szabolcs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:46:45

Uwaga: to jest za pomocą anonimowego Imgur uploader z moim anonimowym kluczem. Witryna imgur ogranicza przesyłanie do 50 przesyłek / godzinę, co powinno być normalne, ale może to spowodować problem, jeśli Wiele osób spróbuje tego jednocześnie. Więc proszę, Zdobądź swój własny anonimowy klucz tutaj:

Http://imgur.com/register/api_anon

A następnie zastąp klucz w poniższym kodzie własnym kluczem (dzięki!).

Najtrudniejszą częścią kodu była konwersja od wyrażenia Mathematica do obrazu PNG do kodowania Base64 do kodowania URL. Istnieje około 1000 sposobów, aby zrobić to źle i myślę, że udało mi się wypróbować je wszystkie.

Kod dzieli się na kilka części:

  • Zbuduj adres URL postu
  • wykonaj połączenie HTTP
  • Wyślij adres URL posta
  • odczytaj wynik, czyli XML
  • W tym celu należy pobrać plik imgur z pliku XML.]}
  • sformatuj adres URL imgur jako markdown (lub jako Mathematica Hyperlink funkcja).

Oto kod:

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 <> ")"
  ]

Testowanie:

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)

I rzeczywisty obraz:

Mathematica graphic

 12
Author: Arnoud Buzing,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-01 04:34:43