Exemplo n.º 1
0
        public async Task MakeSureNothingRenderedWhenImageCached()
        {
            // The exact image we need is in the cache. So we should never make a
            // request to load the PDF file or PdfDocument.

            // Get the infrastructure setup
            var f    = new dummyFile();
            var data = await TestUtils.GetFileAsBytes("test.pdf");

            int loaderCalled = 0;

            f.GetStream = () =>
            {
                loaderCalled++;
                throw new InvalidOperationException();
            };

            // Create the cache, and add everything into it that the system should need.
            var dc = new dummyCache();
            await f.SaveFileInCache(f.DateToReturn, data, dc);

            var dt = await f.GetCacheCreateTime(dc);

            var pageSize = new IWalkerSize()
            {
                Width = 1280, Height = 720
            };
            await dc.InsertObject(string.Format("{0}-{1}-p1-DefaultPageSize", f.UniqueKey, dt.Value.ToString()), pageSize);

            var imageData = new byte[] { 0, 1, 2, 3, 4 };
            await dc.Insert(string.Format("{0}-{1}-p1-w100-h56", f.UniqueKey, dt.Value), imageData);

            Debug.WriteLine("Setup is done, and data has been inserted into the cache. Testing starting");

            // Create the rest of the infrastructure.
            var vm = new FileDownloadController(f, dc);
            var pf = new PDFFile(vm);

            // Now, build the VM

            var pdfVM = new PDFPageViewModel(pf.GetPageStreamAndCacheInfo(1), dc);

            // Subscribe so we can "get" the image.
            MemoryStream lastImage = null;

            pdfVM.ImageStream.Subscribe(img => lastImage = img);
            Assert.IsNull(lastImage);

            // Render, and make sure things "worked"
            pdfVM.RenderImage.Execute(Tuple.Create(IWalker.ViewModels.PDFPageViewModel.RenderingDimension.Horizontal, (double)100, (double)100));
            vm.DownloadOrUpdate.Execute(null);

            await TestUtils.SpinWait(() => lastImage != null, 2000);

            Assert.AreEqual(0, loaderCalled);
            Assert.IsNotNull(lastImage);
            Assert.AreEqual(4, dc.NumberTimesInsertCalled); // Nothing new should have happened
        }
Exemplo n.º 2
0
        /// <summary>
        /// Initialize with the page that we should track.
        /// </summary>
        /// <param name="pageInfo">A stream of cache tags and the PDF pages associated with it.</param>
        /// <remarks>We are really only interested in the first PdfPage we get - and we will re-subscribe, but not hold onto it.</remarks>
        public PDFPageViewModel(IObservable <Tuple <string, IObservable <PdfPage> > > pageInfo, IBlobCache cache = null)
        {
            _cache = cache ?? Blobs.LocalStorage;

            // Render an image when:
            //   - We have at least one render request
            //   - ImageStream is subscribed to
            //   - the file or page updates somehow (new pageInfo iteration).
            //
            // Always pull from the cache first, but if that doesn't work, then render and place
            // in the cache.

            // Get the size of the thing when it is requested. This sequence must be finished before
            // any size calculations can be done!
            var imageSize = from pgInfo in pageInfo
                            from sz in _cache.GetOrFetchPageSize(pgInfo.Item1, () => pgInfo.Item2.Take(1).Select(pdf => pdf.Size.ToIWalkerSize()))
                            select new
            {
                PGInfo = pgInfo,
                Size   = sz
            };
            var publishedSize = imageSize
                                .Do(info => _pageSize = info.Size)
                                .Select(info => info.PGInfo)
                                .Publish().RefCount();

            _pageSizeLoaded = publishedSize.AsUnit();

            // The render request must be "good" - that is well formed. Otherwise
            // we will just ignore it. This is because sometimes when things are being "sized" the
            // render request is malformed.
            RenderImage = ReactiveCommand.Create();
            var renderRequest = RenderImage
                                .Cast <Tuple <RenderingDimension, double, double> >()
                                .Where(info => (info.Item1 == RenderingDimension.Horizontal && info.Item2 > 0) ||
                                       (info.Item1 == RenderingDimension.Vertical && info.Item3 > 0) ||
                                       (info.Item1 == RenderingDimension.MustFit && info.Item2 > 0 && info.Item3 > 0)
                                       );

            // Generate an image when we have a render request and a everything else is setup.
            ImageStream = from requestInfo in Observable.CombineLatest(publishedSize, renderRequest, (pSize, rr) => new { pgInfo = pSize, RenderRequest = rr })
                          let imageDimensions = CalcRenderingSize(requestInfo.RenderRequest.Item1, requestInfo.RenderRequest.Item2, requestInfo.RenderRequest.Item3)
                                                from imageData in _cache.GetOrFetchPageImageData(requestInfo.pgInfo.Item1, imageDimensions.Item1, imageDimensions.Item2,
                                                                                                 () => requestInfo.pgInfo.Item2.SelectMany(pdfPg =>
            {
                var ms  = new MemoryStream();
                var ra  = WindowsRuntimeStreamExtensions.AsRandomAccessStream(ms);
                var opt = new PdfPageRenderOptions()
                {
                    DestinationWidth = (uint)imageDimensions.Item1, DestinationHeight = (uint)imageDimensions.Item2
                };
                return(Observable.FromAsync(() => pdfPg.RenderToStreamAsync(ra).AsTask())
                       .Select(_ => ms.ToArray()));
            }))
                                                select new MemoryStream(imageData);
        }