post - online - subir imagenes a imgur
Sube imágenes a Imgur desde Mathematica (3)
Un pajarito acaba de informarme de una solución de Mathematica a esta pregunta (la implementación subyacente todavía usa JLink, pero esta respuesta oculta todo el código relacionado con 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 <> ")"
]
Esto es solo V8 y las opciones de importación XML
"RequestMethod"
y "RequestParameters"
no están documentadas y son experimentales (y por lo tanto están sujetas a cambios).
Aquí hay un desafío para todos los seguidores de etiquetas de mathematica
. Hagamos que sea mucho más conveniente insertar imágenes en publicaciones de SO de Mathematica creando un cargador de imgur .
¿Cómo podemos crear una función imgur[g_]
que imgur[g_]
su argumento (asegurándose de que el tamaño final no sea más ancho que el ancho de las publicaciones de StackOverflow), conviértalo a PNG, súbalo a imgur y devuelva un archivo listo para ser pegado Línea MarkDown como ![Mathematica graphic](http://i.imgur.com/ZENa4.jpg)
?
Referencias útiles:
- Imgur API
- Ejemplo de uso de la solicitud POST de Mathematica en el blog de WRI (publicación en Twitter) por ragfield
- Ejemplo de uso de solicitudes POST de Mathematica en SO (cargando a ifile.it)
No pude adaptar este último método para cargar una imagen sin exportarla primero a un archivo.
Advertencia, ¡use con cuidado! StackOverflow utiliza una instalación de imgur separada que mantiene las imágenes indefinidamente. Si usa el imgur principal, las imágenes desaparecerán después de 6 meses si nadie las ve . Lamentablemente, a partir de noviembre de 2011 no parece haber una forma oficial de subir imágenes a StackOverflow mediante programación.
Actualización: Vea a continuación una solución para subir a StackOverflow directamente .
Nota : Esto está usando el cargador anónimo de imgur con mi clave anónima. El sitio imgur restringe las cargas a 50 cargas por hora, lo que normalmente debería ser correcto, pero esto puede causar un problema si muchas personas lo intentan simultáneamente. Así que por favor obtenga su propia clave anónima aquí:
http://imgur.com/register/api_anon
Y luego reemplace la clave en el código de abajo con su propia clave ( ¡gracias! ).
La parte más difícil de codificar fue la conversión de una expresión de Mathematica a una imagen PNG a una codificación Base64 a una codificación URL. Hay alrededor de 1,000 formas de hacerlo mal y creo que logré probarlas todas.
El código se divide en algunas partes:
- Construye la URL POST
- Hacer la conexión HTTP
- Enviar la URL POST
- Lee el resultado, que es XML
- Extraiga la url de imgur del XML
- Formatea la url de imgur como marca (o como una función de
Hyperlink
Mathematica ).
Aquí está el código:
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 <> ")"
]
Pruebas:
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)
Y la imagen real:
Nota: Obtenga una paleta preparada con esta funcionalidad here .
La solución de Arnoud me emocionó e impacientó, así que aquí hay una mejora. No podría haber hecho esto sin estudiar su código. Esta versión parece ser algo más confiable y menos propensa a errores de tiempo de espera, pero para ser honesto, no conozco Java, así que cualquier mejora es bienvenida.
Lo más importante: esta versión se carga directamente en stack.imgur.com
, por lo que es seguro usarla aquí en , sin tener que preocuparse de que las imágenes cargadas desaparezcan después de un tiempo.
Proporciono tres funciones:
-
stackImage
carga la expresión, se exporta como PNG y devuelve la URL -
stackMarkdown
devuelve el descuento, listo para ser copiado -
stackCopyMarkdown
copia el descuento en el portapapeles
Siguiente paso: crea un botón de paleta que hace esto automáticamente para el gráfico seleccionado en el cuaderno. Las mejoras al código son bienvenidas.
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://.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];
]
]
Actualizar:
Aquí hay un botón que mostrará una vista previa de la selección y ofrecerá la carga (o cancelación). Requiere que se definan las funciones previas.
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"]]]]
Lamentablemente, no puedo poner el botón en una paleta ( CreatePalette
) porque las dimensiones de la paleta influirán en la rasterización. Las soluciones a este problema son bienvenidas.
Actualización 2:
En función de la respuesta a esta pregunta , aquí hay un botón de la paleta que funciona solo para 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]
Advertencia: destruye el contenido del portapapeles incluso si hace clic en cancelar en el cuadro de vista previa.