Télécharger des images de Mathematica vers Imgur

voici un défi à tous les suiveurs de tag mathematica . Faisons en sorte qu'il soit beaucoup plus pratique d'insérer des images dans So post de Mathematica en créant un imgur uploader.

Comment Pouvons-nous créer une fonction imgur[g_] qui rastériera son argument (en s'assurant que la taille finale n'est pas plus large que la largeur des poteaux StackOverflow), le convertir en PNG, le télécharger à imgur, et retourner un prêt à être collé MarkDown comme ![Mathematica graphic](http://i.imgur.com/ZENa4.jpg) ?

références utiles:

Je n'ai pas pu adapter cette dernière méthode pour télécharger une image sans l'exporter d'abord dans un fichier.


attention, utilisez avec soin! StackOverflow utilise une installation imgur séparée qui conserve les images indéfiniment. Si vous utilisez l'imgur principal, les images disparaîtront après 6 mois si personne ne les voit . Malheureusement à partir de 2011 Novembre Il semble être pas de manière officielle pour télécharger des images à StackOverflow programmatically.


mise à Jour: Voir ci-dessous une solution pour le téléchargement sur StackOverflow directement .

52
demandé sur Szabolcs 2011-11-07 19:02:59

3 réponses

un petit oiseau vient de m'informer d'une solution Mathematica à cette question (l'implémentation sous-jacente utilise toujours JLink, mais cette réponse cache tout le code associé à 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 <> ")"
]

c'est V8 seulement et les XML options d'importation "RequestMethod" et "RequestParameters" ne sont pas documentés et expérimentaux (et donc sujets à changement).

16
répondu Arnoud Buzing 2011-12-01 17:32:59

Note: obtenez une palette prête à l'emploi avec cette fonctionnalité ici .


la solution D'Arnoud m'a excité et impatient, alors voici une amélioration. Je n'aurais pas pu faire ça sans étudier son code. Cette version semble un peu plus fiable et moins sujette aux erreurs de timeout, mais pour être honnête, je ne connais pas de Java du tout, donc toute amélioration est la bienvenue.

le plus important: Cette version télécharge directement vers stack.imgur.com , il est donc sûr à utiliser ici sur StackOverflow, sans avoir à craindre que les images téléchargées disparaîtront après un certain temps.

je fournir trois fonctions:

  • stackImage télécharge L'expression, exportée en PNG, et renvoie l'URL
  • stackMarkdown renvoie le markdown, prêt à être copié
  • stackCopyMarkdown copie le markdown au bloc-notes

étape suivante: créer un bouton de palette qui le fait automatiquement pour le graphique sélectionné dans le bloc-notes. Les améliorations apportées au code sont les bienvenues.


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

mise à jour:

voici un bouton qui affichera un aperçu de la sélection et offrira le téléchargement (ou l'annulation). Il nécessite les fonctions précédentes pour être défini.

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

malheureusement, je ne peux pas mettre le bouton dans une palette ( CreatePalette ) parce que les dimensions de la palette influenceront la rastérisation. Les Solutions à ce problème sont les bienvenues.

mise à Jour 2:

basé sur la réponse à cette question , voici un bouton de palette Windows-only:

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]

avertissement: it détruit le contenu du presse-papiers, même si vous cliquez sur annuler dans la boîte de prévisualisation.

13
répondu Szabolcs 2017-05-23 11:46:45

Note : ceci utilise le uploader anonyme imgur avec ma clé anonyme. Le site d'imgur limite les chargements à 50 chargements / heure, ce qui devrait normalement suffire, mais cela peut poser un problème si beaucoup de gens essaient cela simultanément. Alors s'il vous plaît obtenez votre propre clé anonyme ici:

http://imgur.com/register/api_anon

puis remplacer la clé dans le code ci-dessous avec votre propre clé ( merci! ).

la partie la plus difficile à coder a été la conversion D'une expression Mathematica en PNG image en Base64 encoding en URL encoding. Il y a environ 1000 façons de faire le mal et je pense que j'ai réussi à tous les essayer.

Le code se décompose en quelques morceaux:

  • construire l'url de la poste
  • Faire la connexion HTTP
  • Send the POST url
  • Lire la suite, qui est XML
  • extraire l'url imgur du XML
  • formater l'url imgur comme markdown (ou comme un Mathematica Hyperlink fonction).

voici le code:

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

test:

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)

et l'image actuelle:

Mathematica graphic

12
répondu Arnoud Buzing 2011-12-01 04:34:43