I need to write my own pdf viewer (UserControl). I use pdfium.dll for that. The wrapper of it is PdfiumService. This service can render pages to BitmapSource.
PdfViewer displays pages in VirtualizingStackPanel in ScrollViewer.
Any ideas how can I do lazy render for pdf? The problem is if pdf is about 20mb (1000 pages), rendered pages take about 2gb RAM.
Can VirtualizingStackPanel help me? I didn't find any events for "BeginVirtualizing" or something else. Any easy ways to know what item is displaying now?
Maybe something like that:
Calculate how many pages can be displayed at once.
See ScrollViewer's offset.
Calculate the index of page is now displaying.
Render 5 pages next to current.
Are there any ready solutions, or some tips, or ideas for this?
well, i had a bit of that with images from books....the trouble is not really the gui where you put the bitmap, but how you get the images from the library...is it one by one, sequentially or randomly ?
In fact, if you use a VirtualizingStackPanel it will only manage the gui element to create or destroy, but if you have a full collection of bitmaps in memory you are dead.
One way is to create Page object whitout the bitmap, and create the image when needed + add a timer that will clear all "oldest images"
I do something like that in CBR; and i use a custom control to display pages
private BitmapImage _Image = null;
/// <summary>
/// the image
/// </summary>
public BitmapImage Image
{
get
{
if (_Image == null)
_Image = (DocumentFactory.Instance.GetService(Parent) as BookService).GetImageFromStream(Parent.FilePath, FilePath);
ImageLastAcces = DateTime.Now;
return _Image;
}
set { _Image = value; }
}
Related
My project consists of a video player and a image viewer, both fullscreen in a panel with only one visible at a time. When the video pauses I capture the frame, display it in the image viewer and swap which control is visible. The problem is, when the image viewer is shown you see the previous image for a brief second before the new image is painted.
Does anyone have any suggestions on how I can prevent this? Ideally I want it to be seemless when the controls swap.
I've already set the image viewer to be double buffered.
Edit:
Code, doesn't really show much here.
private void ShowImageView()
{
this.axWindowsMediaPlayer.Visible = false;
this.imageViewer.Visible = true;
}
private void ShowVideoView()
{
this.axWindowsMediaPlayer.Visible = true;
this.imageViewer.Visible = false;
}
I've managed to solve it, the image viewer had a Image Changed event that I hadn't spotted (I'd tried using the Image Loaded event). Subscribing to the image changed event and only showing the control then, seems to give me the transistion I was looking for.
Not sure if the title makes any sense.
In my WPF application I would like the window to contain a small image, icon size. When the user clicks on the image another one simply replaces it, that holds the same dimensions.
I have all the images loaded into my project for C#/WPF. (By the way there are 3 images)
What I have been trying:
I tried changing the opacity in the code-behind to make one image
have full opacity and the others have no opacity. Didn't work as the
first toggle would strangely make all images disappear.
I also tried dynamically changing the image source in the code-behind. I
used if statements and a field to determine what image to switch
the source to. Code being:
if (toggle == 1)
{
thebutton.Source = new BitmapImage(new Uri(#"/images/icon2.png", UriKind.Relative));
toggle = 2;
}
Also did not work (made it blank, rather than switching to another image) but I feel like there is an obvious way I'm not seeing.
What I initially wanted to do was simply (like in graphics programs) raise and lower the images to the top and bottom to determine which ones the user should see. All that matters is the visual. The user clicks image 1, image 1 disappears and image 2 appears in its place, and so on for image 3.
Set the Build Action of the image files to Resource, and load them by Resource File Pack URIs:
thebutton.Source = new BitmapImage(new Uri("pack://application:,,,/images/icon2.png"));
I would like to show 1 million locations on a map based on OpenStreetMap.
I work on C# VS2013 and GMAP.NET WPF. But, when I added markers for each location, the map cannot be shown up because the marker is a bitmap image.
And 1 million markers consume too much memory on my laptop (with 8 GB mem).
The code is:
public void add_marker(List<Tuple<double, double>> latLongList, ref GMapControl myMap)
{
System.Windows.Media.Imaging.BitmapImage bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.UriSource = new Uri(#"C:\djx_2014_6_3\my_projects\test_gmap_dot_net\GMap_WPF\try1\try_gmap_wpf\try_gmap_wpf\images\map_marker.png", UriKind.Absolute);
bitmapImage.DecodePixelHeight = 5;
bitmapImage.DecodePixelWidth = 5;
bitmapImage.EndInit();
foreach(var v in latLongList)
{
GMap.NET.PointLatLng point = new GMap.NET.PointLatLng(v.Item1, v.Item2);
GMapMarker marker = new GMapMarker(point);
System.Windows.Controls.Image image = new System.Windows.Controls.Image();
image.Source = bitmapImage;
marker.Shape = image;
marker.ZIndex = 5;
myMap.Markers.Add(marker);
}
}
I do not want to use the image as markers but I cannot find out how to use default marker in openStreetMap.
Any help would be appreciated.
WPF wasn't designed to be used for things like this. First of all you're creating a Bitmap for each tag, which is a user control and comes with some pretty heavy overhead for GUI hit-testing and binding etc. Secondly, WPF renders with DirectX, which means at some point all that data has to be set up with vertex buffers and uploaded into the graphics card. If you use data binding or try to create separate UI elements then this is going to take a lot of initial set-up time and memory, as you have already discovered. And if you try to draw them yourself (e.g. by creating your own user control and overriding OnRender) then it can be even worse, since all that work is now being done every frame (apart from buffered stuff which still incurs the initial setup anyway so you're back to square one).
If I had to do this myself I would start by organizing the data set with an appropriate 2D structure such as a k-d tree, an R*-tree or even a basic quad-tree. This will allow you to quickly determine at any given moment which markers are in the view frustum.
Next, I would add the appropriate bindings to scrollbars etc so that I could monitor exactly where the current view frustum was, and then each frame I would update the list of visible tags based on that. So long as you don't have more than a few thousand objects comes into view at once you should be ok, otherwise you'll have to stagger the updates over multiple frames with a queue.
If that doesn't suit your needs then you really have only two options left: 1) generate the raw bitmap data yourself manually, or 2) use a more suitable technology.
The browser would render a webpage faster if it knows the images dimensions. But how can I assign the Width and Height in ASP.NET automatically?
I can do a server control extending Image that would query the image size using GDI+ and assign those values to its own Width and Height properties.
But there are several things that worries me and would like to hear opinions:
Cache: What is the best way to implement cache? I would like to cache the Height and Width values across all pages for each image.
Which method should I use to query the image size? The constructor or another method (OnInit, OnPreRender, etc, etc)?
Is it GDI+ the best option to query image size, or is there any other efficient way?
How can I query the size for remotes images?
Of course I have an idea of how to do all that I mentioned, but I wanted to hear some thoughts.
http://code.google.com/speed/page-speed/docs/rendering.html#SpecifyImageDimensions
EDIT: This is what I have so far:
[ToolboxData("<{0}:AutoSizeImage runat=server></{0}:AutoSizeImage>")]
public class AutoSizeImage : Image
{
protected override void OnPreRender(EventArgs e)
{
if (Width.Value + Height.Value == 0)
{
if (IsLocal(ImageUrl))
{
using (System.Drawing.Image img = System.Drawing.Image.FromFile(Context.Server.MapPath(ImageUrl)))
{
Width = img.Width;
Height = img.Height;
}
}
else
{
System.Net.WebRequest request = System.Net.WebRequest.Create(ImageUrl);
using (System.Net.WebResponse response = request.GetResponse())
using (System.IO.Stream responseStream = response.GetResponseStream())
using (System.Drawing.Image img = System.Drawing.Image.FromStream(responseStream))
{
Width = img.Width;
Height = img.Height;
}
}
}
base.OnPreRender(e);
}
private bool IsLocal(string p)
{
return !(p.StartsWith("http://") || p.StartsWith("https://") || p.StartsWith("ftp://"));
}
}
It works beautifully, but I need to implement cache now.
I want to cache the output of this control for each value of ImageUrl, that is, I want the OnPreRender method to be called once for each image. Is that possible?
If you are going to be querying the image size on the fly, you might end up making things slower. Of course it all depends on how your application works.
If I were to try to do something similar, I would get the image dimensions at the time when the image is uploaded. (or when it was created using a filesystem watcher). I would then store this information in a database and then cache against the database.
If the size of images will change foreach user that are using the app, then you will have to use Session or Cookie.
Otherwise, if the size of images will not change (always the same size, user independent), then maybe better you use Cache.
Which method should I use to query the image size? The constructor or another method (OnInit, OnPreRender, etc, etc)?
In PreRender, because at this time all your controls are already created. This is the best moment to set the properties of your controls.
In your scope, I think so. The GDI+ is optimized for it.
Remote images?
I am going to use Image Optimization Framework that generates sprites and writes the image width and height so no need to reinvent the wheel.
https://web.archive.org/web/20211020150102/https://www.4guysfromrolla.com/articles/101310-1.aspx
So I have a custom Button class in a Winforms app written in C# 4.0. The button holds a static image normally, but when a refresh operation takes place it switches to an animated AJAX-style button. In order to animate the image I have a timer set up that advances the image animation on every tick and sets that as the button image. That's the only way I can get it to work. The solution I have isn't that efficient; any advice would be helpful.
So two questions:
1. Is there an easier way - as in am I overlooking some feature I should be using?
2. Is there a better way to manually animate the image?
Find code below of what I'm doing on each tick. The first area of improvement: maybe copy each frame of the image to a list? Note the _image.Dispose(); failing to dispose of a local Image was causing memory leaks.
Thanks for any advice here. I will post something online and link it once I have an efficient solution.
private void TickImage()
{
if (!_stop)
{
_ticks++;
this.SuspendLayout();
Image = null;
if(_image != null)
_image.Dispose();
//Get the animated image from resources and the info
//required to grab a frame
_image = Resources.Progress16;
var dimension = new FrameDimension(_image.FrameDimensionsList[0]);
int frameCount = _image.GetFrameCount(dimension);
//Reset to zero if we're at the end of the image frames
if (_activeFrame >= frameCount)
{
_activeFrame = 0;
}
//Select the frame of the animated image we want to show
_image.SelectActiveFrame(dimension, _activeFrame);
//Assign our frame to the Image property of the button
Image = _image;
this.ResumeLayout();
_activeFrame++;
_ticks--;
}
}
I guess Winforms is not so reach in animation capabilities on its own. If you want more advanced animation use may consider some third-party solutions.
I think you should not load image from resource every tick. The better way is to preload image frames one and hold the reference. Then use it to set appropriate frame every tick.
As I've recently tested, animated gifs are animating well without any additional coding, at least on standard buttons. But if you still need to aminate frames manually, you may try something like this:
// put this somewhere in initialization
private void Init()
{
Image image = Resources.Progress16;
_dimension = new FrameDimension(image.FrameDimensionsList[0]);
_frameCount = image.GetFrameCount(_dimension);
image.SelectActiveFrame(_dimension, _activeFrame);
Image = image;
}
private void TickImage()
{
if (_stop) return;
// get next frame index
if (++_activeFrame >= _frameCount)
{
_activeFrame = 0;
}
// switch image frame
Image.SelectActiveFrame(_dimension, _activeFrame);
// force refresh (NOTE: check if it's really needed)
Invalidate();
}
Another option is to use ImageList property with preloaded static frames and cycle ImageIndex propery just as you do it with SelectActiveFrame above.