Git Product home page Git Product logo

cachedimage's People

Contributors

aybe avatar borningstar avatar djscribbles avatar floydpink avatar fossabot avatar genusatplay avatar n-ski avatar stackia avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

cachedimage's Issues

WinINet not caching images, probably because .net core 3.1

I've got a .Net Core 3.1 WPF project, the bitmap caching stuff doesn't seem to work, I suspect it's an issue with the .Net Core implementation. I havent investigated further to confirm, but if anyone else runs into it the dedicated caching mode should work.

A better way to cache image

BitmapImage has a UriCachePolicy property. You can simply set it to RequestCacheLevel.Default to get an IE-like cache policy with all exceptions handled properly.

        private static void ImageUrlPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            var url = e.NewValue as string;

            if (string.IsNullOrEmpty(url))
                return;

            var cachedImage = (Image) obj;
            var bitmapImage = new BitmapImage();
            bitmapImage.BeginInit();
            bitmapImage.UriSource = new Uri(url);
            bitmapImage.UriCachePolicy = new RequestCachePolicy(RequestCacheLevel.Default);
            bitmapImage.EndInit();
            cachedImage.Source = bitmapImage;
        }

There are also some issues in your code:

  • WebRequest exception is not handled properly. If an request responses 404, the application will crash.
  • Not thread-safety. If I have some CachedImage in the same view, and request the same url simultaneously, it will happen write-write confliction on the same file.
  • Memory wasting. You read all bytes from web response to memory then write to file. But you pass the file uri to BitmapImage, it will read all bytes from the file to memory again. Instead, it's better to directly construct a MemoryStream from the web response and pass it to BitmapImage.StreamSource.

I tried to rewrite FileCache.cs before I discovered the UriCachePolicy property of BitmapImage. This is what I have done and it worked correctly in my scenario where hundreds of CachedImage control request some random image simultaneously.

        // A private field to record if a file is being written.
        private static readonly Dictionary<string, bool> IsWritingFile = new Dictionary<string, bool>();

        public static async Task<MemoryStream> HitAsync(string url)
        {
            if (!Directory.Exists(AppCacheDirectory))
            {
                Directory.CreateDirectory(AppCacheDirectory);
            }
            var uri = new Uri(url);
            var fileNameBuilder = new StringBuilder();
            using (var sha1 = new SHA1Managed())
            {
                var canonicalUrl = uri.ToString();
                var hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(canonicalUrl));
                fileNameBuilder.Append(BitConverter.ToString(hash).Replace("-", "").ToLower());
                if (Path.HasExtension(canonicalUrl))
                    fileNameBuilder.Append(Path.GetExtension(canonicalUrl));
            }

            var fileName = fileNameBuilder.ToString();
            var localFile = string.Format("{0}\\{1}", AppCacheDirectory, fileName);
            var memoryStream = new MemoryStream();

            FileStream fileStream = null;
            if (!IsWritingFile.ContainsKey(fileName) && File.Exists(localFile))
            {
                using (fileStream = new FileStream(localFile, FileMode.Open, FileAccess.Read))
                {
                    await fileStream.CopyToAsync(memoryStream);
                }
                memoryStream.Seek(0, SeekOrigin.Begin);
                return memoryStream;
            }

            var request = WebRequest.Create(uri);
            request.Timeout = 30;
            try
            {
                var response = await request.GetResponseAsync();
                var responseStream = response.GetResponseStream();
                if (responseStream == null)
                    return null;
                if (!IsWritingFile.ContainsKey(fileName))
                {
                    IsWritingFile[fileName] = true;
                    fileStream = new FileStream(localFile, FileMode.Create, FileAccess.Write);
                }

                using (responseStream)
                {
                    var bytebuffer = new byte[100];
                    int bytesRead;
                    do
                    {
                        bytesRead = await responseStream.ReadAsync(bytebuffer, 0, 100);
                        if (fileStream != null)
                            await fileStream.WriteAsync(bytebuffer, 0, bytesRead);
                        await memoryStream.WriteAsync(bytebuffer, 0, bytesRead);
                    } while (bytesRead > 0);
                    if (fileStream != null)
                    {
                        await fileStream.FlushAsync();
                        fileStream.Dispose();
                        IsWritingFile.Remove(fileName);
                    }
                }
                memoryStream.Seek(0, SeekOrigin.Begin);
                return memoryStream;
            }
            catch (WebException)
            {
                return null;
            }
        }

In Image.cs:

        private static async void ImageUrlPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            var url = e.NewValue as string;

            if (string.IsNullOrEmpty(url))
                return;

            var memoryStream = await FileCache.HitAsync(url);
            if (memoryStream == null)
                return;

            try
            {
                var cachedImage = (Image) obj;
                var bitmapImage = new BitmapImage();
                bitmapImage.BeginInit();
                bitmapImage.StreamSource = memoryStream;
                bitmapImage.EndInit();
                cachedImage.Source = bitmapImage;
            }
            catch (Exception)
            {
                // ignored, in case the downloaded file is a broken or not an image.
            }
        }

Exception during using CachedImage item in an ItemTemplate inside a ListView of a UserControl

I was using the cachedImage:Image element inside the DataTemplate of a ListView inside a UserControl. The direct builds, both in Debug & Release flavors, were working just fine - but when I generated the setup file using Inno-setup & installed that in other machines, the page started crashing with the following log:

Set property 'System.Windows.Controls.ItemsControl.ItemTemplate' threw an exception.
Stack Trace:    at System.Windows.Markup.WpfXamlLoader.Load(XamlReader xamlReader, IXamlObjectWriterFactory writerFactory, Boolean skipJournaledProperties, Object rootObject, XamlObjectWriterSettings settings, Uri baseUri)
   at System.Windows.Markup.WpfXamlLoader.LoadBaml(XamlReader xamlReader, Boolean skipJournaledProperties, Object rootObject, XamlAccessLevel accessLevel, Uri baseUri)
   at System.Windows.Markup.XamlReader.LoadBaml(Stream stream, ParserContext parserContext, Object parent, Boolean closeStream)
   at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
   at MyApp.MyWindow.InitializeComponent() in E:\w_Development\DotNet\MyApp\MyWindow.xaml:line 1
   at MyApp.MyWindow..ctor(Window window) in E:\w_Development\DotNet\MyApp\MyWindow.xaml.cs:line 54
   at MyApp.MainWindow.<NavigateWithDelay>d__3.MoveNext() in E:\w_Development\DotNet\MyApp\MainWindow.xaml.cs:line 35
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c.<ThrowAsync>b__6_0(Object state)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.DispatcherOperation.InvokeImpl()
   at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)
   at MS.Internal.CulturePreservingExecutionContext.CallbackWrapper(Object obj)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at MS.Internal.CulturePreservingExecutionContext.Run(CulturePreservingExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Windows.Threading.DispatcherOperation.Invoke()
   at System.Windows.Threading.Dispatcher.ProcessQueue()
   at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
   at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
   at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
   at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
   at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
   at System.Windows.Application.RunDispatcher(Object ignore)
   at System.Windows.Application.RunInternal(Window window)
   at System.Windows.Application.Run(Window window)
   at MyApp.App.Main()

The DataTemplate is like the following:

<DataTemplate x:Key="MyItemTemplate">
            <Grid Margin="8 4 8 4" Background="#7aBa23">
                <Grid Margin="2" Background="White">
                    <!--<Grid.Effect>
                    <DropShadowEffect BlurRadius="5" ShadowDepth="2"/>
                </Grid.Effect>-->
                    <Grid.RowDefinitions>
                        <RowDefinition Height="{Binding MY_TILE_H}" MaxHeight="240"/>
                        <RowDefinition Height="32"/>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="{Binding MY_TILE_W1}" MaxWidth="256"/>
                        <ColumnDefinition Width="{Binding MY_TILE_W2}" MaxWidth="124"/>
                    </Grid.ColumnDefinitions>

                    <!--<Image Grid.Row="0" Grid.ColumnSpan="2"
                       Width="{Binding MY_TILE_W}" MaxWidth="380" 
                       Height="{Binding MY_TILE_H}" MaxHeight="240" 
                       Stretch="UniformToFill">
                        <Image.Source>
                            <BitmapImage UriCachePolicy="Revalidate"  
                                         UriSource="{Binding ImageUrl}" 
                                         CreateOptions="IgnoreImageCache"
                                         CacheOption="OnLoad"/>
                        </Image.Source>
                    </Image>-->
                    <cachedImage:Image Grid.Row="0" Grid.ColumnSpan="2"
                       Width="{Binding MY_TILE_W}" MaxWidth="380" 
                       Height="{Binding MY_TILE_H}" MaxHeight="240" 
                       Stretch="UniformToFill"
                       ImageUrl="{Binding ImageUrl}"/>
               ... ... ...
                </Grid>
            </Grid>
        </DataTemplate>

The custom UserControl, used under a TabControl in the MyWindow.xaml has the following skeleton:

<materialDesign:DialogHost x:Name="DialogProgress">
        <materialDesign:DialogHost.DialogContent>
            <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" 
                        Height="64" Width="Auto" x:Name="StpProgContent"
                        Orientation="Horizontal" Background="#7ABA23">
                <ProgressBar Width="24" Height="24" Margin="16"
                    Foreground="White"
                    Style="{DynamicResource MaterialDesignCircularProgressBar}"
                    IsIndeterminate="True"
                    Value="33"/>
                <TextBlock x:Name="ProgMsg" Text="Posting your order ..." 
                           Padding="12 8 12 8" VerticalAlignment="Center" 
                           Foreground="White" FontWeight="DemiBold" FontSize="18"/>
            </StackPanel>
        </materialDesign:DialogHost.DialogContent>
        <Grid Background="#FaFaFa">
            <Grid.RowDefinitions>
                <RowDefinition Height="3*"/>
                <RowDefinition Height="2*"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="512"/>
            </Grid.ColumnDefinitions>

       ... ... ...

            <ListView x:Name="MyListView" Grid.Column="0" 
                      ScrollViewer.VerticalScrollBarVisibility="Visible"
                      ScrollViewer.HorizontalScrollBarVisibility="Disabled"
                      ItemTemplate="{DynamicResource MyItemTemplate}" 
                      Grid.RowSpan="2" Margin="0 60 0 0"
                      SelectionChanged="MyListView_SelectionChanged">
                <!--PreviewMouseDown="MyListView_MouseDown"-->
                <ListView.ItemsPanel>
                    <ItemsPanelTemplate>
                        <WrapPanel Orientation="Horizontal"/>
                    </ItemsPanelTemplate>
                </ListView.ItemsPanel>
            </ListView>
        ... ... ...

        </Grid>
    </materialDesign:DialogHost>

I really like the result this library is delivering in the direct builds, but is there any kind of clash with InnoSetup or any other view in release-mode with the above codes that it's crashing?

I am not an expert in WPF or .Net - but any kind of help can allow me to explore & solve this issue in the right way.

Btw, thanks for the library.

Uri Format Exception In UserControl without any CachedImage Control inside.

Hello.

I have in Visual Studio 2019 the issue of an UriFormatException.

I created a new UserControl as a View. Moved to a Namespace "Views".

But I don´t have Anything placed in the UserControl yet.

No ImageCache References or a ImageCache-Control.

<UserControl x:Class="Views.SettingsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="clr-namespace:SerienNaGer_Desktop.ViewModels"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<Grid />
</UserControl>

So I get Squiggly Lines under "<UserControl ", and following Exception.

UriFormatException: Ungültiger URI: Das URI-Format konnte nicht bestimmt werden.
UriFormatException: Invalid URI: The URI-Format could not be determined. <-Manual translation

StackTrace:
bei System.Uri.CreateThis(String uri, Boolean dontEscape, UriKind uriKind)
   bei System.Uri..ctor(String uriString)
   bei CachedImage.Image.<ImageUrlPropertyChanged>d__0.MoveNext()
--- Ende der Stapelüberwachung vom vorhergehenden Ort, an dem die Ausnahme ausgelöst wurde ---
   bei System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c.<ThrowAsync>b__6_0(Object state)
   bei System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   bei System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)

I had a Workaround for the other ImageCache-Controls, where I can´t use the XAML-Designer except I Remove the ImageUrl-Property from the Control temporarily.

This is somehow strange to me.
How does the ImageCache can "Bleed" into a UserControl?

thx in advance Zui

IsAsync in binding seems to have no effect

When using the default Image control like this:

 <Image Source="{Binding SelectedSeries.FanArt, IsAsync=True}"/>

the image is loaded on a different thread and the UI does not freeze.

However, when using the CachedImage version:

<c:Image ImageUrl="{Binding SelectedSeries.FanArt, IsAsync=True}"/>

the UI freezes while loading the image.

Am I missing something here or is this an issue?

Dedicated mode not display image

FileCache.AppCacheMode = FileCache.CacheMode.Dedicated;
FileCache.AppCacheDirectory = DirectoryHelper.GetAppRootDirectory(".Caches/Thumbnails/");

AppCacheDirectory == "D:\\Documents\\Visual Studio 2022\\Projects\\XX\\XX\\bin\\Debug\\net6.0-windows\\.Caches\\Thumbnails\\"

WinINet mode work fine.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.