FB2圢匏の電子曞籍のサポヌトを実装するSDK





サむ゚ンスフィクションの「ノヌベル」は 、䞭囜の䜜家Liu Cixin劉慈欣が䜜品The Three-Body Problem 䞉體で受け取ったこずを知っおいたす。 バラク・オバマ 蚌明 ずマヌク・ザッカヌバヌグ 蚌明 はこの本に泚意を払った。



画像

Olga Braathenは圌女自身のむニシアチブでこの本をロシア語に翻蚳したした ここではfb2をダりンロヌドできたす 。



2016幎の「ノヌベル賞」のもう1぀の候補者は、 Neven Stevenson 雪厩ずクリプトノミコンを曞いたで、 Sevenevesの䜜品 ここから英語でダりンロヌドできたす 。誰もロシア語に翻蚳しなかったのは残念です。



EDISONの開発者は、数幎前に曞いたElectronic Document Access Controlプログラムを䜜成したした。今日は、FB2圢匏の電子曞籍のサポヌトを実装するSDKに぀いお説明したす。




はじめに



図曞通分野での情報技術の䜿甚は、読者にフィクション、科孊および技術文献の豊富なセットぞのリモヌトアクセスを提䟛するむンタヌネットサヌビスの出珟をもたらしたした。 そのようなサヌビスは、叞曞職を新しいレベルに匕き䞊げたす。 図曞通は単䞀のネットワヌクに統合され、デゞタル化されたコンテンツの地理的に分散した巚倧なデヌタベヌスを圢成したす。むンタヌネットでの図曞通サヌビスの提䟛は、察象読者を拡倧し、远加収入を提䟛したす。 䞻芁なナヌザヌにもメリットがありたす。時間をかけお図曞通を蚪れたり、本を個人的に䜿甚したり、タむムリヌに配達したりする必芁がありたせん。 特定の地域では利甚できない珍しい文献ぞのアクセスが可胜です。 暩利者は、盞互に有益な条件でコンテンツを提䟛するこずにより、ロむダリティを受け取るこずができたす。



図曞通サヌビスでは、著䜜暩の遵守ずコピヌ保護に特に泚意が払われたす。 独自の圢匏はトランスポヌトレベルで䜿甚され、クラむアント偎の゜フトりェアは受信したコンテンツをディスクに保存しないでください。



コンテンツの倧郚分は、スキャナヌを䜿甚しお物理メディアを手動でデゞタル化し、テキストを認識しお怜玢できるようにするこずで生成されたすが、これが唯䞀の゜ヌスではありたせん。 電子曞籍を保存するために蚭蚈された倚くのデゞタル圢匏があり、これらの圢匏で既にデゞタル化された本は少なくありたせん。 したがっお、図曞通サヌビスではさたざたな電子圢匏のサポヌトが必芁です。 サヌビスの1぀でフィクションブック圢匏の電子曞籍のサポヌトを導入するためのSDK開発者ツヌルキットの開発に぀いおお話したす。



挑戊する



コンテンツ配信サヌビスは、リモヌトリポゞトリ内の文献ぞのペヌゞ単䜍のアクセスをナヌザヌに提䟛したす。 各ペヌゞぞのアクセスは固定され、課金されたす。 このサヌビスは党文怜玢を実装し、その結果は半透明の長方圢で匷調衚瀺されたす。 サヌバヌずクラむアント間のトラフィックは保護されおおり、独自のバむナリ圢匏です。



EDISONプログラマヌは、゜リュヌションのサヌバヌ郚分ずクラむアント郚分を構築するずきに共通のコヌドベヌスを䜿甚するだけでなく、FB2圢匏の電子曞籍のサポヌトの実装を簡玠化するすぐに䜿甚できる䞀連の機胜を最終開発者に提䟛するSDKを䜜成するタスクに盎面したした。



サヌビスの機胜に基づいお、SDK関数のセットの芁件が事前に決定されたした。

  1. 曞誌情報の取埗。
  2. 電子曞籍のペヌゞ数を取埗する。
  3. 関連ペヌゞぞのリンクを含む党文怜玢結果を取埗する。
  4. フルテキスト怜玢の結果を匷調衚瀺するために、四角圢の座暙を取埗したす。
  5. 任意のペヌゞコンテンツをバむナリ圢匏で受信し、ペヌゞをレンダリングしたす。


実装ず技術C ++ / Qt



解決策



FB2の電子曞籍は1ペヌゞのドキュメントです。 この圢匏は、ドキュメントの倖芳に関する情報を提䟛したせん。 たず、ドキュメントの内容を耇補せずに、FB2ドキュメントをペヌゞに分割する問題を解決する必芁がありたした。 その結果、元のドキュメントの解析、ドキュメントのレンダリングおよびペヌゞングの結果ずしお取埗された、元のFB2ドキュメントに関するメタデヌタを栌玍するむンデックスファむル圢匏が蚭蚈されたした。

むンデックスファむルには、XMLドキュメントのフラグメントの堎所がドキュメントの先頭からのオフセットの圢匏で、フラグメントの長さが文字数で、さらにXMLプレフィックスが含たれおいたす。



むンデックスファむルの構造には、3぀のセクションが含たれたす。





XMLドキュメントのフラグメントの堎所に関する情報を䜿甚するず、解析する必芁なく元のドキュメントから目的の情報を差し匕くこずができたす。XMLプレフィックスを䜿甚するず、目的のペヌゞのみのマヌクアップを含むミニチュアXMLドキュメントを䜜成し、解析しお、ナヌザヌの芁求に応じお目的のペヌゞをすぐにレンダリングできたす。



ドキュメントのペヌゞネヌションを含むむンデックスファむルの䟋。

<document> <description> <fragment> <offset>418</offset> <length>5230</length> <prefix><![CDATA[<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:xlink="http://www.w3.org/1999/xlink">]]></prefix> </fragment> </description> <binary id="cover.jpg" > <fragment> <offset>43034</offset> <length>48151</length> </fragment> </binary> <page number="1" > <fragment> <offset>5657</offset> <length>1779</length> <prefix><![CDATA[<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:xlink="http://www.w3.org/1999/xlink"><body>]]></prefix> </fragment> </page> <page number="2" > <fragment> <offset>7436</offset> <length>2366</length> <prefix><![CDATA[<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:xlink="http://www.w3.org/1999/xlink"><body><section><section><p>]]></prefix> </fragment> </page> </document>
      
      







ドキュメントをペヌゞに分割するアルゎリズムのアむデアがあったずき、私たちはそれを実装し始めたした。 むンデックスを䜜成するために、Qtラむブラリの暙準クラスを䜿甚しお元のドキュメントのストリヌミング解析の方法を遞択したした。これは、QXmlStreamReader :: characterOffsetメ゜ッドを䜿甚しおXMLファむルを連続しお読み取り、ファむル内のオフセットに関する情報を文字数で栌玍できるためです。



FB2ドキュメントを解析するプロセスでは、タグからタグぞ移動するずきに、ドキュメントの段萜が単語のセットに解析され、それが再び行に組み立おられたす。 蚭定ファむルに埓っお、指定されたペヌゞ䜙癜の幅ず段萜のむンデントを考慮しお、各行が最倧幅に蚭定されたす。 行の堎合、蚭定ファむルで指定された行間隔も指定されたす。 XMLドキュメントのタグに応じお、フォントパラメヌタヌ、サむズ、スタむル、および配眮が蚭定されたす。 芋出しず小芋出しの堎合は䞭倮揃えが蚭定され、゚ピグラフの堎合は右揃えが蚭定され、デフォルトでは巊揃えが蚭定されたす。 文字列に単語を远加するず、远加されたすべおの単語の長さを合蚈するこずにより、文字列の長さが再蚈算されたす。 行の長さが指定されたペヌゞ幅を超える堎合、行はペヌゞオブゞェクトに远加されたす。 行に収たらない単語は次の行に远加されたす。 ペヌゞに行を远加するず、行間隔を考慮しおすべおの行の高さが再蚈算されたす。 画像を埋め蟌むずき、ラむンの高さは、ラむンに远加されるオブゞェクトの最倧の高さず芋なされる必芁がありたした。 むンデントを考慮しお、远加されたすべおの行の高さが指定されたペヌゞの高さを超える堎合、次のフラグメントがむンデックスファむルに远加されたす。 説明されおいるアルゎリズムは、FB2ドキュメントをペヌゞに解析するずき、およびむンデックスファむルを䜿甚しおペヌゞにランダムにアクセスするずきに䜿甚されたす。



QXmlStreamReader :: characterOffsetメ゜ッドは、ドキュメントのペヌゞぞのランダムアクセスで、バむト数ではなく文字数でオフセットを返すため、元のファむルの先頭を読み取り、ドキュメントの興味深い郚分だけを差し匕く必芁がありたす。 seekメ゜ッドを䜿甚したバむト単䜍のファむルオフセットは、必然的に゚ラヌに぀ながりたす。

 QString Document::documentFragment(uint offset, uint length) { QString fragment; QFile file(m_fileName); if (!file.open(QIODevice::ReadOnly)) { m_error = IOError; return fragment; } QTextStream fileStream(&file); fileStream.setCodec("UTF-8"); fileStream.setAutoDetectUnicode(true); fileStream.seek(0); fileStream.read(offset); fragment = fileStream.read(length); file.close(); if ((uint) fragment.size() < length) { m_error = IOError; fragment = QString(); return fragment; } return fragment; }
      
      







これにもかかわらず、パフォヌマンスの䜎䞋はありたせん;ドキュメントの最埌のペヌゞぞのアクセスは、最初のペヌゞぞのアクセスず同じくらい速く、1秒もかかりたせん。 実際には、FB2圢匏の写真のない本の平均ボリュヌムが10 MBを超えるこずはめったにありたせん。



7 MBファむルを998ペヌゞに分割し、むンデックスを準備するには、玄10秒かかりたす。 9 MBファむルを1576ペヌゞに分割するには、玄15秒かかりたす。 平均しお、1秒間に玄100ペヌゞがレンダリングされたす。 むンデックスがある堎合、ドキュメントは50ミリ秒で開きたす。



次に、ドキュメントのペヌゞを参照しお党文怜玢の問題を解決する必芁がありたした。 そしお、ここでは、速床を確保するために、ドキュメントのコンテンツを耇補する必芁がありたしたが、XMLマヌクアップはなく、通垞のテキストファむルの圢匏でした。 ペヌゞの開始マヌカヌず終了マヌカヌは、れロバむトずしおテキストむンデックスに挿入されたす。 怜玢結果をペヌゞにバむンドし、長方圢の座暙を保存するには、2぀の補助むンデックスをバむナリ圢匏で敎理する必芁がありたした。 怜玢結果をペヌゞにリンクするための補助むンデックスには、ペヌゞ番号、テキストむンデックスのペヌゞマヌカヌの開始バむトず終了バむトのシリアル番号が栌玍されたす。



党文怜玢は、顧客が提䟛するラむブラリを䜿甚しお実行され、特定の単語のすべおの単語圢匏が返されたす。 怜玢ク゚リは単語のセットに分割され、単語ごずにすべおの単語圢匏が怜玢され、怜玢された単語圢匏の生成された配列のテキストむンデックスで怜玢が実行されたす。 テキストむンデックスの補助むンデックスずペヌゞ開始/終了マヌカヌを䜿甚しお、怜玢結果が属するペヌゞ番号が決定されたす。 長方圢の座暙を持぀補助むンデックスは、ペヌゞが芁求されたずきにのみ圢成されたす。 各ペヌゞに個別のむンデックスファむルが生成されたす。 四角圢の座暙を取埗するプロセスでは、行を単語に分割し、各単語の境界を蚈算するため、元のドキュメントをペヌゞに分割するための同じアルゎリズムが䜿甚されたす。むンデックスは、同じペヌゞに切り替えるずきにこのアルゎリズムが再床呌び出されるのを防ぐのに圹立ちたす。



党文怜玢甚のむンデックスの䜜成には、玄10 MBの容量のドキュメントで玄1分かかりたす。 むンデックスがある堎合、怜玢は1,576ペヌゞのドキュメントで玄1秒間機胜したす。



もう1぀の驚きは、芋぀かったテキストの断片の䞊に半透明の長方圢が衚瀺されたこずです。 単語の境界を蚈算するための数孊はもずもずピクセル単䜍であったため、ドキュメントのペヌゞを拡倧瞮小するずきにいく぀かのピクセルの䞍正確さが生じおいたした。 解決策が芋぀かりたした。敎数の代わりに浮動小数点倀を䜿甚し、コヌドの倧郚分を修正しお、DPI出力デバむスを考慮しお、すべおの蚈算をむンチに倉換する必芁がありたした。

  m_dpiX = (qreal) QApplication::desktop()->physicalDpiX(); m_dpiY = (qreal) QApplication::desktop()->physicalDpiY(); QFontMetricsF fm(m_font); m_rect = fm.boundingRect(m_text); m_textDescent = fm.descent() / m_dpiY; qreal width = m_rect.width() / m_dpiX; qreal height = m_rect.height() / m_dpiY; m_rect.setSize(QSizeF(width, height));
      
      





フィニッシュラむンでは、䞀連の長方圢を含むペヌゞビュヌをバむナリ圢匏にシリアル化し、そこから読み戻しおペヌゞのコンテンツをクラむアントに転送し、同じSDKを䜿甚しおレンダリングする問題を解決するために残りたした。 ここではすべおが非垞にシンプルであるこずが刀明したした。暙準のQTラむブラリクラスであるQDataStreamが助けになりたした。



問題を解決する過皋で、次のクラスが特定されたした。









すべおのSDKクラスのメ゜ッドは単䜓テストでカバヌされ、FB2ドキュメントが正しくペヌゞ付けされおいるこず、およびクラむアントプログラムのナヌザヌがペヌゞを芁求するずきにたったく同じ画像が衚瀺されるこずを確認したす。ペヌゞはむンデックスファむルを準備するずきにサヌバヌ偎で最初にレンダリングされたす。



その結果、最終目暙が達成されたした。 箱入り゜リュヌションよりもSDKを開発する利点は柔軟性です。 最も難しい郚分は単玔な関数の呌び出しの背埌に隠されおおり、SDKを䜿甚する開発者は、その䜿甚方法を自分で決定できたす。たずえば、システム関数の速床ずより快適なナヌザヌ゚クスペリ゚ンスを確保するために事前にむンデックスを構築するか、ドキュメントぞの最初のアクセスず最初の怜玢でむンデックスを構築するかなどですディスク領域を節玄するためにたれに䜿甚しおそれらを芁求しお削陀したす。



SDKのパフォヌマンスをお客様に瀺すために、2぀のデスクトップアプリケヌションがそのベヌスで実装されたした。 FictionBookReaderは、FB2ドキュメントの基本的なリヌダヌの機胜に、怜玢結果の匷調衚瀺によるペヌゞ分割および党文怜玢機胜を提䟛したす。







FB2SDKデモは、SDKのサヌバヌおよびクラむアント郚分の機胜を瀺したす。 サヌバヌパヌツの機胜は[サヌバヌ]タブで匷調衚瀺されたす。このタブでは、ドキュメントの解析ずマルチペヌゞむンデックスの䜜成、および四角圢ずフルテキストむンデックスを䜿甚したファむルの䜜成を瀺したす。 クラむアントパヌツの機胜は、生成されたバむナリファむルに埓っおドキュメントペヌゞのレンダリングを瀺す[クラむアント]タブで匷調衚瀺されたす。















その他のプロゞェクト

5233人時でマむクロトモグラフ甚の゜フトりェアを䜜成する方法

FB2圢匏の電子曞籍のサポヌトを実装するSDK

電子文曞ぞのアクセスを管理したす。 DefViewからVivaldiぞ

Axxon NextずSureViewの2぀のビデオ監芖システムを統合したす

X線トモグラフィヌ゜フトりェアの開発の詳现

「スコヌプ」数十億キロワット時を監芖する方法

デヌタベヌスを操䜜するためのシンプルなJIRAプラグむンの開発

DevOpsを支揎する1008時間でDebian䞊のネットワヌクデバむスのファヌムりェアビルダヌ

貧しい人々のためのAWSを介したWindows Auto Service Update



All Articles