53 votes

Télécharger des images sur Imgur à partir de Mathematica

Voici un défi pour tous mathematica les suiveurs de tags. Rendons beaucoup plus pratique l'insertion d'images dans un article de SO à partir de Mathematica en créant un fichier de type imgur téléchargeur.

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

Références utiles :

Je n'ai pas réussi à adapter cette dernière méthode au téléchargement d'une image sans l'exporter d'abord vers un fichier.


Attention, à utiliser avec précaution ! StackOverflow utilise un installation séparée d'imgur qui conservent les images indéfiniment. Si vous utilisez la page principale d'imgur, les images disparaîtront au bout de 6 mois si personne ne les consulte. . Malheureusement, depuis novembre 2011, il semble y avoir aucun moyen officiel pour télécharger des images sur StackOverflow de manière programmatique.


Mise à jour : Voir ci-dessous une solution pour télécharger sur StackOverflow directement .

2 votes

Veuillez noter que le téléchargement vers http://i.stack.imgur.com/ est plus difficile (vous devrez "conduire" l'interface SO)

0 votes

@belisarius Oups, je n'avais pas réalisé que StackOverflow utilise un site imgur séparé ... Sur le site principal d'imgur, les images peuvent ne pas être conservées pour toujours, donc ce n'est peut-être pas une bonne idée de l'utiliser pour SO imgur.com/faq#long (il faut au moins 1 vue / 6 mois pour qu'elles soient conservées)

4 votes

Publier des graphiques manuellement n'est pas vraiment si difficile (dans V8). Faites un clic droit sur un graphique, choisissez "Enregistrer l'image sous...". La boîte de dialogue du fichier s'ouvre alors à l'endroit où il se trouvait la dernière fois, c'est-à-dire généralement sur mon bureau où un fichier appelé output.png attend déjà d'être écrasé par sa prochaine incarnation. Deux clics suffisent, deux autres clics et il est affiché dans ma boîte de réponse SO. Cela prend 15 secondes au maximum. Obtenir la ligne Markdown et la coller prendra à peu près le même temps.

16voto

Arnoud Buzing Points 7413

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

Il s'agit uniquement du V8 et le XML options d'importation "RequestMethod" y "RequestParameters" sont non documentés et expérimentaux (et donc susceptibles d'être modifiés).

0 votes

Merci d'avoir partagé cela Arnoud ! Malheureusement, cela ne semble pas fonctionner lorsque j'essaie de télécharger sur StackOverflow (en utilisant la méthode que j'ai mentionnée dans un commentaire sur votre autre réponse). Je pense que le problème est que l'image doit être soumise en tant que multiplart/form-data Savez-vous comment faire ? Par ailleurs, avez-vous une idée de la façon dont on pourrait transformer ce bouton en un bouton de palette qui téléchargerait la sélection (après l'avoir prévisualisée) ? Voir mon autre réponse pour savoir ce que j'ai essayé et comment cela n'a pas fonctionné (la largeur trop étroite de la palette est utilisée pour la rastérisation).

0 votes

+1 : Très bien ! Maintenant, j'essaie de faire en sorte que cela fonctionne avec OAuth afin de pouvoir télécharger des images directement dans les albums de mon compte et autres :). Aussi, comment as-tu trouvé ces options non documentées ?

0 votes

@nixeagle Si vous parvenez à le faire fonctionner, je ne verrais pas d'inconvénient à ce que vous postiez le code (avec des explications sur les problèmes et la façon dont vous les avez résolus) comme réponse supplémentaire ici.

13voto

Szabolcs Points 12411

Note : Obtenez une palette prête à l'emploi grâce à cette fonctionnalité aquí .


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

Le plus important : cette version télécharge vers stack.imgur.com directement, ce qui permet de l'utiliser en toute sécurité sur StackOverflow, sans avoir à craindre que les images téléchargées ne disparaissent au bout d'un certain temps.

J'assure trois fonctions :

  • stackImage télécharge l'expression, exportée en PNG, et renvoie l'URL
  • stackMarkdown renvoie le texte de démarquage, prêt à être copié
  • stackCopyMarkdown Copie le texte de démarquage dans le presse-papiers

Prochaine étape : créer un bouton de palette qui fait cela automatiquement pour le graphique sélectionné dans le carnet de notes. Les améliorations du 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 proposera le téléchargement (ou l'annulation). Il nécessite que les fonctions précédentes soient définies.

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 placer le bouton dans une palette ( CreatePalette ) car les dimensions de la palette vont influencer le tramage. Les solutions à ce problème sont les bienvenues.

Mise à jour 2 :

En fonction de la réponse à la question cette question Voici un bouton de palette fonctionnant uniquement sous 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]

Attention : il détruit le contenu du presse-papiers même si vous cliquez sur annuler dans la boîte d'aperçu.

0 votes

Je pense que le problème de la palette Rasterize mérite une question à part entière.

0 votes

C'est fantastique ! Je réservais mon vote dans l'espoir de cela. +1

1 votes

@Mr.Wizard vérifiez le chatroom pour une solution packagée.

12voto

Arnoud Buzing Points 7413

Note : Ceci utilise l'uploader anonyme d'imgur avec ma clé anonyme. Le site d'imgur limite les téléchargements à 50 téléchargements par heure, ce qui devrait normalement suffire, mais cela peut poser un problème si beaucoup de personnes essaient simultanément. Veuillez donc obtenir votre propre clé anonyme ici :

http://imgur.com/register/api_anon

Et puis remplacez la clé dans le code ci-dessous par votre propre clé ( Merci ! ).

La partie la plus délicate à coder était la conversion d'une expression Mathematica en image PNG, puis en encodage Base64 et enfin en encodage URL. Il y a environ 1 000 façons de se tromper et je pense avoir réussi à toutes les essayer.

Le code se décompose en plusieurs parties :

  • Construire l'url POST
  • Établir la connexion HTTP
  • Envoyez l'url POST
  • Lisez le résultat, qui est XML
  • Extraire l'url d'imgur de l'XML
  • Formatez l'url d'imgur en markdown (ou en tant que 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

0 votes

Existe-t-il un moyen d'effectuer le codage et le téléchargement au sein même de Mathematica, sans avoir recours à JLink ? +1, au fait.

0 votes

@rcollyer -- Pas dans la V8, pour autant que je sache. L'encodage et le téléchargement sont-ils des fonctions que vous souhaiteriez voir intégrées à Mathematica ?

1 votes

J'ai des erreurs : Java::excptn: A Java exception occurred: java.io.IOException: Server returned HTTP response code: 400 for URL: http://api.imgur.com/2/upload at sun.net.www.protocol.http.HttpURLConnection.getInputStream(H‌​ttpURLConnection.jav‌​a:1290). XML`Parser`XMLGetString::string: String expected at position 1 in XML`Parser`XMLGetString[EndOfFile].

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X