Exemplo n.º 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);
        }