예제 #1
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);
        }
예제 #2
0
        /// <summary>
        /// Get everything setup to show the PDF document
        /// </summary>
        /// <param name="docSequence"></param>
        /// <param name="initialPage">The page that should be shown when we start up. Zero indexed</param>
        /// <param name="screen">The screen that hosts everything (routing!)</param>
        public FullTalkAsStripViewModel(IScreen screen, PDFFile file)
        {
            Debug.Assert(file != null);
            Debug.Assert(screen != null);

            HostScreen = screen;

            // We basically re-set each time a new file comes down from the top.

            Pages = new ReactiveList <PDFPageViewModel>();

            var pageSizeChanged = file.WhenAny(x => x.NumberOfPages, x => x.Value)
                                  .DistinctUntilChanged()
                                  .ObserveOn(RxApp.MainThreadScheduler);

            var b = from newPageLength in pageSizeChanged
                    let np = Pages.Count
                             from allpages in CreateNPages(newPageLength - np, np, file)
                             select new {
                numPages   = newPageLength,
                freshPages = allpages
            };

            b
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe(info => SetNPages(info.numPages, info.freshPages));

            // Page navigation. Make sure things are clean and we don't over-burden the UI before
            // we pass the info back to the UI!
            _moveToPage = new ReplaySubject <int>(1);
            _loaded     = new ReplaySubject <Unit>(1);
            MoveToPage  = _moveToPage
                          .CombineLatest(_loaded, (p, _) => p)
                          .Select(scrubPageIndex)
                          .DistinctUntilChanged();

            PageForward = ReactiveCommand.Create();
            PageForward
            .Cast <int>()
            .Select(pn => pn + 1)
            .Subscribe(_moveToPage);

            PageBack = ReactiveCommand.Create();
            PageBack
            .Cast <int>()
            .Select(pn => pn - 1)
            .Subscribe(_moveToPage);

            PageMove = ReactiveCommand.Create();
            PageMove
            .Cast <int>()
            .Subscribe(_moveToPage);
        }