Open vblazenka opened 6 years ago
Hey, @fchasen. Thank you for this cool library you and other people created.
I was wondering if you could give me some tips for regarding my question? I would love to help back.
Thank you!
@wedranb if you look at the wiki under Updating to v0.3 from v0.2 you find that they have a new method:
generatePagination() was far too resource intensive, as it rendered every page. It has been replaced by book.locations.generate(600) which will create a CFI for every X characters in the book.
From my understanding depending on the argument you pass (150 being the default) it goes through the book and marks where it is every X characters. You get back a big array of pages. I don't find this very helpful though because it's not actual pages, just a rough estimate. Using this method you could skip a page if your number is too high or count a page twice if too low. It seems that when you use rendition.currentLocation()
it has an end
and start
. In those is the list of pages in that chapter but that can be wrong based off of your screen size. All in all, there seems to be no easy way to do it.
Users want total page number. Support for it would be great.
After the current section is rendered, rest of book could be initialised to calculate pages.
book.locations.generate
currently doesn't help.
Getting the page for a currently rendered chapter is simple enough, but rendering the entire book out in each users browser to get page numbers just wasn't practical.
Would be amazing to render out the entire book server side and save the pages as an epub page list. With Puppeteer it should not be too hard to setup.
How about showing the user a page number in the format chapter.page (e.g. 1.1, 1.1, 1.2, 1.3, 1.4, 1.5, 2.1, 2.3, etc)? It would still increment predictably and be easy to read. It would also be a lot faster and easier to generate than full pagination, but still better fit your use case than locations.
@geek1011 You can do that with numbers from rendition.currentLocation()
I've made an extra offscreen rendering of the book. I use that to load one section at a time and get page counts. Takes a while but it's no problem since it's all in the background after the book has loaded. Will show a spinner or similar where page counts are shown while loading them.
@geek1011 I think the basic user (who is just reading with the epub, never coded anything) will be confused by that page numbering system. Wouldn't want to have to tell every user why their page numbers are weird.
@fchasen thanks for that. I'll give puppeteer a shot and let you know!
book.locations.generate
returns a promise containing an array of all the CFI locations. Correct me if I am wrong but if these locations are all the pages then we can just get the length of the array.
this.book.ready.then((book) => {
return this.book.locations.generate();
}).then(locations => {
console.log("Total Pages?: ", locations.length);
});
@askilondz You are wrong. It generates cfi ranges for every x (default 150) characters which has nothing to do with pages.
@mikkelvp :-) thanks for the clarification.
Hi guys! Has anyone found a practical, and hopefully accurate, solution to this?
So far the approaches I'm considering are:
A) @fchasen solution sounds nice, but doesn't the number of pages depend also on screen and font size?
B) Use book.locations.generate
, though it has nothing to do with pages
Also, what about fixed-layout epubs?
@fgilio I've described my solution earlier in this issue. A) Yes, if you have applied styling you will need to wait for browser to render with that styling before getting page count for a section.
Hi @mikkelvp That's what I was afraid of. There seems like there is no way of preprocessing this server side only once. It would need to be generated either client side, or with a, probably overly complex, server side solution that takes into account this variables (screen size and font size, and maybe others). The server side solution could also do it on demand and store the results for the next time the epub and variables match. Or maybe I'm just overly complicating this, but this is when a pdf sounds like something super simple 😅
@mikkelvp Could you show your code for how you're rendering each section for the offscreen rendering you are doing? I like this approach for getting the page count. I'm looping through each spine item and attempting to render each item/section item.render()
but having some issues would be curious to see your solution. Thanks!
@fchasen I want to show more sections together, e.g. if the page is having an image, breaking it into sections shows part of face then neck then chest and so on, and which does not make any sense. Who can help?
Here's the best solution that I have come up with for getting page number and total pages based on setting the number of characters per page:
// Initialize the book
let bookUri = "https://s3.amazonaws.com/moby-dick/moby-dick.epub";
let book = ePub(bookUri, {});
let rendition = book.renderTo('epubContainer', {
flow: 'paginated',
manager: 'continuous'
spread: 'always'
width: "100% - 106px",
height: this.calculateReaderHeight()
});
// Display the book
let displayed = rendition.display(window.location.hash.substr(1) || undefined);
displayed.then(function() {
console.log('rendition.currentLocation():', rendition.currentLocation());
});
// Generate location and pagination
book.ready.then(function() {
const stored = localStorage.getItem(book.key() + '-locations');
console.log('metadata:', book.package.metadata);
if (stored) {
return book.locations.load(stored);
} else {
return book.locations.generate(1024); // Generates CFI for every X characters (Characters per/page)
}
}).then(function(location) { // This promise will take a little while to return (About 20 seconds or so for Moby Dick)
localStorage.setItem(book.key() + '-locations', book.locations.save());
});
// When navigating to the next/previous page
rendition.on('relocated', function(locations) {
progress = book.locations.percentageFromCfi(locations.start.cfi);
console.log('Progress:', progress); // The % of how far along in the book you are
console.log('Current Page:', book.locations.locationFromCfi(locations.start.cfi);
console.log('Total Pages:', book.locations.total);
});
EPubJS will use these generated epubCFI's for a "start" and an "end" for each page. The bigger the number you set in the book.locations.generate()
method, the less number of pages you have. This is also why I'm logging the book.package.metadata
so that I can determine if the publisher has set a "characters per page" so I can use that value. I'm still early on in my epub.js
development but have learned quite a bit over the past week.
I hope this can help someone.
@sengemann how accurate is this? What if the user changes font size or screen size?
It updates accordingly when the relocated
event is triggered. I will have to see how to manually trigger that event for the actual values to change.
It updates accordingly when the
relocated
event is triggered. I will have to see how to manually trigger that event for the actual values to change.
As far as your understanding, if I call rendition.currentLocation()
when on a given page, will the returned start and end CFIs be the actual start and end CFIs of the page 100% of the time? Or are these just estimates, so that if I go to one of these start CFIs, it may not bring me to the correct page...
If anyone else has an answer to this it will likewise be appreciated.
The documentation of this library is really bad. Seems to be very good project but I'm losing a lot of time guessing how it works :(((((
Hi,How to get current page and total number of pages? Does anybody have a solution? PLease 🥺
@MrXCQ You can't. :) In this thread you can find possible solutions but nothing is accurate.
It updates accordingly when the
relocated
event is triggered. I will have to see how to manually trigger that event for the actual values to change.As far as your understanding, if I call
rendition.currentLocation()
when on a given page, will the returned start and end CFIs be the actual start and end CFIs of the page 100% of the time? Or are these just estimates, so that if I go to one of these start CFIs, it may not bring me to the correct page...If anyone else has an answer to this it will likewise be appreciated.
The only time that the method rendition.currentLocation()
has not been returning the correct location was immediately after adjusting the font-size via the themes()
method. I have a bug created for that here: https://github.com/futurepress/epub.js/issues/982
@sengemann would you please give us the calculateReaderHeight() function?
@hesampour, it's pretty simple once you know what your variables are:
calculateReaderHeight() {
let h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
// On the next line you need to factor in the height of any of your UI elements.
// You could just take the values if they are static or use jQuery to get the heights dynamically (that would be the preferred method)
h = h - 50 - 68 - 44; // 50: Header Height, 68: Footer Height, 44: 22px * 2 top/bottom margin
return h;
},
The documentation of this library is really bad. Seems to be very good project but I'm losing a lot of time guessing how it works :(((((
thats right
does anyone have a solution for pagination?
I'm messing around with the react native implementation, and adjusting it to my needs here https://github.com/sbrighiu/epubjs-rn. @hrkazemi you can look in the repo for pagingEnabled={true}.
I've also found the documentation for epub.js http://epubjs.org/documentation/0.3/, if newcomers don't find it immediately
Would be really nice to be able to get number of pages and current page, but as my content varies from device size to device size and from epub to epub, I don't see a reliable way of doing it :(
What about the completion? Like a percentage? 61%
@sbrighiu and @MrXCQ This is the best solution that I have came up with to get the percentage, current page, page range and total pages: https://github.com/futurepress/epub.js/issues/744#issuecomment-492300092
There are a few requirements for this to work:
book.locations.generate(X)
where X
is the number of characters you want to have on a pageWhat about the completion? Like a percentage? 61% @sbrighiu I did use the mupdf library instead. it's work for both epub & pdf (and great if you are doing native but has poor document).
@fchasen help me please... I have to different .epub, but crafted the same way... i dont know why one of then dont generate the locations, get the spine and everything but location returns -1 only. The promise dont complete and dont get in on .then().
Promisse sshow this on every part: [Exception: TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them at Function.o (
seems like this one is still open. While I was trying to figure things out, I just found a solution that looks like enough for my current problem. In the Rendition object, we have location as a static member. In location, there are start and end objects so in these objects we have an index ( which I assume right now as a section) and in displayed there is a page and total numbers which belong to this index.
You can check the docs again for the detailed structure.
Also here below I inserted a screenshot for a better understanding.
Meanwhile, If anyone got a better idea please let me know.
seems like this one is still open. While I was trying to figure things out, I just found a solution that looks like enough for my current problem. In the Rendition object, we have location as a static member. In location, there are start and end objects so in these objects we have an index ( which I assume right now as a section) and in displayed there is a page and total numbers which belong to this index.
You can check the docs again for the detailed structure.
Also here below I inserted a screenshot for a better understanding.
Meanwhile, If anyone got a better idea please let me know.
Here, you only get the Total page and current page for the current chapter, not the overall. 😥
this is not working
Some thoughts after beating my head against this problem for a few hours:
Page numbers are a lost cause
IMO "page number" is not a particularly helpful concept when it comes to ebooks. An "accurate" page number that increments or decrements by exactly 1 every time the user moves backwards or forwards by 1 page must be calculated on the client. There is no way around this - this type of page number is dependent on the exact rendering of the book which is dependent on the client's viewport, the client's interpretation of fonts, the client's interpretation of CSS, etc.
Even if you were willing to deal with this limitation and churn out page numbers on the client, the results are not that helpful to the user. You are showing them an arbitrary page number that won't match up with page numbers generated on another other device or even on the same device if the view is rotated resized. Imagine reading a book, noting that you were on page 3 of 450, rotating your device, and then discovering that you are now on page 2 of 300. This is confusing (and unavoidable).
A better metric
I think total % progress in the book is a much better metric. This can be calculated with locations as demonstrated in some of the responses above and shouldn't change appreciably if the user switches devices, rotates their screen, resizes their browser, etc. For a little more context you could combine this with "X pages left in chapter" which doesn't require any extra calculations (although this number would change if the view is resized/rotated/etc.).
Generating locations server side
@fchasen mentioned using Puppeteer to generate locations on the server. I'm sure this would work, but Puppeteer tends to be overkill. I did a little testing and with some patience it's possible to use jsdom and xhr2 to get epubjs working in Node itself (at least enough to where you can generate locations and extract the book's table of contents).
Hope these ramblings are somewhat helpful.
I've been battling with this for a bit so I'm still trying to find better ways to do this as quickly and accurately as possible. The best I've come up with:
Since we have access to:
book.locations.generate(1024)
)We can estimate the current and total pages:
TotalLocations / TotalPages = SectionLocations / SectionPages
Total Pages = (TotalLocations * SectionPages) / SectionLocations;
The implementation:
async function estimatePages() {
if (book.locations.total == 0) await book.locations.generate(1024);
let currentLocation = rendition.currentLocation();
let sectionIndex = currentLocation.start.index;
let sectionPages = currentLocation.start.displayed.total;
let sectionBaseCFI = book.spine.get(sectionIndex).cfiBase;
let sectionStartLocation = book.locations._locations.findIndex((item) =>
item.startsWith("epubcfi(" + sectionBaseCFI)
);
let sectionLocations = book.locations._locations.filter((item) =>
item.startsWith("epubcfi(" + sectionBaseCFI)
).length;
let totalLocations = book.locations.total;
let estPages = (totalLocations * sectionPages) / sectionLocations;
let estSectionStartPage =
estPages * (sectionStartLocation / totalLocations);
let estCurrentPage =
estSectionStartPage + currentLocation.start.displayed.page;
return {
currentPage: Math.round(estCurrentPage),
totalPages: Math.round(estPages),
};
}
Benefits / Notes:
1024
in above example), the more accurate it should be.It's not perfect, but it's the best I could come up with.
@evanreichard This doesn't work, I'm testing on my book and on different chapters it shows completely different numbers for total and current pages.
@vedmant Yeah there's some wonkyness when changing between chapters. I ended up abandoning total page count and reverting to total percentage, and the current / total page counts for the current chapter only.
Any updates on this case?
Any updates on this case?
@chrisovato - Check out my method and see if it works for you: https://github.com/futurepress/epub.js/issues/744#issuecomment-492300092
Hi, I would like to show something like this (in my reader footer):
Page 5 - 323
. This is basically this:"Page " + currentPage + " - " + totalPages
But I didn't find a way to get
currentPage
andtotalPages
number.For
currentPage
I tried:But I get strange numbers like (in order): 0, 1, 2, 4, 6, 8, 11...
And I'm not even sure how to get
totalPages
number.Can anyone help? I would like to find solution for both cases and add them to epub documentation.
EDIT: I use v0.3, I found that v0.2 has generatePagination method but I want to use v0.3