I have Xamarin Android app.
I try to save Linear layout like Bitmap . Here is code
public void Save()
{
LinearLayout view = FindViewById<LinearLayout>(Resource.Id.badge);
view.DrawingCacheEnabled = true;
view.BuildDrawingCache();
Bitmap layout = view.GetDrawingCache(true);
}
I need to save it to Pictures folder. How I can do this?
He explained the way to save bitmap as png in memory card with c #. I hope to understand your problem is correct.
"This here is a slim way to export a Bitmap as PNG-file to the sd-card using only C# stuff"
https://stackoverflow.com/a/29012075/6322661
You can use Canvas to draw a View by the following code:
public Bitmap createViewBitmap(View v)
{
Bitmap bitmap = Bitmap.CreateBitmap(v.Width, v.Height,
Bitmap.Config.Argb8888);
Canvas canvas = new Canvas(bitmap);
v.Draw(canvas);
return bitmap;
}
Linear layout is a kind of View. So you can create a Linear layout BitMap :
View v = FindViewById<LinearLayout>(Resource.Id.myLinearLayout);
Bitmap myBitMap = createViewBitmap(v);
And then save it in the DCIM folder:
public static void saveImage(Bitmap bmp)
{
try
{
using (var os = new System.IO.FileStream(Android.OS.Environment.ExternalStorageDirectory + "/DCIM/Camera/MikeBitMap2.jpg", System.IO.FileMode.CreateNew))
{
bmp.Compress(Bitmap.CompressFormat.Jpeg, 95, os);
}
}
catch (Exception e)
{
}
}
You can refer to my github for the more code information.
Related
In my WPF application images are taken with a camera use a view and then passed as bitmaps to another when it's closed via eventargs. However, when I then try to process the images I get the AccessViolationException. This does not occure when I process the images before they are passed or when I use images loaded from a file.
Getting the image from the camera (The PtCamera class is my wrapper for the Camera class from the API)
Bitmap GetRefImage(PtCamera cam)
{
Bitmap image = new Bitmap(2560, 1920, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
if (cam.IsConnected)
{
cam.FetchImage(out image);
}
else
{
ErrorOccurred?.Invoke(this, $"GetRefImage: {cam.Error}");
}
return image;
}
In this context I can access the bitmap and process it as I like.
After passing the bitmap when the view is closed:
void CloseZoomedView(bool isConf)
{
if (cam is object && cam.IsConnected)
cam.Close();
ZoomClosingArgs eArg = new ZoomClosingArgs()
{
IsConfirmed = isConf,
RefImage = refImage,
};
ClosingZoom?.Invoke(this, eArg);
}
The exception occurs directly when accessing the data in the other viewmodel:
void HandleZoomImageClosed(object sender, ZoomClosingArgs e)
{
if (e is object && e.IsConfirmed)
{
Color test = e.RefImage.GetPixel(0, 0);
//...
}
}
The bitmap is generated by accessing the memory of the camera via FetchImage()
public void FetchImage(out Bitmap image)
{
camera.Memory.GetActive(out int memID);
camera.Memory.ToBitmap(memID, out image);
}
If i replace the code in FetchImage() with just a new Bitmap from file
image = new Bitmap(#"d:\testimage.png")
It works without problems in any context.
The API documentation simply states the following:
Accessible
Camera.Memory.ToBitmap
Syntax
uEye.Memory.ToBitmap(int s32MemId, out System.Drawing.Bitmap bitmap)
Description
Returns a bitmap which contains the image. The method uses the already
allocated image memory and the image is displayed in the format you
specified when allocating the image memory.
Any hints are much appreciated.
I was closing my camera object too early. In CloseZoomedView() the cam.Close() method releases all the memory areas taken up by the camera. With passing a new Bitmap before closing it works like a charm.
void CloseZoomedView(bool isConf)
{
ZoomClosingArgs eArg = new ZoomClosingArgs()
{
IsConfirmed = isConf,
RefImage = new Bitmap(refImage),
};
if (cam is object && cam.IsConnected)
cam.Close();
ClosingZoom?.Invoke(this, eArg);
}
Im in the process of making a snipping tool. I've got it so that my program can be used to draw a rectangle with the mouse and have that image saved. Now what I'm trying to do is have the image generated be transfered to a picture box that show's the user what they have just captured before they decide to save it or anything else.
Is there a way in which I can do this?
So far my screen capture code saves the captured image to the clipboard with the following code found in my ScreenCapture class:
public static bool saveToClipboard = true;
public static void CaptureImage(bool showCursor, Size curSize, Point curPos, Point SourcePoint, Point DestinationPoint, Rectangle SelectionRectangle, string FilePath, string extension)
{
using (Bitmap bitmap = new Bitmap(SelectionRectangle.Width, SelectionRectangle.Height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
g.CopyFromScreen(SourcePoint, DestinationPoint, SelectionRectangle.Size);
if (showCursor)
{
Rectangle cursorBounds = new Rectangle(curPos, curSize);
Cursors.Default.Draw(g, cursorBounds);
}
}
if (saveToClipboard)
{
Image img = (Image)bitmap;
Clipboard.SetImage(img);
}
}
}
Has anyone ever done something like this before? Also, is it possible to have the picture box auto resize so that the screen capture size is used and not the picture boxes?
update
Further to some of the comments below, I've been trying to save the image I store in my above class and pass it to the picture box. But nothing is displayed when I do it. The code I've been using is thus:
Held on the form1.cs:
public void SetImage(Image img)
{
imagePreview.Image = img;
}
And in the screen capture class:
if (saveToClipboard)
{
Image img = (Image)bitmap;
ControlPanel cp = new ControlPanel();
cp.SetImage(img);
Clipboard.SetImage(img);
}
ControlPanel cp = new ControlPanel();
cp.SetImage(img);
this won't work because you need to access the parent form in use, not create a new instance of it.
Look at the answer to this question on creating a simple custom event, but add an Image to the ProgressEventArgs that they create. Then on your main form, subsribe to the event and update the picturebox from there.
I have a .png image i wish to overlay on a base image.
My overlay image contains just a red slant line. I need to get the red line overlayed on the base image at the same co-ordinate as it is in overlay image.
The problem is I do not have the co-ordinates location.
I need to find it programmatically with C#. The overlay image will always be transparent or of white background. What code to find the line co-ordinates from overlay image?
You can create new image, render background image first and then render overlay image over it. Since overlay has alpha channel and line is placed where it should be (i mean there is opaque space on top and left side of line) you do not need coordinates. Illustration code:
Image imageBackground = Image.FromFile("bitmap1.png");
Image imageOverlay = Image.FromFile("bitmap2.png");
Image img = new Bitmap(imageBackground.Width, imageBackground.Height);
using (Graphics gr = Graphics.FromImage(img))
{
gr.DrawImage(imageBackground, new Point(0, 0));
gr.DrawImage(imageOverlay, new Point(0, 0));
}
img.Save("output.png", ImageFormat.Png);
If you are using WPF, why not use a path for your overlay instead of an image if it is a simple line? This would allow it to scale to any size, and has methods for manipulating its dimensions.
If you are using Winforms, there are some similar graphics drawing capabilities you might leverage. Getting the dimensions of the image should be easy, assuming you're using a PictureBox, the following properties should suffice:
myPictureBox.Top
myPictureBox.Bottom
myPictureBox.Left
myPictureBox.Right
Similarly, for a WPF Image:
myImage.Margin
I already needed to create a blank space around an image and I used the ImageFactory library to do that.
Here is the code. I guess you are capable to figure out how to adjust to your needs.
public static Image ResizedImage(Image image, int desiredWidth, int desiredHeight)
{
Image res = (Bitmap)image.Clone();
Image resizedImage;
ImageLayer imageLayer = new ImageLayer();
try
{
if (res != null)
{
//white background
res = new Bitmap(desiredWidth, desiredHeight, res.PixelFormat);
//image to handle
using (var imgf = new ImageFactory(true))
{
imgf
.Load(image)
.Resize(new ResizeLayer(new Size(desiredWidth, desiredHeight),
ResizeMode.Max,
AnchorPosition.Center,
false));
resizedImage = (Bitmap)imgf.Image.Clone();
}
//final image
if (resizedImage != null)
{
imageLayer.Image = resizedImage;
imageLayer.Size = new Size(resizedImage.Width, resizedImage.Height);
imageLayer.Opacity = 100;
using (var imgf = new ImageFactory(true))
{
imgf
.Load(res)
.BackgroundColor(Color.White)
.Overlay(imageLayer);
res = (Bitmap)imgf.Image.Clone();
}
}
}
}
catch (Exception ex)
{
ex.Message;
}
return res;
}
I have the following task. Take a base image and overlay on it another one. The base image is 8b png as well as overlay.
Here are the base (left) and overlay (right) images.
Here is a result and how it must look.
The picture in the left is a screenshot when one picture is on top of another (html and positioning) and the second is the result of programmatic merging.
As you can see in the screenshot the borders of the text is darker. Also here are the sizes of the images
Base image 14.9 KB
Overlay image 6.87 KB
Result image 34.8 KB
The size of the resulting image is also huge
Here is my code that I use to merge those pictures
/*...*/
public Stream Concatinate(Stream baseStream, params Stream[] overlayStreams) {
var #base = Image.FromStream(baseStream);
var canvas = new Bitmap(#base.Width, #base.Height);
using (var g = canvas.ToGraphics()) {
g.DrawImage(#base, 0, 0);
foreach (var item in overlayStreams) {
using (var overlayImage = Image.FromStream(item)) {
try {
Overlay(#base as Bitmap, overlayImage as Bitmap, g);
} catch {
}
}
}
}
var ms = new MemoryStream();
canvas.Save(ms, ImageFormat.Png);
canvas.Dispose();
#base.Dispose();
return ms;
}
/*...*/
/*Tograpics extension*/
public static Graphics ToGraphics(this Image image,
CompositingQuality compositingQuality = CompositingQuality.HighQuality,
SmoothingMode smoothingMode = SmoothingMode.HighQuality,
InterpolationMode interpolationMode = InterpolationMode.HighQualityBicubic) {
var g = Graphics.FromImage(image);
g.CompositingQuality = compositingQuality;
g.SmoothingMode = smoothingMode;
g.InterpolationMode = interpolationMode;
return g;
}
private void Overlay(Bitmap source, Bitmap overlay, Graphics g) {
if (source.Width != overlay.Width || source.Height != overlay.Height)
throw new Exception("Source and overlay dimensions do not match");
var area = new Rectangle(0, 0, source.Width, source.Height);
g.DrawImage(overlay, area, area, GraphicsUnit.Pixel);
}
My questions are
What should I do in order to merge images to achieve the result as in the screenshot?
How can I lower the size of the result image?
Is the System.Drawing a suitable tool for this or is there any better tool for working with png for .NET?
The answers to your questions are:
1) Just call method ToGraphics with a argument CompositingQuality.Default instead of using default argument values like in the example:
using (var g = canvas.ToGraphics(compositingQuality: CompositingQuality.Default))
The problem is with CompositingQuality.HighQuality is that it makes a composition of both images into one, but you want to make an overlay, not to make a composition of two images.
2) The size will be similar to the one you specified and that can not be changed, it is due to a image format.
3) If you are programming in c# for desktop, than System.Drawing is the best choice as far as I know.
I have an ecommerce store built in asp.net c# (Webforms) and a lot of the new product images are very hard to source, so I'd like to watermark them with our logo or domain name.
There are too many products to just download the images and add the watermark, and users with limited image editing experience will be uploading new ones (So they won't have a clue how to add the watermark).
So I guess this just leaves me with using a HttpHandler? Yes / No? If so can you provide some insight (Preferably code samples in C#) into the most efficient way of adding the watermark, considering some pages will have around 20 images (Jpegs) on (All of which need to be watermarked)
I would obtain the Graphicsobject to the jpeg, and then draw the watermark on top of that item, and save it again with the watermark:
using (Image image = Image.FromFile("myImage.jpg"))
using(Graphics g = Graphics.FromImage( image)){
g.DrawImage( myWaterMarkImage, myPosition);
image.Save(myFilename);
}
This looks like it could be helpful:
http://www.switchonthecode.com/tutorials/csharp-snippet-tutorial-how-to-draw-text-on-an-image
While it focus's on text, I am sure with a little modification you could add a graphic in also.
Once you have an implementation you could either call it once per view or when adding prior to saving the file.
Here is a sample HttpHandler
/// <summary>
/// Summary description for $codebehindclassname$
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class ImageHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
string imageName = string.Empty;
string physicalPath = string.Empty;
Image image = null;
Image thumbnailImage = null;
Bitmap bitmap = null;
using (MemoryStream memoryStream = new MemoryStream())
{
string actionName = context.Request.QueryString["Image"];
string opacity = context.Request.QueryString["Opacity"];
int opacityPercent = int.Parse(opacity);
Color waterMarkColor = Color.Gray;
switch (actionName)
{
case "BlueHills":
string myCompany = "My Company Name";
Font font = new Font("Times New Roman", 8f);
context.Response.ContentType = "image/png";
bitmap = Resources.Resources.BlueHills;
Graphics g = Graphics.FromImage(bitmap);
Brush myBrush = new SolidBrush(Color.FromArgb(opacityPercent, waterMarkColor));
SizeF sz = g.MeasureString(myCompany, font);
int X = (int)(bitmap.Width - sz.Width) / 2;
int Y = (int)(sz.Height) / 2;
g.DrawString(myCompany, font, myBrush, new Point(X, Y));
bitmap.Save(memoryStream, ImageFormat.Png);
break;
default:
string test = actionName;
break;
}
context.Response.BinaryWrite(memoryStream.GetBuffer());
memoryStream.Close();
if (image != null) { image.Dispose(); }
if (thumbnailImage != null) { thumbnailImage.Dispose(); }
if (bitmap != null) { bitmap.Dispose(); }
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
and can be called like such:
<asp:Image ID="Image1" runat="server" ImageUrl="~/ImageHandler.ashx?Image=BlueHills&Opacity=50" />
I suggest you to take a look to WPF classes to do this job (GDI+ are deprecated in a web context).
The way (I don't know if is THE BEST way, but I've already done this and works pretty fine) is something similar to:
// Load the original image
BitmapImage image = new BitmapImage();
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = new Uri(physical_imagepath);
image.EndInit();
// Create a final render image
RenderTargetBitmap final = new RenderTargetBitmap(yourNeededWidth, yourNeededHeight, yourDpiDefault, yourDpiDefault, PixelFormats.Default);
DrawingVisual dv = new DrawingVisual();
using (DrawingContext dc = dv.RenderOpen())
{
Rect rectImage = new Rect(0, 0, (double)image.PixelWidth, (double)image.PixelHeight);
dc.DrawImage(image, rectImage);
// Load the bitmap of the watermark
BitmapImage watermark = new BitmapImage();
watermark.BeginInit();
watermark.CacheOption = BitmapCacheOption.OnLoad;
watermark.UriSource = new Uri(physical_logopath);
watermark.EndInit();
// Defines the watermark box
Rect rectWatermark = new Rect(0, 0, (double)watermark.PixelWidth, (double)watermark.PixelHeight);
/* use rectWatermark.X and rectWatermark.Y to move your watermark box around on the final image */
dc.DrawImage(watermark, rectWatermark);
}
final.Render(dv);
// And then serve the final Bitmap to the client
Of course all written as HttpHandler.
The code above is not tested.
(little ads: I've published a CodeCanyon Item that do a similar job).
This isn't an answer so much as a few tips:
Jpeg doesn't support transparency, the best you can probably do is add the watermark image and make it a very light grey color.
Use the generic handler (.ashx), it's very lightweight and prevents you from having to add anything to your web.config file.
If there are going to be upwards of 20 images per page, then I would recommend adding the watermark as you get the images. This is a one-time cost per image and will make loading pages with the images faster.
I can't vouch for the most efficient way of adding a watermark, but if you go with tip #3, it becomes less important as you will only be performing the operation once ever per image. I would probably just use the System.Drawing namespace to do this; just be sure to dispose of the resources you use (Image, Graphics, etc), though I'm sure there are libraries out there that would work much better.
The obvious optimization to any 'on the fly image wartermarking' is to cache the 'watermarked' image if you can afford the storage cost. So, the efficiency of the wartermarking operation itself do not matters much.