I have to "generate" a png file and send it to the Telegram bot via SendPhotoAsync of SeendDocumentAsync.
This is a piece of my C# code:
...
Bitmap speedometer = new Bitmap(#"C:\Immagini\bot\speedometer.png");
Bitmap pointer = new Bitmap(#"C:\Immagini\bot\pointer.png");
Bitmap finalImage = new Bitmap(speedometer);
using (Graphics graphics = Graphics.FromImage(finalImage))
{
Bitmap rotatedPointer = RotateImage(pointer, efficienza_int * (float)1.8);
rotatedPointer.MakeTransparent(Color.White);
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.DrawImage(rotatedPointer, 0, 0);
?????????????
}
Now, I want to send my finalImage without saving it on the disk with Save method.
How can I?
Thanks in advice!
Save it to MemoryStream, and send the MemoryStream in your call to the bot, like this:
using (MemoryStream ms = new MemoryStream())
using (Bitmap finalImage = new Bitmap(speedometer))
{
using (Graphics graphics = Graphics.FromImage(finalImage))
{
// ... stuff
}
finalImage.Save(ms, ImageFormat.Png);
// This is important: otherwise anything reading the stream
// will start at the point AFTER the written image.
ms.Position = 0;
Bot.SendPhotoAsync(/* send 'ms' here. Whatever the exact args are */);
}
It is possible that async sending requires the stream to remain open. Though, normally, when you have such an async send, you can specify a function that should be called after the sending has finished.
In that case, you should not put the MemoryStream in a using block, but instead store the stream object in a global variable in your class, and make sure that the function handling the end of the async send disposes it.
Also do note this question...
bot.sendphoto does not work asp.net
Apparently SendPhotoAsync is not enough to actually send it; the answer there specifies you need to call .GetAwaiter() and .GetResult(). I don't know the API, so you'll have to figure that out yourself.
From the Telegram Bot API documentation (link)
Sending files
There are three ways to send files (photos, stickers, audio, media, etc.):
...
Post the file using multipart/form-data in the usual way that files are uploaded via the browser. 10 MB max size for photos, 50 MB for other files.
Your question is not clear!
However, (if I understand your question right)
You are using TelgramBotClient from this repository: https://github.com/TelegramBots
when you invoke SendPhotoAsync from this client it takes FileToSend as a parameter which represent the photo you processed with rotation, transparency and smoothing.
when you pass this FileToSend you can set the photo either by loading it from temp file you created after processing or you can load it directory from MemoryStream like this:
using System.Drawing;
using System.Drawing.Drawing2D;
using Telegram.Bot;
using Telegram.Bot.Args;
using System.IO;
using System.Drawing.Imaging;
namespace LoadGraphicsFromMemory
{
public static class ImageExtensions
{
public static MemoryStream ToMemoryStream(this Bitmap image, ImageFormat format)
{
using (MemoryStream ms = new MemoryStream())
{
image.Save(ms, format);
return ms;
}
}
}
class Program
{
private static float efficienza_int;
private static readonly TelegramBotClient Bot = new TelegramBotClient("Your API key");
static void Main(string[] args)
{
Bot.OnMessage += BotOnMessageReceived;
}
private static void BotOnMessageReceived(object sender, MessageEventArgs e)
{
Bitmap speedometer = new Bitmap(#"C:\Immagini\bot\speedometer.png");
Bitmap pointer = new Bitmap(#"C:\Immagini\bot\pointer.png");
Bitmap finalImage = new Bitmap(speedometer);
using (Graphics graphics = Graphics.FromImage(finalImage))
{
Bitmap rotatedPointer = RotateImage(pointer, efficienza_int * (float)1.8);
rotatedPointer.MakeTransparent(Color.White);
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.DrawImage(rotatedPointer, 0, 0);
}
Bot.SendPhotoAsync(e.Message.Chat.Id, new Telegram.Bot.Types.FileToSend("My File", finalImage.ToMemoryStream(ImageFormat.Jpeg)));
}
private static Bitmap RotateImage(Bitmap pointer, object p)
{
return pointer;
}
}
}
Related
It's definitely possible to convert an SVG to EMF, for example this website. I wonder if it's possible to achieve this conversion in C#?
Update:
I tried to read an SVG file using SVG.NET and draw it to a Graphics object, then tried export the Image as a MetaFile in .emf extension (I followed the instruction here: GDI+ / C#: How to save an image as EMF?). The reading was done successfully and the image did get exported as .emf. However, when I opened that .emf in PowerPoint, it couldn't be un-grouped, which indicated that the drawing info of that file was actually not dumped correctly.
Update 2:
Now it does export a ungroup-able .emf, but the ungrouping shows a really poor result. I used the following code to produce the .emf:
private void OpenPictureButtonClick(object sender, EventArgs e)
{
var openFileDialog = new OpenFileDialog();
openFileDialog.ShowDialog();
_svgDoc = SvgDocument.Open(openFileDialog.FileName);
RenderSvg(_svgDoc);
}
private void SavePictureClick(object sender, EventArgs e)
{
var saveFileDialog = new SaveFileDialog {Filter = "Enhanced Meta File | *.Emf"};
saveFileDialog.ShowDialog();
var path = saveFileDialog.FileName;
var graphics = CreateGraphics();
var img = new Metafile(path, graphics.GetHdc());
var ig = Graphics.FromImage(img);
_svgDoc.Draw(ig);
ig.Dispose(); img.Dispose(); graphics.ReleaseHdc(); graphics.Dispose();
}
private void RenderSvg(SvgDocument svgDoc)
{
svgImageBox.Image = svgDoc.Draw();
}
I had the same issue but searching had no results.
Finally I ended up with my own simple solution below. I used SVG.NET.
public static byte[] ConvertToEmf(string svgImage)
{
string emfTempPath = Path.GetTempFileName();
try
{
var svg = SvgDocument.FromSvg<SvgDocument>(svgImage);
using (Graphics bufferGraphics = Graphics.FromHwndInternal(IntPtr.Zero))
{
using (var metafile = new Metafile(emfTempPath, bufferGraphics.GetHdc()))
{
using (Graphics graphics = Graphics.FromImage(metafile))
{
svg.Draw(graphics);
}
}
}
return File.ReadAllBytes(emfTempPath);
}
finally
{
File.Delete(emfTempPath);
}
}
At first I create a temp file. Then I use Draw(Graphics) method to save emf in it. And at last I read bytes from temp file.
Don't try to use MemoryStream for Metafile. Unfortunately, it's not working.
This is what I found to be currently the best solution. This is almost like the accepted answer and uses SVG.NET, but is capable of doing it in memory.
The important changes are to release the handle and to reset the position memory stream.
public static Stream ConvertSvgToEmf(string svgImage)
{
using var writeStream = new MemoryStream();
var svg = SvgDocument.FromSvg<SvgDocument>(svgImage);
var stream = new MemoryStream();
var sizedImage = new Bitmap((int)svg.Width.Value, (int)svg.Height.Value);
using (var graphicsFromSizedImage = Graphics.FromImage(Image.FromHbitmap(sizedImage.GetHbitmap())))
using (var metafile = new Metafile(stream, graphicsFromSizedImage.GetHdc(), EmfType.EmfPlusOnly)) // Specify EmfType for lesser file size
using (var graphics = Graphics.FromImage(metafile))
{
svg.Draw(graphics);
graphicsFromSizedImage.ReleaseHdc();
}
stream.Position = 0;
return stream;
}
Be aware that the underlying implementation relies on System.Drawing and therefore the gdi must be accessible. On linux based OS's (or Docker images) libgdiplus must be installed.
As System.Drawing is considered to be deprecated, alternatives like Magick.NET may be better suited for your case.
I'm taking a Stream convert it to Image, process that image, then return a FileStream.
Is this a performance problem? If not, whats the optimized way to convert and return back a stream?
public FileStream ResizeImage(int h, int w, Stream stream)
{
var img = Image.FromStream(stream);
/* ..Processing.. */
//converting back to stream? is this right?
img.Save(stream, ImageFormat.Png);
return stream;
}
The situation in which this is running: User uploads image on my site (controller gives me a Stream, i resize this, then send this stream to rackspace (Rackspace takes a FileStream).
You basically want something like this, don't you:
public void Resize(Stream input, Stream output, int width, int height)
{
using (var image = Image.FromStream(input))
using (var bmp = new Bitmap(width, height))
using (var gr = Graphics.FromImage(bmp))
{
gr.CompositingQuality = CompositingQuality.HighSpeed;
gr.SmoothingMode = SmoothingMode.HighSpeed;
gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
gr.DrawImage(image, new Rectangle(0, 0, width, height));
bmp.Save(output, ImageFormat.Png);
}
}
which will be used like this:
using (var input = File.OpenRead("input.jpg"))
using (var output = File.Create("output.png"))
{
Resize(input, output, 640, 480);
}
That looks as simple as it can be. You have to read the entire image contents to be able to process it and you have to write the result back.
FileStreams are the normal .NET way to handle files, so for normal purposes your approach is okay.
The only thing I don't understand is why you return the FileStream again - it is the same object as was passed by a parameter.
If you are doing a lot of images and only modify parts of the data, memory mapped files could improve performance. However it is a more advanced concept to use.
I have some textfields processed and other elements, but I want to get the bitmap so I can save it somewhere on disk. I need to do it directly from WatiN if this is possible.
How can I do this?
I had a similar problem some time ago.
Watin can't do this directly but it exposes the mshtml objects needed to get some results.
At the time my code was pretty much like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WatiN.Core;
using WatiN.Core.Native.InternetExplorer;
using mshtml;
using System.Windows.Forms;
namespace ConsoleApplication1
{
class Program
{
[STAThread]
static void Main(string[] args)
{
Browser browser = new IE("http://www.google.com");
IEElement banner = browser.Images[0].NativeElement as IEElement;
IHTMLElement bannerHtmlElem = banner.AsHtmlElement;
IEElement bodyNative = browser.Body.NativeElement as IEElement;
mshtml.IHTMLElement2 bodyHtmlElem = (mshtml.IHTMLElement2)bodyNative.AsHtmlElement;
mshtml.IHTMLControlRange controlRange = (mshtml.IHTMLControlRange)bodyHtmlElem.createControlRange();
controlRange.add((mshtml.IHTMLControlElement)bannerHtmlElem);
controlRange.execCommand("Copy", false, System.Reflection.Missing.Value);
controlRange.remove(0);
if (Clipboard.GetDataObject() != null)
{
IDataObject data = Clipboard.GetDataObject();
if (data.GetDataPresent(DataFormats.Bitmap))
{
System.Drawing.Image image = (System.Drawing.Image)data.GetData(DataFormats.Bitmap, true);
// do something here
}
}
}
}
}
This little hack, basically, tries to copy the image to the clipboard. However I had a couple of problems making it work properly and ended up snapshoting the region around the image and saving it to disk.
Although this may not be very helpful it may point you in some directions..
I don't think you can get the binary information directly from WatiN. However you have Image.Uri method give you the URI of the image. So then it is easy to download it wih http request.
using (Browser browser = new IE("http://www.sp4ce.net/computer/2011/01/06/how-to-use-WatiN-with-NUnit.en.html"))
{
Image image = browser.Images[0];
Console.Write(image.Uri);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(image.Uri);
WebResponse response = request.GetResponse();
using (Stream stream = response.GetResponseStream())
using (FileStream fs = File.OpenWrite(#"c:\foo.png"))
{
byte[] bytes = new byte[1024];
int count;
while((count = stream.Read(bytes, 0, bytes.Length))!=0)
{
fs.Write(bytes, 0, count);
}
}
}
Hope this helps
A while ago I needed to extract image data too so I came with this solution:
Create an hidden field and a canvas inside the page using
ie.RunScript("document.body.innerHTML += \"<input type='hidden' id='hidden64'/>\";");
ie.RunScript("document.body.innerHTML += \"<canvas id='canv' width='150px' height='40px' ></canvas>\";");
transform it to base64 using javascript and retrieving its value
ie.RunScript("var c = document.getElementById('canv');");
ie.RunScript("var ctx = c.getContext('2d');");
ie.RunScript("var img = document.getElementsByName('imgCaptcha')[0];");
ie.RunScript("ctx.drawImage(img, 10, 10);");
ie.RunScript("document.getElementById('hidden64').value=c.toDataURL();");
then retrieving the codified value
string data = ie.Element(Find.ById("hidden64")).GetAttributeValue("value");
var base64Data = Regex.Match(data, #"data:image/(?<type>.+?),(?<data>.+)").Groups["data"].Value;
var binData = Convert.FromBase64String(base64Data);
Bitmap im;
using (var stream = new MemoryStream(binData))
{
im = new Bitmap(stream);
}
Hope it helps :)
public Image GetImageFromElement(IHTMLElement Element)
{
int width = (int)Element.style.width;
int height = (int)Element.style.height;
IHTMLElementRender2 render = (IHTMLElementRender2)Element;
Bitmap screenCapture = new Bitmap(width, height);
Rectangle drawRectangle = new Rectangle(0, 0, width, height);
this.DrawToBitmap(screenCapture, drawRectangle);
Graphics graphics = Graphics.FromImage(screenCapture);
IntPtr graphicshdc = graphics.GetHdc();
render.DrawToDC(graphicshdc);
graphics.ReleaseHdc(graphicshdc);
graphics.Dispose();
return screenCapture as Image;
}
That's the Method i use for php generated images.
It's implimented in my own WebBrowserClass, which extends the webbrowser control.
(so "this" = WebBrowser)
But we have to import the IHTMLElementRender2 interface, to use the method.
[Guid("3050f669-98b5-11cf-bb82-00aa00bdce0b"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
ComVisible(true),
ComImport]
interface IHTMLElementRender2
{
void DrawToDC([In] IntPtr hDC);
void SetDocumentPrinter([In, MarshalAs(UnmanagedType.BStr)] string bstrPrinterName, [In] IntPtr hDC);
};
I found this method in web, about 1 year ago, so if you search for it you might find more information.
Iwan
I had such problem, and I could not solve it. PHP generated new images all the time so I used the CaptureWebPageToFile() method.
Here is my code to Serialize, Deserialize and Save an image to the file system. I have looked at many examples of serialization/deserialization and I just want to get some feedback as I am sure my code could be improved. Any feedback would be greatly appreciated. I know this is a common problem so hopefully this question will be a good resource for others in the future.
This is the revised code using recommendations:
private void Form1_Load(object sender, EventArgs e)
{
RunTest();
}
private void RunTest()
{
byte[] jpgba = ConvertFileToByteArray("D:\\Images\\Image01.jpg");
using (Image jpgimg = ConvertByteArrayToImage(jpgba))
{
SaveImageToFileSystem(jpgimg, "D:\\Images\\Image01_Copy.jpg");
}
byte[] pngba = ConvertFileToByteArray("D:\\Images\\Image02.png");
using (Image pngimg = ConvertByteArrayToImage(pngba))
{
SaveImageToFileSystem(pngimg, "D:\\Images\\Image02_Copy.png");
}
byte[] gifba = ConvertFileToByteArray("D:\\Images\\Image03.gif");
using (Image gifimg = ConvertByteArrayToImage(gifba))
{
SaveImageToFileSystem(gifimg, "D:\\Images\\Image03_Copy.gif");
}
MessageBox.Show("Test Complete");
this.Close();
}
private static byte[] ConvertFileToByteArray(String FilePath)
{
return File.ReadAllBytes(FilePath);
}
private static Image ConvertByteArrayToImage(byte[] ImageByteArray)
{
using (MemoryStream ms = new MemoryStream(ImageByteArray))
{
return Image.FromStream(ms);
}
}
private static void SaveImageToFileSystem(Image ImageObject, string FilePath)
{
// ImageObject.Save(FilePath, ImageObject.RawFormat);
// This method only works with .png files.
// This method works with .jpg, .png and .gif
// Need to copy image before saving.
using (Image img = new Bitmap(ImageObject.Width, ImageObject.Height))
{
using (Graphics tg = Graphics.FromImage(img))
{
tg.DrawImage(ImageObject, 0, 0);
}
img.Save(FilePath, img.RawFormat);
}
return;
}
What I have see from quick look:
Streams should be wrapped in using(...) pattern, in your case if exception occurs during processing, then Dispose() won't be called.
using (FileStream fs = new FileStream(FilePath, FileMode.Open))
{
// Another small optimization, removed unnecessary variable
byte[] iba = new byte[(int)fs.Length];
fs.Read(iba, 0, iba.Length);
}
You should catch only exceptions you expect. For example in SerializeImage this will be IOException. Catching all exceptions is very bad practice.
}
catch (IOException ex)
{
Image.FromStream method depends on stream, so if you close underlying stream and return Image you can receive unpredictable behavior (well, in most cases this will work, but sometimes error occurs). So you need to create image copy and return it.
using (MemoryStream ms = new MemoryStream(ImageByteArray))
{
using (Image img = Image.FromStream(ms))
{
return new Bitmap(img);
}
}
You are not disposed tg graphics object and img object in SaveImage method (but disposed ImageObject, see next paragraph). And in general I do not see necessity in such logic, simply call ImageObject.Save(..., ImageFormat.Png) if you want to save image preserving quality.
In the same method (SaveImage) you are disposed ImageObject parameter. This is also bad practice in most cases, consider disposing this image outside worker method by using using(...) pattern.
Here's a bit more:
private void RunTest()
{
// byte array that can be stored in DB
byte[] iba;
// image object to display in picturebox or used to save to file system.
iba = ReadImage("D:\\Images\\Image01.jpg");
using (Image img = DeserializeImage(iba))
{
SaveImage(img, "D:\\Images\\Image01_Copy.jpg");
}
iba = ReadImage("D:\\Images\\Image02.png");
using (Image img1 = DeserializeImage(iba))
{
SaveImage(img1, "D:\\Images\\Image02_Copy.png");
}
iba = ReadImage("D:\\Images\\Image03.gif");
using (var img2 = DeserializeImage(iba))
{
SaveImage(img2, "D:\\Images\\Image03_Copy.gif");
}
MessageBox.Show("Test Complete");
}
private static byte[] ReadImage(String filePath)
{
// This seems to be the easiest way to serialize an image file
// however it would be good to take a image object as an argument
// in this method.
using (var fs = new FileStream(filePath, FileMode.Open))
{
Int32 fslength = Convert.ToInt32(fs.Length);
var iba = new byte[fslength];
fs.Read(iba, 0, fslength);
return iba;
}
}
private static Image DeserializeImage(byte[] imageByteArray)
{
using (var ms = new MemoryStream(imageByteArray))
{
return Image.FromStream(ms);
}
}
private static void SaveImage(Image imageObject, string filePath)
{
// I could only get this method to work for .png files.
// imageObject.Save(filePath, imageObject.RawFormat);
// This method works with .jpg, .png and .gif
// Need to copy image before saving.
using (Image img = new Bitmap(imageObject.Width, imageObject.Height))
{
using (Graphics tg = Graphics.FromImage(img))
{
tg.DrawImage(imageObject, 0, 0);
}
img.Save(filePath, img.RawFormat);
}
return;
}
Note what you called Serializing is just reading the bytes in. Serializing is more what you're doing when you Save.
I got rid of all the try/catch blocks. The best they were doing for you is telling you whether the problem happened in Reading, Saving or Deserializing. You can determine that from the stack trace, which you were destroying by only displaying ex.Message.
You were also returning null on a serious exception, propagating failure.
Beside that I agree with everything arbiter said.
As John Saunder says, serializing and deserializing are more than just reading the raw data from a file. See Wiki on Serialization
For images in .net, you don't need to use anything more than the provided framework methods (most of the time)
So Loading an Image (De-Serialization) in .net is.
using System.Drawing.Image;
Image test;
test = Image.FromFile(#"C:\myfile.jpg")
test = Image.FromStream(myStream); // or you can load from an existing stream
Likewise, Saving the image (Serialization) is:
test.Save(#"C:\anotherFile.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
These are the basics of loading and saving an image in .net. If you have a more specific scenario, ask another question.
I'd like to be able to create a simple PNG image, say of a red square using a c# web based service to generate the image, called from an <img src="myws.ashx?x=100> HTML element.
some example HTML:
<hmtl><body>
<img src="http://mysite.com/webservice/rectangle.ashx?size=100">
</body></html>
Is there is anyone who can cobble together a simple (working) C# class just to get me started? Once off and going I'm sure I can finish this off to actually do what I want it to do.
End game is to create simple Red/Amber/Green (RAG) embedded status markers for a data driven web page that shows performance metrics etc*
I'd like it to use PNG's as I anticipate using transparency in the future*
ASP.NET 2.0 C# solution please... (I don't have a production 3.5 box yet)
tia
SOLUTION
rectangle.html
<html>
<head></head>
<body>
<img src="rectangle.ashx" height="100" width="200">
</body>
</html>
rectangle.ashx
<%# WebHandler Language="C#" Class="ImageHandler" %>
rectangle.cs
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Web;
public class ImageHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
int width = 600; //int.Parse(context.Request.QueryString["width"]);
int height = 400; //int.Parse(context.Request.QueryString["height"]);
Bitmap bitmap = new Bitmap(width,height);
Graphics g = Graphics.FromImage( (Image) bitmap );
g.FillRectangle( Brushes.Red, 0f, 0f, bitmap.Width, bitmap.Height ); // fill the entire bitmap with a red rectangle
MemoryStream mem = new MemoryStream();
bitmap.Save(mem,ImageFormat.Png);
byte[] buffer = mem.ToArray();
context.Response.ContentType = "image/png";
context.Response.BinaryWrite(buffer);
context.Response.Flush();
}
public bool IsReusable {
get {return false;}
}
}
Web services, especially SOAP expect things like an XML envelope with the details of the call in. You'd be better off using a HttpHandler.
Something like this:
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Web;
public class ImageHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
int width = int.Parse(context.Request.QueryString["width"]);
int height = int.Parse(context.Request.QueryString["height"]);
using (Bitmap bitmap = new Bitmap(width,height)) {
...
using (MemoryStream mem = new MemoryStream()) {
bitmap.Save(mem,ImageFormat.Png);
mem.Seek(0,SeekOrigin.Begin);
context.Response.ContentType = "image/png";
mem.CopyTo(context.Response.OutputStream,4096);
context.Response.Flush();
}
}
}
}
This is very rough of course. You'd call it then:
<img src="myhandler.ashx?width=10&height=10"/>
A web service is not suitable for this. It returns a message in a specific format, typically SOAP, so it can't be an image.
Use a regular web form instead, where you remove all markup except the #page directive. Use the BinaryWrite method to write the image data to the response stream.
Example:
byte[] imageData;
using (Bitmap image = new Bitmap(10,10)) {
using (Graphics g = Graphics.FromImage(image)) {
g.Clear(Color.Red);
}
using (MemoryStream m = new MemoryStream()) {
image.Save(m, ImageFormat.Png);
imageData = m.ToArray();
}
}
Response.ContentType = "image/png";
Response.BinaryWrite(imageData);
I think #Lloyd's answer is a good start.
I've had problems with alpha transparencies and PNGs: Can you make an alpha transparent PNG with C#?
There is another way to accomplish serving a dynamic image.
namespace MyApp
{
[ServiceContract]
public interface IMyService
{
[WebGet(UriTemplate = "Image.png")]
[OperationContract]
Stream ShowImage();
}
}
For the implementation:
public Stream ShowImage()
{
Bitmap image = new Bitmap(#"C:\Image.png");
Image image2 = new Bitmap(125, 125);
using (Graphics graphics = Graphics.FromImage(image2))
{
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.DrawImage(image, 0, 0, 125, 125);
}
MemoryStream imageAsMemoryStream = new MemoryStream();
image2.Save(imageAsMemoryStream, ImageFormat.Png);
imageAsMemoryStream.Position = 0;
return imageAsMemoryStream;
}
Start the service as a regular WCF service and add the service in your app.config
(WebService = new WebServiceHost(typeof(MyService))).Open();
You can pass parameters to make it more dynamic.
It is NOT possible to output image from a WebService.
Check this: http://www.c-sharpcorner.com/UploadFile/gnsrinivas1511/Webservice05112009034709AM/Webservice.aspx
Also, depending on how you implement this, please be aware that you could be setting yourself up for a DOS attack. Generating images is not the most processor friendly thing. Please be sure to have some authentication and or caching mechanism in place to help alleviate this potential pain point.