readium / readium-sdk

A C++ ePub renderer SDK
BSD 3-Clause "New" or "Revised" License
388 stars 164 forks source link

There is any way to get current page and total pages? #286

Open paulocoutinhox opened 7 years ago

paulocoutinhox commented 7 years ago

Hi,

There is any way to get current page and total pages?

Thanks.

paulocoutinhox commented 7 years ago

I see example, and i get pages by chapter without problem. But i want get all pages like iBooks. There is a way? Thanks.

danielweck commented 7 years ago

Related: https://github.com/readium/readium-js/issues/16

paulocoutinhox commented 7 years ago

My code to solve part of problems. It gets the page count by section/chapter. But i need get all pages count.

    func updateToolbar() {
        // total de página e página atual
        var pageDataText = ""

        if let currentPageOpenPagesArray = currentPageOpenPagesArray {
            if currentPageOpenPagesArray.count > 0 {
                var pageNumbers = [String]()

                for pageDict in currentPageOpenPagesArray {
                    let spineItemIndex: Int = pageDict["spineItemIndex"] as! Int
                    let spineItemPageIndex: Int = pageDict["spineItemPageIndex"] as! Int
                    let pageIndex = currentPageIsFixedLayout ? spineItemIndex : spineItemPageIndex
                    pageNumbers.append(String(pageIndex + 1))
                }

                let currentPages = pageNumbers.joined(separator: "-")
                var pageCount = 0

                if currentPageOpenPagesArray.count > 0 {
                    let firstOpenPageDict = currentPageOpenPagesArray[0]
                    let number: Int = firstOpenPageDict["spineItemPageCount"] as! Int
                    pageCount = currentPageIsFixedLayout ? currentPageSpineItemCount : number
                }

                // isto pode ser necessário lá na frente 
                //let pageType = currentPageIsFixedLayout ? "FXL" : "reflow"

                pageDataText = String(format: "Página: %@ de %@", currentPages, String(pageCount))
            }
        }

        readerBottomOptions?.lbPage.text = pageDataText
    }
danielweck commented 7 years ago

Yes, there is a similar implementation in Readium SDK Launcher-iOS: https://github.com/readium/SDKLauncher-iOS/blob/master/Classes/EPubViewController.m#L640-L670

    if (m_currentPageOpenPagesArray == nil || [m_currentPageOpenPagesArray count] <= 0) {
        label.text = @"";
    }
    else {

        NSMutableArray *pageNumbers = [NSMutableArray array];

        for (NSDictionary *pageDict in m_currentPageOpenPagesArray) {

            NSNumber *spineItemIndex = [pageDict valueForKey:@"spineItemIndex"];
            NSNumber *spineItemPageIndex = [pageDict valueForKey:@"spineItemPageIndex"];

            int pageIndex = m_currentPageIsFixedLayout ? spineItemIndex.intValue : spineItemPageIndex.intValue;

            [pageNumbers addObject: [NSNumber numberWithInt:pageIndex + 1]];
        }

        NSString* currentPages = [NSString stringWithFormat:@"%@", [pageNumbers componentsJoinedByString:@"-"]];

        int pageCount = 0;
        if ([m_currentPageOpenPagesArray count] > 0)
        {
            NSDictionary *firstOpenPageDict = [m_currentPageOpenPagesArray objectAtIndex:0];
            NSNumber *number = [firstOpenPageDict valueForKey:@"spineItemPageCount"];

            pageCount = m_currentPageIsFixedLayout ? m_currentPageSpineItemCount: number.intValue;
        }
        NSString* totalPages = [NSString stringWithFormat:@"%d", pageCount];

        label.text = LocStr(@"PAGE_X_OF_Y", [currentPages UTF8String], [totalPages UTF8String], m_currentPageIsFixedLayout?[@"FXL" UTF8String]:[@"reflow" UTF8String]);
    }
paulocoutinhox commented 7 years ago

Hi, i already do it im my project. But it get the current and total pages for the current "chapter".

func updateToolbar() {
        // total de páginas e página atual
        pageDataText = ""

        if let currentPageOpenPagesArray = currentPageOpenPagesArray {
            if currentPageOpenPagesArray.count > 0 {
                var pageNumbers = [String]()

                for pageDict in currentPageOpenPagesArray {
                    let spineItemIndex: Int = pageDict["spineItemIndex"] as! Int
                    let spineItemPageIndex: Int = pageDict["spineItemPageIndex"] as! Int
                    let pageIndex = currentPageIsFixedLayout ? spineItemIndex : spineItemPageIndex
                    pageNumbers.append(String(pageIndex + 1))
                }

                let currentPages = pageNumbers.joined(separator: "-")
                var pageCount = 0

                if currentPageOpenPagesArray.count > 0 {
                    let firstOpenPageDict = currentPageOpenPagesArray[0]
                    let number: Int = firstOpenPageDict["spineItemPageCount"] as! Int
                    pageCount = currentPageIsFixedLayout ? currentPageSpineItemCount : number
                }

                // isto pode ser necessário lá na frente
                //let pageType = currentPageIsFixedLayout ? "FXL" : "reflow"

                pageDataText = String(format: "Página: %@ de %@", currentPages, String(pageCount))
            }
        }

        readerBottomOptions?.lbPage.text = pageDataText
}

But i want get the total pages of all chapters/spines.

cuneyttyler commented 1 year ago

Hi @paulocoutinhox, did you manage to get current page no and total page count?

guidomagaldi commented 1 year ago

Hello @cuneyttyler , did you manage to do it?

cuneyttyler commented 1 year ago

@guidomagaldi Yes, I calculated the current page by considering the sizes of each chapter files and looking at the percentage of scroll in the current chapter. I assumed the size of one page is 7 kb. You can use the code below:

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

public class PageCalculator {
    private Map<String, Long> sizeMap = new LinkedHashMap<>();
    private long totalSize;
    private int bytesPerPage = 7000;

    public PageCalculator(String filePath) throws IOException {
        calcTotalSize(filePath);
    }

    private void calcTotalSize(String filePath) throws IOException {
        ZipFile zip = new ZipFile(filePath);

        String content = null;
        for (Enumeration e = zip.entries(); e.hasMoreElements(); ) {
            ZipEntry entry = (ZipEntry) e.nextElement();
            if (!entry.isDirectory() && entry.getName().contains("content.opf")) {
                content = getTxtFiles(zip.getInputStream(entry));
            }
        }

        Document doc = Jsoup.parse(content);
        Elements spines = doc.getElementsByTag("package").first().getElementsByTag("spine").first().getElementsByTag("itemref");
        List<String> chapterFileNames = new ArrayList<>();
        for (Element el : spines) {
            String id = el.attr("idref");
            if(el.attr("linear") == null || !el.attr("linear").equals("no")) {
                String chapter = doc.getElementsByTag("package").first().getElementById(id).attr("href");
                chapterFileNames.add(chapter);
            }
        }

        for(String chapter: chapterFileNames) {
            for (Enumeration e = zip.entries(); e.hasMoreElements(); ) {
                ZipEntry entry = (ZipEntry) e.nextElement();
                if (!entry.isDirectory() && entry.getName().contains(chapter)) {
                    sizeMap.put(entry.getName(), entry.getSize());
                }
            }
        }

        totalSize = sizeMap.values().stream().reduce(0l,Long::sum);
    }

    public int getTotalPages() {
        return (int)(totalSize / bytesPerPage);
    }

    public int getCurrentPage(int percent, int chapterIndex) {
        long prevSize = 0;
        int i = 0;
        for(String chapter: sizeMap.keySet()) {
            if(chapterIndex == i) {
                break;
            }
            i++;
            prevSize += sizeMap.get(chapter);
        }

        Long currentChapterSize = (Long) sizeMap.values().toArray()[chapterIndex];
        double currentChapterSizePerc = currentChapterSize.doubleValue() * ((double)percent/100);

        return (int)((prevSize + currentChapterSizePerc ) / bytesPerPage );
    }

    public class ProgressResponse {
        public int chapterIndex;
        public double viewScrollMarginPerc;

        public ProgressResponse(int chapterIndex, double viewScrollMarginPerc) {
            this.chapterIndex = chapterIndex;
            this.viewScrollMarginPerc = viewScrollMarginPerc;
        }
    }

    public ProgressResponse getPageFromProgressPercentage(double percent) {
        double percSize = (percent * totalSize);

        int tempSize = 0;
        int progressChapterIndex = 0;
        long progressChapterSize = 0;
        for(int i = 0; i < sizeMap.size(); i++) {
            String chapter = (String) sizeMap.keySet().toArray()[i];
            long size = sizeMap.get(chapter);

            tempSize += size;
            if(tempSize > percSize) {
                progressChapterIndex = i;
                progressChapterSize = size;
                break;
            }
        }

        int prevSize = 0;
        for(int i = 0; i < progressChapterIndex; i++) {
            String chapter = (String) sizeMap.keySet().toArray()[i];
            long size = sizeMap.get(chapter);
            prevSize += size;
        }

        double viewScrollMarginPerc = (percSize - prevSize) / progressChapterSize;

        return new ProgressResponse(progressChapterIndex,viewScrollMarginPerc - 0.02);
    }

    private static String getTxtFiles(InputStream in) {
        StringBuilder out = new StringBuilder();
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        String line;
        try {
            while ((line = reader.readLine()) != null) {
                out.append(line);
            }
        } catch (IOException e) {
            // do something, probably not a text file
            e.printStackTrace();
        }
        return out.toString();
    }
}
guidomagaldi commented 1 year ago

@cuneyttyler I will try this, thank you for your time! I really appreciate it :)