// TODO: Could pass chapter and pageIndex here, to obtain pageInfo within, and then can set nextPageInfo PageInfo Paginate(ChapterInfo chapter, PageInfo pageInfo) { // Get dimensions of space character Size spaceSize = fontMetrics.MeasureText(" "); int lineHeight = (int)Math.Ceiling(fontSize * spaceSize.Height); int spaceWidth = (int)Math.Ceiling(fontSize * spaceSize.Width); // Initialize a couple variables int accumHeight = 0; int characterCount = pageInfo.AccumulatedCharacterCount; PageInfo nextPageInfo = null; int paragraphIndex = pageInfo.ParagraphIndex; int characterIndex = pageInfo.CharacterIndex; // Loop for lines on page while (true) { ParagraphInfo paragraph = paragraphs[paragraphIndex]; // For blank paragraphs, leave a gap... if (paragraph.Text.Length == 0) { // .. but not when it's at the top of the page if (accumHeight > 0) { accumHeight += (int)Math.Ceiling(ParagraphSpacing * lineHeight); } } // Normal case for non-blank paragraphs else { // This is the amount to indent the entire paragraph int indent = spaceWidth * paragraph.Indent; // Apply first line indent if paragraph indent is zero, and it's // not the first paragraph in the chapter if (indent == 0 && characterIndex == 0 && paragraph != paragraphs[chapter.FirstParagraph]) { indent = spaceWidth * FirstLineIndent; } // Start off accumulated line width with the indent int accumWidth = indent; // Loop for words within line -- always the same paragraph while (true) { // Find next space in paragraph int spaceIndex = paragraph.Text.IndexOf(' ', characterIndex); int wordCharacters = (spaceIndex == -1 ? paragraph.Text.Length : spaceIndex) - characterIndex; int wordWidth = (int)Math.Ceiling(fontSize * fontMetrics.MeasureText(paragraph.Text, characterIndex, wordCharacters).Width); // Check if the accumulated width exceeds the page width, // but make sure to have at least one word. if (accumWidth > indent && accumWidth + wordWidth >= pageSize.Width) { break; } WordInfo word = new WordInfo { LocationLeft = accumWidth, LocationTop = accumHeight, ParagraphIndex = paragraphIndex, CharacterIndex = characterIndex, CharacterCount = wordCharacters, }; pageInfo.Words.Add(word); accumWidth += wordWidth; characterCount += wordCharacters + (spaceIndex == -1 ? 0 : 1); characterIndex += wordCharacters + (spaceIndex == -1 ? 0 : 1); // End of line because it's the end of the paragraph if (spaceIndex == -1) { characterIndex = 0; break; } // End of line because no more words will fit if (accumWidth + spaceWidth >= pageSize.Width) { break; } accumWidth += spaceWidth; // Otherwise, point to next word characterIndex = spaceIndex + 1; // ready for next word } // Bump up the accumulated height of the page accumHeight += lineHeight; } // Start a new line, but check first if it's a new paragraph if (characterIndex == 0) { // If we've been working with the last paragraph in the chapter, // we're also done with the page if (paragraphIndex + 1 == chapter.FirstParagraph + chapter.ParagraphCount) { pageInfo.IsLastPageInChapter = true; break; } // Otherwise, kick up the paragraphIndex paragraphIndex++; } // Check if the next paragraph is too much for this page if ((paragraphs[paragraphIndex].Text.Length == 0 && accumHeight + lineHeight / 2 > pageSize.Height) || accumHeight + lineHeight > pageSize.Height) { break; } } pageInfo.IsPaginated = true; // Create PageInfo for next page if (!pageInfo.IsLastPageInChapter) { nextPageInfo = new PageInfo { ParagraphIndex = paragraphIndex, CharacterIndex = characterIndex, AccumulatedCharacterCount = characterCount }; } return(nextPageInfo); }
private void GenerateParagraphs(StreamReader stream) { string line = null; string prevLine = null; int prevIndent = 0; var paragraphBuilder = new StringBuilder(); while (null != (line = stream.ReadLine())) { // Trim line of all space and find the line indent line = line.TrimEnd(' '); int indent = line.Length; line = line.TrimStart(' '); indent -= line.Length; // A new paragraph is always implied with a line of zero length bool newParagraph = line.Length == 0; if (!newParagraph && paragraphBuilder.Length > 0 && prevLine != null) { // This is the case for a list ("contents" for example) // where each line has a different indent if (indent != prevIndent) { newParagraph = true; } // But some indented text needs to be concatenated (epistoles, for example) else if (indent != 0) { string firstWord = line; int spaceIndex = line.IndexOf(' '); if (spaceIndex != -1) firstWord = firstWord.Substring(0, spaceIndex); // This works for some books, but not for "Phineas Finn" where // at least the first letter has shorter lines than normal // if (indent + prevLine.Length + 1 + firstWord.Length <= 70) // newParagraph = true; } } // Check for a possible paragraph termination if (newParagraph) { if (paragraphBuilder.Length > 0) { SubstituteCharacters(paragraphBuilder); // Create a new ParagraphInfo for the paragraph ParagraphInfo paragraph = new ParagraphInfo { Indent = prevIndent, Text = paragraphBuilder.ToString() }; paragraphs.Add(paragraph); // Clear the StringBuilder paragraphBuilder.Remove(0, paragraphBuilder.Length); } if (line.Length > 0) { // Append the line to the paragraph paragraphBuilder.Append(line); } else { // Add the current line that terminates the paragraph ParagraphInfo emptyParagraph = new ParagraphInfo { Indent = 0, Text = line }; paragraphs.Add(emptyParagraph); } } else { // Insert a space between appended lines assembled into paragraph if (paragraphBuilder.Length > 0) paragraphBuilder.Append(" "); paragraphBuilder.Append(line); } prevLine = line; prevIndent = indent; } // Add the last paragraph if there's one in progress if (paragraphBuilder.Length > 0) { SubstituteCharacters(paragraphBuilder); ParagraphInfo paragraph = new ParagraphInfo { Indent = prevIndent, Text = paragraphBuilder.ToString() }; paragraphs.Add(paragraph); } }
private void GenerateParagraphs(StreamReader stream) { string line = null; string prevLine = null; int prevIndent = 0; var paragraphBuilder = new StringBuilder(); while (null != (line = stream.ReadLine())) { // Trim line of all space and find the line indent line = line.TrimEnd(' '); int indent = line.Length; line = line.TrimStart(' '); indent -= line.Length; // A new paragraph is always implied with a line of zero length bool newParagraph = line.Length == 0; if (!newParagraph && paragraphBuilder.Length > 0 && prevLine != null) { // This is the case for a list ("contents" for example) // where each line has a different indent if (indent != prevIndent) { newParagraph = true; } // But some indented text needs to be concatenated (epistoles, for example) else if (indent != 0) { string firstWord = line; int spaceIndex = line.IndexOf(' '); if (spaceIndex != -1) { firstWord = firstWord.Substring(0, spaceIndex); } // This works for some books, but not for "Phineas Finn" where // at least the first letter has shorter lines than normal // if (indent + prevLine.Length + 1 + firstWord.Length <= 70) // newParagraph = true; } } // Check for a possible paragraph termination if (newParagraph) { if (paragraphBuilder.Length > 0) { SubstituteCharacters(paragraphBuilder); // Create a new ParagraphInfo for the paragraph ParagraphInfo paragraph = new ParagraphInfo { Indent = prevIndent, Text = paragraphBuilder.ToString() }; paragraphs.Add(paragraph); // Clear the StringBuilder paragraphBuilder.Remove(0, paragraphBuilder.Length); } if (line.Length > 0) { // Append the line to the paragraph paragraphBuilder.Append(line); } else { // Add the current line that terminates the paragraph ParagraphInfo emptyParagraph = new ParagraphInfo { Indent = 0, Text = line }; paragraphs.Add(emptyParagraph); } } else { // Insert a space between appended lines assembled into paragraph if (paragraphBuilder.Length > 0) { paragraphBuilder.Append(" "); } paragraphBuilder.Append(line); } prevLine = line; prevIndent = indent; } // Add the last paragraph if there's one in progress if (paragraphBuilder.Length > 0) { SubstituteCharacters(paragraphBuilder); ParagraphInfo paragraph = new ParagraphInfo { Indent = prevIndent, Text = paragraphBuilder.ToString() }; paragraphs.Add(paragraph); } }