alpha0010 / react-native-pdf-viewer

Minimalist PDF viewer for React Native
MIT License
73 stars 10 forks source link

rendering quality #13

Closed harrisontaee closed 2 years ago

harrisontaee commented 2 years ago

Is there any way to improve the rendering quality (DPI) of the pdf?

I've adapted the library code to use a ScrollView as opposed to a FlatList as I require zooming capabilities. When zooming, it's apparent the quality isn't great so need a way to improve this.

alpha0010 commented 2 years ago

The trouble with ScrollView zoom is that, as you noticed, it just does pixel interpolation (also zoom only supported on iOS). No events are passed to the child elements to know that zoom occurred.

This library will render pixels at the detail level correct for its dimensions. To increase DPI, you could try something like <View style={{ transform: [{ scale: 0.5 }] }}><PdfView ... /></View>. <PdfView /> will likely need to be passed a style prop specifying width to be double what is required (not sure if you have measure, of if using '200%' will work). Can of course increase DPI further by using a smaller scale for transform, and larger width on inner view. Be cautious of memory requirements, since this library holds all pixels of rendered views in memory, regardless of if they are on screen or not.

If displaying a single page at a time, you could try adapting https://github.com/alpha0010/react-native-pdf-viewer/issues/7#issuecomment-839908031.

harrisontaee commented 2 years ago

Ah fantastic! Thanks so much for the swift response, really appreciate it!

This works great apart from one tiny issue that was raised in #3. When applying any sort of scale to the PdfView, it became plagued by "black bars". Simple fix was to wrap PdfView in an extra View. I'll attach an image of the issue, but aside, all working great!

import * as DocumentPicker from "expo-document-picker";

import { Dimensions, ScrollView, View } from "react-native";
import { PdfUtil, PdfView } from "react-native-pdf-light";
import React, { useEffect, useRef, useState } from "react";

import { Cross } from "../components/global/icons";
import TopBar from "../components/global/top-bar";

const SCREEN_X = Dimensions.get("window").width;
const MAX_SCALE = 2;

const SheetMusic = ({ navigation }) => {
  const [source, setSource] = useState(null);
  const [pageData, setPageData] = useState([]);
  const scrollRef = useRef(null)

  useEffect(() => {
    const getSizes = async () => {
      const sizes = await PdfUtil.getPageSizes(source);
      setPageData(sizes);
    }
    if (!!source) getSizes();
  }, [source])

  return (
    <View style={{ flex: 1, backgroundColor: "#f3f3f3" }}>
      <TopBar
        leftFunction={() => navigation.navigate("Home")}
        rightIcon={<Cross size={14} />}
        rightFunction={async () => {
          const result = await DocumentPicker.getDocumentAsync();
          if (!!result?.uri) setSource(result.uri.toString().substring(8, result.uri.length));
        }}
      />
      <ScrollView
        ref={scrollRef}
        maximumZoomScale={MAX_SCALE * 2}
        showsHorizontalScrollIndicator={false}
        contentContainerStyle={{ alignItems: "center" }}>
        {!!source && pageData?.length > 0 ?
          pageData.map((item, index) => (
            <View
              key={index}
              style={{
                width: SCREEN_X,
                height: SCREEN_X * item.height / item.width,
                alignItems: "center",
                justifyContent: "center",
                transform: [{ scale: 1 / MAX_SCALE }],
                overflow: "visible",
                backgroundColor: "transparent",
              }}>
              <View> // fixes black bars
                <PdfView
                  source={source}
                  page={index}
                  resizeMode="fitWidth"
                  style={{
                    width: SCREEN_X * MAX_SCALE,
                    height: SCREEN_X * MAX_SCALE * item.height / item.width,
                  }}
                />
              </View>
            </View>
          ))
        : null}
      </ScrollView>
    </View>
  );
};

export default SheetMusic;

example

ariq-d commented 3 weeks ago

Hi @harrisontaee I tried your code and it works, but was wondering did you manage to get this to also have working zoom in / zoom out on Android?

harrisontaee commented 3 weeks ago

Hi @ariq-d, I haven't tried it on Android unfortunately. The ScrollView doesn't support zooming by default on Android and I'm not aware of any elegant solutions out there to be honest. You could potentially wrap each page in a <Zoomable /> component from https://github.com/likashefqet/react-native-image-zoom. That would be what I'd try first.

Let me know if you find a solution 👍