<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ OCR  - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ OCR  - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 18 Jul 2026 13:53:24 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/ocr/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Browser-Based PDF OCR to Text Converter Using JavaScript ]]>
                </title>
                <description>
                    <![CDATA[ Not every PDF contains searchable or editable text. Many PDFs are simply scanned images of documents such as invoices, contracts, books, receipts, government forms, and handwritten notes. While these  ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-pdf-ocr-to-text-converter-javascript/</link>
                <guid isPermaLink="false">6a4d27fa9720ba8235700935</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ pdf ]]>
                    </category>
                
                    <category>
                        <![CDATA[ OCR  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ pdf to text ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Bhavin Sheth ]]>
                </dc:creator>
                <pubDate>Tue, 07 Jul 2026 16:23:22 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/ba3a97e6-1829-4062-acef-9d05eaa14c34.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Not every PDF contains searchable or editable text. Many PDFs are simply scanned images of documents such as invoices, contracts, books, receipts, government forms, and handwritten notes.</p>
<p>While these documents are easy to read, copying, searching, or editing their content isn't possible without additional processing.</p>
<p>This is where <strong>Optical Character Recognition (OCR)</strong> comes in. OCR recognizes text inside scanned images and converts it into editable, searchable digital text.</p>
<p>In this tutorial, you'll build a browser-based <strong>PDF OCR to Text Converter</strong> using JavaScript. Users will be able to upload PDF files, preview pages, configure OCR settings, extract text, monitor processing progress, review OCR confidence scores, and export the results – all directly inside the browser.</p>
<p>Since everything runs locally, uploaded documents never leave the user's device, making the tool both fast and privacy-friendly.</p>
<p>By the end of this tutorial, you'll understand how browser-based OCR works and how to build your own PDF-to-text converter using JavaScript.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a href="#heading-why-pdf-ocr-is-useful">Why PDF OCR Is Useful</a></p>
</li>
<li><p><a href="#heading-how-pdf-ocr-works">How PDF OCR Works</a></p>
</li>
<li><p><a href="#heading-project-setup">Project Setup</a></p>
</li>
<li><p><a href="#heading-what-libraries-are-we-using">What Libraries Are We Using?</a></p>
</li>
<li><p><a href="#heading-creating-the-upload-interface">Creating the Upload Interface</a></p>
</li>
<li><p><a href="#heading-previewing-uploaded-pdf-pages">Previewing Uploaded PDF Pages</a></p>
</li>
<li><p><a href="#heading-configuring-ocr-settings">Configuring OCR Settings</a></p>
</li>
<li><p><a href="#heading-extracting-text-from-the-pdf">Extracting Text from the PDF</a></p>
</li>
<li><p><a href="#heading-tracking-ocr-progress">Tracking OCR Progress</a></p>
</li>
<li><p><a href="#heading-understanding-ocr-confidence-scores">Understanding OCR Confidence Scores</a></p>
</li>
<li><p><a href="#heading-reviewing-the-extracted-text">Reviewing the Extracted Text</a></p>
</li>
<li><p><a href="#heading-exporting-the-ocr-results">Exporting the OCR Results</a></p>
</li>
<li><p><a href="#heading-demo-how-the-pdf-ocr-tool-works">Demo: How the PDF OCR Tool Works</a></p>
</li>
<li><p><a href="#heading-performance-optimization-tips">Performance Optimization Tips</a></p>
</li>
<li><p><a href="#heading-important-notes-from-real-world-use">Important Notes from Real-World Use</a></p>
</li>
<li><p><a href="#heading-common-mistakes-to-avoid">Common Mistakes to Avoid</a></p>
</li>
<li><p><a href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-why-pdf-ocr-is-useful">Why PDF OCR Is Useful</h2>
<p>Many PDF files are scanned documents rather than digital text. Although they look readable, the text is actually stored as images, making it impossible to search, copy, edit, or analyze the content.</p>
<p>OCR (Optical Character Recognition) solves this problem by recognizing characters from scanned pages and converting them into editable, searchable text. Once the text is extracted, it can be copied, translated, indexed, summarized, or imported into other applications.</p>
<p>OCR is widely used across many industries. Businesses use it to process invoices, purchase orders, receipts, contracts, bank statements, and tax documents without manually entering data. Legal professionals use OCR to search agreements, affidavits, and court documents for names, dates, or specific clauses. Government agencies digitize historical records, application forms, passports, and official documents to build searchable digital archives.</p>
<p>Educational institutions convert scanned books, research papers, lecture notes, and examination materials into searchable text, making learning resources easier to access. Healthcare organizations use OCR to digitize prescriptions, laboratory reports, insurance claims, and patient records, reducing paperwork and improving record management.</p>
<p>OCR is also valuable for e-commerce businesses. Sellers handling hundreds of invoices, shipping labels, and purchase orders from platforms such as Amazon, Flipkart, Meesho, or Shopify can quickly extract order numbers, customer details, addresses, and product information instead of typing everything manually.</p>
<p>Developers use OCR when building document management systems, enterprise search tools, AI assistants, and workflow automation platforms where scanned documents need to become searchable digital content.</p>
<p>Since this application performs OCR entirely inside the browser, users can process confidential documents without uploading them to external servers. This keeps document processing fast, private, and secure while making scanned PDFs much more useful.</p>
<h2 id="heading-how-pdf-ocr-works">How PDF OCR Works</h2>
<p>A PDF OCR application converts scanned pages into editable text by combining PDF rendering with Optical Character Recognition.</p>
<p>When a user uploads a PDF, the browser first validates the document and loads it into memory. Each page is then rendered as an image using PDF.js. These rendered page images become the input for the OCR engine.</p>
<p>The OCR engine examines every image pixel by pixel. It identifies printed characters, recognizes words and sentences, and reconstructs the document as digital text. Depending on the selected language, the recognition engine applies language-specific dictionaries and character models to improve accuracy.</p>
<p>If the user enables image enhancement, the application can improve the scanned page before recognition. Converting the page to grayscale, increasing contrast, or sharpening the image often helps OCR detect characters more accurately, especially when working with old scans or low-quality photocopies.</p>
<p>As each page is processed, the application updates a progress indicator so users can monitor the extraction process in real time. The OCR engine also returns a confidence score for every page, allowing users to estimate how reliable the recognized text is.</p>
<p>After all selected pages have been processed, the application combines the extracted text into a single document. Users can review the output, copy it directly from the browser, or export it as a TXT or JSON file for further use.</p>
<p>Since every stage of the workflow runs locally, the uploaded PDF never leaves the user's device. This makes browser-based OCR an excellent solution for sensitive business documents, legal records, healthcare files, financial reports, and government paperwork.</p>
<h2 id="heading-project-setup">Project Setup</h2>
<p>We'll build the PDF OCR application using standard web technologies.</p>
<p>Create the following project structure.</p>
<pre><code class="language-text">pdf-ocr-tool/

│── index.html

│── style.css

│── script.js
</code></pre>
<p>Next, include the required JavaScript libraries inside <strong>index.html</strong>.</p>
<pre><code class="language-html">&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/4.4.168/pdf.min.js"&gt;&lt;/script&gt;

&lt;script src="https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js"&gt;&lt;/script&gt;

&lt;script src="https://unpkg.com/pdf-lib"&gt;&lt;/script&gt;
</code></pre>
<p>These libraries provide everything needed to render PDF pages, recognize text, and manage PDF-related operations directly inside the browser.</p>
<h2 id="heading-what-libraries-are-we-using">What Libraries Are We Using?</h2>
<p>This project combines several JavaScript libraries because OCR involves multiple processing stages.</p>
<p>The primary library is <strong>PDF.js</strong>, which loads the uploaded PDF document and renders every page as an image inside the browser. Since OCR engines work with images rather than PDF files directly, rendering each page is the first step of the workflow.</p>
<p>The application uses <strong>Tesseract.js</strong> to perform Optical Character Recognition. Tesseract is one of the most popular open-source OCR engines and supports dozens of languages, making it possible to recognize printed text from scanned documents without relying on any external API or cloud service.</p>
<p>We also include <strong>PDF-lib</strong>, which helps manage PDF-related operations and provides additional flexibility if future features such as annotations, metadata editing, or document modifications are added.</p>
<p>Together, these libraries create a complete browser-based OCR solution capable of rendering PDF pages, recognizing printed text, tracking recognition progress, reporting confidence scores, and exporting the extracted text while keeping every document private on the user's device.</p>
<h2 id="heading-creating-the-upload-interface">Creating the Upload Interface</h2>
<p>Every OCR workflow begins with selecting a PDF document. Before the application can recognize any text, it must first load the PDF into the browser and verify that it's a supported file type.</p>
<p>A good upload interface should be simple, intuitive, and accessible for both desktop and mobile users. Supporting drag-and-drop uploads alongside the traditional file picker gives users multiple ways to import their documents.</p>
<p>In this project, the upload section serves as the starting point for the entire OCR workflow. After a PDF is selected, the browser validates the file, reads it into memory, and prepares it for page rendering. Since the application runs completely inside the browser, no document is uploaded to an external server. This ensures confidential PDFs remain private throughout the OCR process.</p>
<p>The upload interface also provides clear instructions so users immediately understand how to begin using the tool.</p>
<p>Here's the HTML for the upload area:</p>
<pre><code class="language-html">&lt;div class="upload-container"&gt;

    &lt;div id="dropZone" class="drop-zone"&gt;

        &lt;div class="upload-icon"&gt;
            ☁
        &lt;/div&gt;

        &lt;h2&gt;Drag &amp; Drop PDF Here&lt;/h2&gt;

        &lt;p&gt;Or click to browse file&lt;/p&gt;

        &lt;button id="selectPDF"&gt;

            Select PDF

        &lt;/button&gt;

        &lt;input

            type="file"

            id="pdfInput"

            accept="application/pdf"

            hidden&gt;

    &lt;/div&gt;

&lt;/div&gt;
</code></pre>
<p>Next, validate the uploaded file before loading it.</p>
<pre><code class="language-javascript">const pdfInput = document.getElementById("pdfInput");

pdfInput.addEventListener("change", async (event)=&gt;{

    const file = event.target.files[0];

    if(!file) return;

    if(file.type !== "application/pdf"){

        alert("Please upload a valid PDF file.");

        return;

    }

    loadPDF(file);

});
</code></pre>
<p>Once the validation succeeds, the PDF is loaded into memory and the application proceeds to generate preview thumbnails for each page.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/c47b97f2-6e5f-421d-90c6-0dd34e3440ed.png" alt="PDF upload interface allowing users to drag and drop or browse for a PDF document before OCR processing." style="display:block;margin:0 auto" width="570" height="636" loading="lazy">

<h2 id="heading-previewing-uploaded-pdf-pages">Previewing Uploaded PDF Pages</h2>
<p>After the PDF has been loaded successfully, the application generates page previews.</p>
<p>Instead of immediately starting OCR, users first see thumbnail images for every page in the uploaded document. This allows them to confirm that the correct file has been selected and inspect the document before extraction begins.</p>
<p>The preview stage is especially useful for large PDFs because users can quickly identify scanned pages, blank pages, rotated pages, or incorrect uploads without wasting time running OCR on the wrong document.</p>
<p>PDF.js renders every page as a canvas before displaying it inside the preview grid.</p>
<p>First, load the PDF document.</p>
<pre><code class="language-javascript">const pdf = await pdfjsLib.getDocument({

    data: await file.arrayBuffer()

}).promise;
</code></pre>
<p>Next, render every page.</p>
<pre><code class="language-javascript">for(let pageNumber = 1; pageNumber &lt;= pdf.numPages; pageNumber++){

    const page = await pdf.getPage(pageNumber);

    const viewport = page.getViewport({

        scale:0.35

    });

    const canvas = document.createElement("canvas");

    const context = canvas.getContext("2d");

    canvas.width = viewport.width;

    canvas.height = viewport.height;

    await page.render({

        canvasContext:context,

        viewport

    }).promise;

    previewContainer.appendChild(canvas);

}
</code></pre>
<p>Each rendered page becomes a thumbnail, allowing users to scroll through the document before choosing the OCR settings.</p>
<p>This visual confirmation greatly reduces mistakes when processing long reports, contracts, invoices, books, or multi-page scanned documents.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/84da8fa8-372f-47b9-ad16-fef208211722.png" alt="Uploaded PDF preview displaying thumbnail images of every page before OCR processing begins." style="display:block;margin:0 auto" width="564" height="505" loading="lazy">

<h2 id="heading-configuring-ocr-settings">Configuring OCR Settings</h2>
<p>Different PDF documents require different OCR configurations. A clean digital scan usually processes very quickly, while old photocopies or low-quality scans often require additional image enhancement to improve recognition accuracy.</p>
<p>Before starting OCR, the application allows users to customize several options that affect how text is extracted.</p>
<p>Users can choose whether OCR should process every page or only a specific page range. This is particularly useful when working with large documents where only a few pages contain important information.</p>
<p>The OCR engine also supports multiple recognition languages. Selecting the correct language helps improve accuracy because Tesseract uses language-specific dictionaries and character models during recognition.</p>
<p>For users who prioritize speed, the Fast mode completes OCR quickly while still producing good results. When working with low-quality scans or official documents, High Accuracy mode performs additional processing to improve recognition quality.</p>
<p>The application also includes optional image enhancement settings. Converting pages to grayscale, increasing contrast, or sharpening the scanned image often improves OCR accuracy by making printed characters easier to recognize.</p>
<p>These configurable options allow the OCR engine to adapt to many different document types without overwhelming users with unnecessary complexity.</p>
<p>The page selection section allows users to process either the entire document or only selected pages.</p>
<pre><code class="language-html">&lt;input

type="radio"

name="pages"

value="all"

checked&gt;

All Pages

&lt;input

type="radio"

name="pages"

value="custom"&gt;

Specific Pages
</code></pre>
<p>Users can also choose the OCR language.</p>
<pre><code class="language-html">&lt;select id="language"&gt;

    &lt;option&gt;English&lt;/option&gt;

    &lt;option&gt;Hindi&lt;/option&gt;

    &lt;option&gt;Gujarati&lt;/option&gt;

    &lt;option&gt;Spanish&lt;/option&gt;

    &lt;option&gt;French&lt;/option&gt;

    &lt;option&gt;German&lt;/option&gt;

    &lt;option&gt;Chinese (Simplified)&lt;/option&gt;

&lt;/select&gt;
</code></pre>
<p>Next, configure the OCR accuracy mode.</p>
<pre><code class="language-javascript">const mode = document.querySelector(

'input[name="accuracy"]:checked'

).value;

console.log(mode);
</code></pre>
<p>Finally, enable optional image enhancement features before OCR begins.</p>
<pre><code class="language-javascript">const grayscale = grayscaleCheckbox.checked;

const contrast = contrastCheckbox.checked;

const sharpen = sharpenCheckbox.checked;

console.log(

grayscale,

contrast,

sharpen

);
</code></pre>
<p>These settings allow the application to balance processing speed and recognition quality depending on the type of PDF being analyzed.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/9e4287b5-bb0c-4ac3-a042-5e99ec37be07.png" alt="OCR settings showing page selection, language selection, accuracy mode, and image enhancement options." style="display:block;margin:0 auto" width="565" height="563" loading="lazy">

<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/0335cedb-8dcd-4b8a-b26a-58e71b7f056f.png" alt="Language selection dropdown displaying supported OCR languages including English, Hindi, Gujarati, Spanish, French, German, and Chinese." style="display:block;margin:0 auto" width="526" height="292" loading="lazy">

<h3 id="heading-improving-ocr-accuracy-before-processing">Improving OCR Accuracy Before Processing</h3>
<p>One advantage of browser-based OCR is that the document can be optimized before recognition begins. Small image enhancements often have a significant impact on the quality of the extracted text.</p>
<p>For example, grayscale conversion removes unnecessary color information, allowing the OCR engine to focus only on character shapes. Increasing contrast helps distinguish text from the page background, while sharpening makes blurred letters easier to recognize.</p>
<p>These enhancements are especially valuable when processing old books, photocopies, historical records, receipts, handwritten forms, government documents, engineering drawings, and low-resolution scans.</p>
<p>Choosing the correct OCR language is equally important. A scanned Gujarati document processed using the English language model will usually produce poor recognition results. Selecting the matching language significantly improves OCR accuracy.</p>
<p>Taking a few moments to configure these settings before processing often produces cleaner extracted text, fewer recognition errors, and higher confidence scores, particularly when working with challenging documents.</p>
<h2 id="heading-extracting-text-from-the-pdf">Extracting Text from the PDF</h2>
<p>Once the document has been uploaded, previewed, and the OCR settings have been configured, the application is ready to extract text from the selected pages.</p>
<p>Unlike searchable PDFs that already contain digital text, scanned PDF documents consist entirely of images. OCR works by examining each rendered page image, recognizing every visible character, and converting those characters into editable text.</p>
<p>The extraction process begins by rendering each selected PDF page as an image using PDF.js. Each rendered page is then passed to Tesseract.js, which analyzes the image pixel by pixel and reconstructs words, sentences, paragraphs, and punctuation.</p>
<p>If the user selected a specific page range, only those pages are processed. Otherwise, every page in the document is analyzed.</p>
<p>Because OCR can be computationally intensive, especially for high-resolution scans, the application processes one page at a time. This approach keeps memory usage lower while providing continuous progress updates to the user.</p>
<p>The recognized text from each page is appended to a single output document that can later be reviewed, copied, or exported.</p>
<p>First, create the OCR worker.</p>
<pre><code class="language-javascript">const worker = await Tesseract.createWorker(

    selectedLanguage

);
</code></pre>
<p>Next, loop through the selected pages.</p>
<pre><code class="language-javascript">for(let page = startPage; page &lt;= endPage; page++){

    await processPage(page);

}
</code></pre>
<p>Now perform OCR on the rendered page.</p>
<pre><code class="language-javascript">const result = await worker.recognize(

    canvas

);

const extractedText = result.data.text;
</code></pre>
<p>Append the extracted text to the final output.</p>
<pre><code class="language-javascript">finalText +=

`----- Page ${page} -----\n\n`;

finalText += extractedText;

finalText += "\n\n";
</code></pre>
<p>Once every page has been processed, terminate the OCR worker.</p>
<pre><code class="language-javascript">await worker.terminate();
</code></pre>
<p>Processing one page at a time allows users to monitor OCR progress while ensuring stable performance, even for large documents.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/f0d63a41-e872-40c3-9dd1-6bec86a8a545.png" alt="Extract Text button used to begin OCR processing for the uploaded PDF." style="display:block;margin:0 auto" width="575" height="171" loading="lazy">

<h2 id="heading-tracking-ocr-progress">Tracking OCR Progress</h2>
<p>OCR processing can take anywhere from a few seconds to several minutes depending on the size of the document, image quality, language, and selected accuracy mode.</p>
<p>Providing a progress indicator is important because users can immediately see that the application is actively processing the document instead of appearing frozen.</p>
<p>As each page finishes recognition, the progress bar updates automatically, displaying both the current page number and the overall completion percentage.</p>
<p>For example, a 42-page document may display messages such as "Processing Page 2 of 42" before eventually reaching the final page.</p>
<p>Showing real-time progress improves the overall user experience and makes it easier to estimate the remaining processing time.</p>
<p>The OCR engine reports its progress while recognizing each page.</p>
<pre><code class="language-javascript">logger: info =&gt; {

    console.log(info);

}
</code></pre>
<p>Update the progress bar.</p>
<pre><code class="language-javascript">progressBar.style.width =

`${percentage}%`;

progressLabel.innerText =

`${percentage}%`;
</code></pre>
<p>Display the currently processed page.</p>
<pre><code class="language-javascript">status.innerText =

`Processing Page ${currentPage}

of ${totalPages}`;
</code></pre>
<p>Once the final page has been processed, the progress bar reaches one hundred percent and the extracted text becomes available for review.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/bc5e38e8-9fb8-44c8-8a8e-1dcd0c44cc5c.png" alt="OCR progress indicator showing the current page being processed and the overall completion percentage." style="display:block;margin:0 auto" width="567" height="100" loading="lazy">

<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/b00a2478-9079-49db-b8e7-909985109016.png" alt="OCR progress reaching the final page before completing text extraction." style="display:block;margin:0 auto" width="559" height="94" loading="lazy">

<h2 id="heading-understanding-ocr-confidence-scores">Understanding OCR Confidence Scores</h2>
<p>One useful feature of Tesseract.js is that it reports a confidence score for every page that it processes.</p>
<p>The confidence score estimates how accurately the OCR engine recognized the characters contained on a page. Higher confidence generally indicates cleaner scans, sharper text, and fewer recognition errors.</p>
<p>For example, a professionally scanned document with clear printed text may produce confidence scores above ninety-five percent, while older photocopies or blurry mobile phone images may produce lower values.</p>
<p>Displaying confidence scores helps users quickly identify pages that may require manual review or reprocessing.</p>
<p>In this application, every processed page displays its individual OCR confidence score after recognition finishes.</p>
<p>The OCR engine returns the confidence value together with the extracted text.</p>
<pre><code class="language-javascript">const confidence =

result.data.confidence;
</code></pre>
<p>Store each page's score.</p>
<pre><code class="language-javascript">confidenceScores.push({

    page: currentPage,

    confidence

});
</code></pre>
<p>Display the results.</p>
<pre><code class="language-javascript">confidenceScores.forEach(score=&gt;{

    console.log(

        score.page,

        score.confidence

    );

});
</code></pre>
<p>Pages with lower confidence scores may contain faded text, handwritten notes, poor lighting, skewed scans, or low image resolution. Reviewing these pages helps improve the overall quality of the extracted document.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/b08a9ace-3e1b-474c-9f13-939ed55522b5.png" alt="OCR confidence scores displayed for every processed PDF page." style="display:block;margin:0 auto" width="160" height="697" loading="lazy">

<h2 id="heading-optimizing-ocr-accuracy">Optimizing OCR Accuracy</h2>
<p>Even with a powerful OCR engine, the quality of the original document has a significant impact on the extracted text.</p>
<p>Scanned PDFs with sharp, high-resolution pages usually produce excellent results without additional processing. But documents containing faded printing, uneven lighting, shadows, handwritten annotations, or compression artifacts may require image enhancement before OCR begins.</p>
<p>The application includes several preprocessing options that improve recognition quality.</p>
<p>Grayscale conversion removes unnecessary color information and simplifies the image for the OCR engine. Increasing contrast helps separate text from the background, while sharpening improves character edges that may appear blurry in low-quality scans.</p>
<p>Selecting the correct recognition language is equally important. OCR models are trained for specific languages, so choosing the matching language greatly improves character recognition and reduces spelling mistakes.</p>
<p>Users should also select the appropriate accuracy mode. Fast Mode works well for clean digital scans, while High Accuracy Mode performs additional analysis that produces better results for difficult documents, although it requires more processing time.</p>
<p>Taking a few extra seconds to configure these settings often produces significantly cleaner text, higher confidence scores, and fewer manual corrections after extraction.</p>
<h2 id="heading-reviewing-the-extracted-text">Reviewing the Extracted Text</h2>
<p>Once the OCR process finishes, the application combines the recognized text from every processed page into a single output area.</p>
<p>Instead of immediately downloading the results, users can first review the extracted text directly inside the browser. This provides an opportunity to verify the OCR output, check formatting, identify recognition errors, and ensure that the correct pages were processed.</p>
<p>The extracted text preserves the page sequence by separating the content from each page with a clear page heading. This makes it much easier to navigate large documents such as books, contracts, technical manuals, invoices, government records, and research papers.</p>
<p>For searchable PDFs, the extracted text is usually very accurate. For scanned documents, users can quickly compare the OCR output with the original page preview and decide whether additional image enhancement or a different OCR language would improve the results.</p>
<p>The application also includes a <strong>Copy</strong> button so users can instantly copy all extracted text to the clipboard without downloading a file.</p>
<p>First, display the extracted text.</p>
<pre><code class="language-javascript">document.getElementById(

"output"

).value = finalText;
</code></pre>
<p>Next, implement the copy feature.</p>
<pre><code class="language-javascript">async function copyText(){

    await navigator.clipboard.writeText(

        finalText

    );

    alert("Text copied successfully.");

}
</code></pre>
<p>Attach the event listener.</p>
<pre><code class="language-javascript">document.getElementById(

"copyButton"

).addEventListener(

"click",

copyText

);
</code></pre>
<p>Providing an in-browser preview allows users to verify OCR quality before exporting the results.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/97a5b7c6-834f-4fd9-baba-c5f50b35708a.png" alt="Extracted OCR text displayed inside the browser with a copy button for quickly copying the recognized text." style="display:block;margin:0 auto" width="551" height="266" loading="lazy">

<h2 id="heading-exporting-the-ocr-results">Exporting the OCR Results</h2>
<p>After reviewing the extracted content, users can export it in different formats depending on how they intend to use the information.</p>
<p>Plain text files are ideal for editing inside any text editor, importing into word processors, or searching with desktop applications.</p>
<p>JSON exports are useful for developers building document management systems, AI applications, search engines, automation workflows, or APIs that consume structured OCR results.</p>
<p>Providing multiple export formats makes the OCR tool suitable for both everyday users and software developers.</p>
<p>Creating a downloadable TXT file is straightforward.</p>
<pre><code class="language-javascript">const blob = new Blob(

    [finalText],

    {

        type:"text/plain"

    }

);
</code></pre>
<p>Generate the download link.</p>
<pre><code class="language-javascript">const url = URL.createObjectURL(

blob

);

const link = document.createElement(

"a"

);

link.href = url;

link.download = "ocr-output.txt";

link.click();
</code></pre>
<p>JSON exports include additional information such as page numbers and confidence scores.</p>
<pre><code class="language-javascript">const report = {

    text: finalText,

    confidence: confidenceScores

};

downloadJSON(report);
</code></pre>
<p>These export options allow users to continue working with the extracted text in virtually any application.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/2dc04fb4-b1ff-498b-876d-6eeb85e59de9.png" alt="Export options allowing users to download OCR results as TXT or JSON files." style="display:block;margin:0 auto" width="575" height="123" loading="lazy">

<h2 id="heading-demo-how-the-pdf-ocr-tool-works">Demo: How the PDF OCR Tool Works</h2>
<h3 id="heading-step-1-upload-your-pdf">Step 1: Upload Your PDF</h3>
<p>The OCR workflow begins by uploading a PDF document using either the drag-and-drop area or the file picker.</p>
<p>Once a document has been selected, the browser validates the file format, loads the PDF into memory, and prepares it for page rendering. Since all processing occurs locally, the uploaded file never leaves the user's computer.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/eb91d9de-30de-480b-93cd-70f2ae0ca5e7.png" alt="PDF upload interface allowing users to select a PDF document for OCR text extraction." style="display:block;margin:0 auto" width="570" height="636" loading="lazy">

<h3 id="heading-step-2-preview-the-uploaded-pdf">Step 2: Preview the Uploaded PDF</h3>
<p>After the upload is complete, the application renders thumbnail previews of every page.</p>
<p>This allows users to verify that the correct document has been selected and inspect the page order before running OCR.</p>
<p>Previewing the document is particularly useful when processing large books, reports, legal documents, or scanned archives containing dozens of pages.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/622cfe19-938c-46af-aa40-0cee319ee477.png" alt="Uploaded PDF preview displaying page thumbnails before OCR processing begins." style="display:block;margin:0 auto" width="564" height="505" loading="lazy">

<h3 id="heading-step-3-configure-ocr-settings">Step 3: Configure OCR Settings</h3>
<p>Before text extraction begins, users configure the OCR options.</p>
<p>The application allows users to choose all pages or a specific page range, select the OCR language, switch between Fast and High Accuracy modes, and enable optional image enhancement features such as grayscale conversion, contrast improvement, and sharpening.</p>
<p>These settings help improve recognition quality depending on the condition of the scanned document.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/6bedc5cd-cc83-4bc6-be6f-2e7da57e408d.png" alt="OCR configuration panel showing page selection, language selection, accuracy mode, and image enhancement options.language selection menu displaying multiple supported recognition languages." style="display:block;margin:0 auto" width="565" height="563" loading="lazy">

<h3 id="heading-step-4-start-ocr-processing">Step 4: Start OCR Processing</h3>
<p>After reviewing the settings, users click the <strong>Extract Text</strong> button.</p>
<p>The browser begins processing every selected page one by one. During this stage, each rendered page image is analyzed by the OCR engine, which recognizes printed characters and converts them into editable text.</p>
<p>Because OCR runs directly inside the browser, even confidential documents remain completely private throughout the process.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/9f9cf7cd-6cf8-4686-ab7c-d4b5ab96dc47.png" alt="Extract Text button used to begin OCR processing for the uploaded PDF." style="display:block;margin:0 auto" width="575" height="171" loading="lazy">

<h3 id="heading-step-5-monitor-processing-progress">Step 5: Monitor Processing Progress</h3>
<p>As OCR runs, the application displays a live progress indicator.</p>
<p>Users can monitor the current page being processed, overall completion percentage, and recognition progress in real time. For large documents, this provides useful feedback and reassures users that the application is actively processing the file.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/51a2fcc1-f97f-4e9f-b53d-4a133b0ec4fc.png" alt="OCR progress indicator displaying the current page and completion percentage" style="display:block;margin:0 auto" width="567" height="100" loading="lazy">

<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/1db2c8f7-84f7-441b-9cbe-2a691e98c40f.png" alt="OCR processing nearing completion on the final page of the document." style="display:block;margin:0 auto" width="575" height="133" loading="lazy">

<h3 id="heading-step-6-review-ocr-confidence-scores">Step 6: Review OCR Confidence Scores</h3>
<p>Once recognition is complete, the application displays confidence scores for every processed page.</p>
<p>These values indicate how accurately the OCR engine recognized each page. Pages with lower confidence scores may contain faded text, skewed scans, or poor image quality and can be reviewed manually if necessary.</p>
<p>Confidence scores provide an additional layer of quality assurance before exporting the extracted text.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/1a3fec10-8c8c-4104-b9f9-9a555029999c.png" alt="OCR confidence scores displayed for each processed PDF page." style="display:block;margin:0 auto" width="160" height="697" loading="lazy">

<h3 id="heading-step-7-review-the-extracted-text">Step 7: Review the Extracted Text</h3>
<p>After OCR finishes, the complete extracted text appears inside the browser.</p>
<p>Users can scroll through the recognized content, compare it with the original document, and copy the text directly to the clipboard using the built-in Copy button.</p>
<p>This makes it easy to reuse the extracted information immediately without downloading a separate file.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/52b22a16-9fa3-4b34-9687-7923be187f4f.png" alt="Browser-based OCR text output with a built-in copy button." style="display:block;margin:0 auto" width="551" height="266" loading="lazy">

<h3 id="heading-step-8-export-the-results">Step 8: Export the Results</h3>
<p>Finally, users can export the OCR results.</p>
<p>The application supports downloading the extracted text as a TXT file for general editing or as a JSON file for software development and automation workflows.</p>
<p>After selecting the preferred format, the browser generates the file instantly without uploading any data to external servers.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979d22f93bc273cc33971b1/e60a2073-a432-4b97-a879-83430abb9cdb.png" alt="Export section allowing users to download OCR results in TXT or JSON format." style="display:block;margin:0 auto" width="575" height="123" loading="lazy">

<h2 id="heading-performance-optimization-tips">Performance Optimization Tips</h2>
<p>OCR is one of the most computationally intensive operations performed inside a browser. Although modern JavaScript engines and OCR libraries are highly optimized, a few simple techniques can significantly improve performance.</p>
<p>Before processing begins, render PDF pages at an appropriate resolution. Extremely high-resolution images increase processing time without always improving recognition accuracy.</p>
<pre><code class="language-javascript">const viewport = page.getViewport({

    scale:1.5

});
</code></pre>
<p>Processing pages sequentially instead of loading every page simultaneously reduces memory consumption for large documents.</p>
<pre><code class="language-javascript">for(let page = 1; page &lt;= totalPages; page++){

    await processPage(page);

}
</code></pre>
<p>Users should enable OCR only when working with scanned PDFs. Searchable PDFs already contain digital text, so OCR simply increases processing time without improving the results.</p>
<p>If the document contains hundreds of pages, allowing users to analyze only a selected page range can significantly reduce processing time.</p>
<p>Using grayscale images instead of full-color pages also improves recognition speed while reducing memory usage.</p>
<p>Whenever possible, choose the OCR language that matches the document. Smaller language models generally process faster and produce more accurate results than attempting recognition with an incorrect language.</p>
<p>Finally, remember to terminate the OCR worker after processing completes to release browser resources.</p>
<pre><code class="language-javascript">await worker.terminate();
</code></pre>
<p>These small optimizations produce a smoother user experience while making browser-based OCR practical even for large documents.</p>
<h2 id="heading-important-notes-from-real-world-use">Important Notes from Real-World Use</h2>
<p>OCR accuracy depends heavily on the quality of the original document.</p>
<p>Clean scans with high resolution, good lighting, and sharp printed text usually produce excellent recognition results. Older photocopies, faded documents, handwritten notes, or skewed scans may require image enhancement before OCR begins.</p>
<p>Before processing, always verify that the uploaded file is a valid PDF.</p>
<pre><code class="language-javascript">if(file.type !== "application/pdf"){

    alert("Please upload a valid PDF.");

    return;

}
</code></pre>
<p>Selecting the correct OCR language is equally important. Processing a Gujarati document with the English language model will significantly reduce recognition accuracy.</p>
<pre><code class="language-javascript">console.log(

"Selected Language:",

selectedLanguage

);
</code></pre>
<p>Users should also review OCR confidence scores after processing. Pages with lower confidence values often benefit from rescanning or using image enhancement options.</p>
<p>Because the entire workflow runs locally, browser-based OCR is well suited for confidential business reports, contracts, financial documents, legal records, healthcare files, and government paperwork that should never be uploaded to third-party services.</p>
<h2 id="heading-common-mistakes-to-avoid">Common Mistakes to Avoid</h2>
<p>One common mistake is enabling OCR for documents that already contain selectable text.</p>
<p>Searchable PDFs can usually be processed much faster by extracting the embedded text directly.</p>
<pre><code class="language-javascript">if(pdfHasText){

    skipOCR();

}
</code></pre>
<p>Another mistake is choosing the wrong recognition language.</p>
<p>Always select the language that matches the document before starting OCR.</p>
<pre><code class="language-javascript">worker = await Tesseract.createWorker(

selectedLanguage

);
</code></pre>
<p>Some users also attempt OCR on extremely low-quality scans without enabling image enhancement.</p>
<p>Using grayscale conversion, contrast adjustment, or sharpening often improves recognition quality considerably.</p>
<p>Finally, always review the extracted text before exporting it.</p>
<p>Checking the OCR output and confidence scores helps identify pages that may require rescanning or additional processing before the results are used in business workflows.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, you built a browser-based PDF OCR to Text Converter using JavaScript.</p>
<p>You learned how to upload PDF documents, preview scanned pages, configure OCR settings, select recognition languages, improve image quality, extract text, monitor processing progress, review OCR confidence scores, and export the recognized text directly from the browser.</p>
<p>More importantly, you discovered how modern browsers can perform Optical Character Recognition locally without requiring a backend server or cloud-based OCR service.</p>
<p>This approach keeps document processing fast, private, and secure while giving users complete control over how scanned PDFs are converted into editable text.</p>
<p>You can try the complete implementation here:</p>
<p><a href="https://allinonetools.net/pdf-to-text/"><strong>PDF OCR to Text Converter</strong></a></p>
<p>Once you understand this workflow, you can extend the project further by adding handwriting recognition, AI-powered document summarization, automatic translation, named entity extraction, keyword detection, document classification, searchable PDF generation, or intelligent document automation.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How To Create An Optical Character Reader Using Angular And Azure Computer Vision ]]>
                </title>
                <description>
                    <![CDATA[ By Ankit Sharma Introduction In this article, we will create an optical character recognition (OCR) application using Angular and the Azure Computer Vision Cognitive Service.  Computer Vision is an AI service that analyzes content in images. We will ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-create-an-optical-character-reader-using-angular-and-azure-computer-vision/</link>
                <guid isPermaLink="false">66d45dac787a2a3b05af4394</guid>
                
                    <category>
                        <![CDATA[ AI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Angular ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Azure ]]>
                    </category>
                
                    <category>
                        <![CDATA[ OCR  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 15 May 2020 19:03:00 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9c9aff740569d1a4ca2913.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Ankit Sharma</p>
<h2 id="heading-introduction">Introduction</h2>
<p>In this article, we will create an optical character recognition (OCR) application using Angular and the Azure Computer Vision Cognitive Service. </p>
<p>Computer Vision is an AI service that analyzes content in images. We will use the OCR feature of Computer Vision to detect the printed text in an image. The application will extract the text from the image and detects the language of the text. </p>
<p>Currently, the OCR API supports 25 languages.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ul>
<li>Install the latest LTS version of Node.JS from <a target="_blank" href="https://nodejs.org/en/download/">https://nodejs.org/en/download/</a></li>
<li>Install the Angular CLI from <a target="_blank" href="https://cli.angular.io/">https://cli.angular.io/</a></li>
<li>Install the .NET Core 3.1 SDK from <a target="_blank" href="https://dotnet.microsoft.com/download/dotnet-core/3.1">https://dotnet.microsoft.com/download/dotnet-core/3.1</a></li>
<li>Install the latest version of Visual Studio 2019 from <a target="_blank" href="https://visualstudio.microsoft.com/downloads/">https://visualstudio.microsoft.com/downloads/</a></li>
<li>An Azure subscription account. You can create a free Azure account at <a target="_blank" href="https://azure.microsoft.com/en-in/free/">https://azure.microsoft.com/en-in/free/</a></li>
</ul>
<h2 id="heading-source-code">Source Code</h2>
<p>You can get the source code from <a target="_blank" href="https://github.com/AnkitSharma-007/Angular-Computer-Vision-Azure-Cognitive-Services">GitHub</a>.</p>
<blockquote>
<p>We will use an ASP.NET Core backend for this application. The ASP.NET Core backend provides a straight forward authentication process to access Azure cognitive services. This will also ensure that the end-user won’t have direct access to cognitive services.</p>
</blockquote>
<h2 id="heading-create-the-azure-computer-vision-cognitive-service-resource">Create the Azure Computer Vision Cognitive Service resource</h2>
<p>Log in to the Azure portal and search for the cognitive services in the search bar and click on the result. Refer to the image shown below.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/CreateCVCogServ.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>On the next screen, click on the Add button. It will open the cognitive services marketplace page. Search for the Computer Vision in the search bar and click on the search result. It will open the Computer Vision API page. Click on the Create button to create a new Computer Vision resource. Refer to the image shown below.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/SelectComputerVisionCogServ.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>On the Create page, fill in the details as indicated below.</p>
<ul>
<li><strong>Name</strong>: Give a unique name for your resource.</li>
<li><strong>Subscription</strong>: Select the subscription type from the dropdown.</li>
<li><strong>Pricing tier</strong>: Select the pricing tier as per your choice.</li>
<li><strong>Resource group</strong>: Select an existing resource group or create a new one.</li>
</ul>
<p>Click on the Create button. Refer to the image shown below.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/ConfigureComputerVisionCogServ.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>After your resource is successfully deployed, click on the “Go to resource” button. You can see the Key and the endpoint for the newly created Computer Vision resource. Refer to the image shown below.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/ComputerVisionCogServKey-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Make a note of the key and the endpoint. We will be using these in the latter part of this article to invoke the Computer Vision OCR API from the .NET Code. The values are masked here for privacy.</p>
<h2 id="heading-creating-the-aspnet-core-application">Creating the ASP.NET Core application</h2>
<p>Open Visual Studio 2019 and click on “Create a new Project”. A “Create a new Project” dialog will open. Select “ASP.NET Core Web Application” and click on Next. Now you will be at “Configure your new project” screen, provide the name for your application as <code>ngComputerVision</code> and click on create. Refer to the image shown below.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/CreateProject_1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>You will be navigated to “Create a new ASP.NET Core web application” screen. Select “.NET Core” and “ASP.NET Core 3.1” from the dropdowns on the top. Then, select the “Angular” project template and click on <code>Create</code>. Refer to the image shown below.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/CreateProject_2.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>This will create our project. The folder structure of the application is shown below.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/Sol_Exp-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The <code>ClientApp</code> folder contains the Angular code for our application. The Controllers folders will contain our API controllers. The angular components are present inside the <code>ClientApp\src\app</code> folder. </p>
<p>The default template contains a few Angular components. These components won’t affect our application, but for the sake of simplicity, we will delete fetchdata and counter folders from <code>ClientApp/app/components</code> folder. Also, remove the reference for these two components from the <code>app.module.ts</code> file.</p>
<h2 id="heading-installing-computer-vision-api-library">Installing Computer Vision API library</h2>
<p>We will install the Azure Computer Vision API library which will provide us with the models out of the box to handle the Computer Vision REST API response. To install the package, navigate to Tools &gt;&gt; NuGet Package Manager &gt;&gt; Package Manager Console. It will open the Package Manager Console. Run the command as shown below.</p>
<pre><code>Install-Package Microsoft.Azure.CognitiveServices.Vision.ComputerVision -Version <span class="hljs-number">5.0</span><span class="hljs-number">.0</span>
</code></pre><p>You can learn more about this package at the <a target="_blank" href="https://www.nuget.org/packages/Microsoft.Azure.CognitiveServices.Vision.ComputerVision/">NuGet gallery</a>.</p>
<h2 id="heading-create-the-models">Create the Models</h2>
<p>Right-click on the <code>ngComputerVision</code> project and select Add &gt;&gt; New Folder. Name the folder as Models. Again, right-click on the Models folder and select Add &gt;&gt; Class to add a new class file. Put the name of your class as <code>LanguageDetails.cs</code> and click Add.</p>
<p>Open <a target="_blank" href="https://github.com/AnkitSharma-007/Angular-Computer-Vision-Azure-Cognitive-Services/blob/master/ngComputerVision/Models/LanguageDetails.cs">LanguageDetails.cs</a> and put the following code inside it.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">namespace</span> <span class="hljs-title">ngComputerVision.Models</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">LanguageDetails</span>
    {
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Name { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> NativeName { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Dir { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    }
}
</code></pre>
<p>Similarly, add a new class file <a target="_blank" href="https://github.com/AnkitSharma-007/Angular-Computer-Vision-Azure-Cognitive-Services/blob/master/ngComputerVision/Models/AvailableLanguage.cs">AvailableLanguage.cs</a> and put the following code inside it.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> System.Collections.Generic;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">ngComputerVision.Models</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">AvailableLanguage</span>
    {
        <span class="hljs-keyword">public</span> Dictionary&lt;<span class="hljs-keyword">string</span>, LanguageDetails&gt; Translation { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    }
}
</code></pre>
<p>We will also add two classes as DTO (Data Transfer Object) for sending data back to the client.</p>
<p>Create a new folder and name it DTOModels. Add the new class file <a target="_blank" href="https://github.com/AnkitSharma-007/Angular-Computer-Vision-Azure-Cognitive-Services/blob/master/ngComputerVision/DTOModels/AvailableLanguageDTO.cs">AvailableLanguageDTO.cs</a> in the DTOModels folder and put the following code inside it.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">namespace</span> <span class="hljs-title">ngComputerVision.DTOModels</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">AvailableLanguageDTO</span>
    {
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> LanguageID { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> LanguageName { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    }
}
</code></pre>
<p>Add the <a target="_blank" href="https://github.com/AnkitSharma-007/Angular-Computer-Vision-Azure-Cognitive-Services/blob/master/ngComputerVision/DTOModels/OcrResultDTO.cs">OcrResultDTO.cs</a> file and put the following code inside it.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">namespace</span> <span class="hljs-title">ngComputerVision.DTOModels</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">OcrResultDTO</span>
    {
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Language { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> DetectedText { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    }
}
</code></pre>
<h2 id="heading-adding-the-ocr-controller">Adding the OCR Controller</h2>
<p>We will add a new controller to our application. Right-click on the Controllers folder and select Add &gt;&gt; New Item. An “Add New Item” dialog box will open. Select “Visual C#” from the left panel, then select “API Controller Class” from templates panel and put the name as <code>OCRController.cs</code>. Click on Add. </p>
<p>Refer to the image below.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/AddController-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The <code>OCRController</code> will handle the image recognition requests from the client app. This controller will also return the list of all the languages supported by OCR API.</p>
<p>Open the <a target="_blank" href="https://github.com/AnkitSharma-007/Angular-Computer-Vision-Azure-Cognitive-Services/blob/master/ngComputerVision/Controllers/OCRController.cs">OCRController.cs</a> file and put the following code inside it.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> System;
<span class="hljs-keyword">using</span> System.Threading.Tasks;
<span class="hljs-keyword">using</span> Microsoft.AspNetCore.Mvc;
<span class="hljs-keyword">using</span> System.Net.Http;
<span class="hljs-keyword">using</span> System.Net.Http.Headers;
<span class="hljs-keyword">using</span> Newtonsoft.Json.Linq;
<span class="hljs-keyword">using</span> System.IO;
<span class="hljs-keyword">using</span> Newtonsoft.Json;
<span class="hljs-keyword">using</span> System.Text;
<span class="hljs-keyword">using</span> ngComputerVision.Models;
<span class="hljs-keyword">using</span> System.Collections.Generic;
<span class="hljs-keyword">using</span> Microsoft.Azure.CognitiveServices.Vision.ComputerVision.Models;
<span class="hljs-keyword">using</span> ngComputerVision.DTOModels;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">ngComputerVision.Controllers</span>
{
    [<span class="hljs-meta">Produces(<span class="hljs-meta-string">"application/json"</span>)</span>]
    [<span class="hljs-meta">Route(<span class="hljs-meta-string">"api/[controller]"</span>)</span>]
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">OCRController</span> : <span class="hljs-title">Controller</span>
    {
        <span class="hljs-keyword">static</span> <span class="hljs-keyword">string</span> subscriptionKey;
        <span class="hljs-keyword">static</span> <span class="hljs-keyword">string</span> endpoint;
        <span class="hljs-keyword">static</span> <span class="hljs-keyword">string</span> uriBase;

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">OCRController</span>(<span class="hljs-params"></span>)</span>
        {
            subscriptionKey = <span class="hljs-string">"b993f3afb4e04119bd8ed37171d4ec71"</span>;
            endpoint = <span class="hljs-string">"https://ankitocrdemo.cognitiveservices.azure.com/"</span>;
            uriBase = endpoint + <span class="hljs-string">"vision/v2.1/ocr"</span>;
        }

        [<span class="hljs-meta">HttpPost, DisableRequestSizeLimit</span>]
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;OcrResultDTO&gt; <span class="hljs-title">Post</span>(<span class="hljs-params"></span>)</span>
        {
            StringBuilder sb = <span class="hljs-keyword">new</span> StringBuilder();
            OcrResultDTO ocrResultDTO = <span class="hljs-keyword">new</span> OcrResultDTO();
            <span class="hljs-keyword">try</span>
            {
                <span class="hljs-keyword">if</span> (Request.Form.Files.Count &gt; <span class="hljs-number">0</span>)
                {
                    <span class="hljs-keyword">var</span> file = Request.Form.Files[Request.Form.Files.Count - <span class="hljs-number">1</span>];

                    <span class="hljs-keyword">if</span> (file.Length &gt; <span class="hljs-number">0</span>)
                    {
                        <span class="hljs-keyword">var</span> memoryStream = <span class="hljs-keyword">new</span> MemoryStream();
                        file.CopyTo(memoryStream);
                        <span class="hljs-keyword">byte</span>[] imageFileBytes = memoryStream.ToArray();
                        memoryStream.Flush();

                        <span class="hljs-keyword">string</span> JSONResult = <span class="hljs-keyword">await</span> ReadTextFromStream(imageFileBytes);

                        OcrResult ocrResult = JsonConvert.DeserializeObject&lt;OcrResult&gt;(JSONResult);
                        <span class="hljs-keyword">if</span> (!ocrResult.Language.Equals(<span class="hljs-string">"unk"</span>))
                        {
                            <span class="hljs-keyword">foreach</span> (OcrLine ocrLine <span class="hljs-keyword">in</span> ocrResult.Regions[<span class="hljs-number">0</span>].Lines)
                            {
                                <span class="hljs-keyword">foreach</span> (OcrWord ocrWord <span class="hljs-keyword">in</span> ocrLine.Words)
                                {
                                    sb.Append(ocrWord.Text);
                                    sb.Append(<span class="hljs-string">' '</span>);
                                }
                                sb.AppendLine();
                            }
                        }
                        <span class="hljs-keyword">else</span>
                        {
                            sb.Append(<span class="hljs-string">"This language is not supported."</span>);
                        }
                        ocrResultDTO.DetectedText = sb.ToString();
                        ocrResultDTO.Language = ocrResult.Language;
                    }
                }
                <span class="hljs-keyword">return</span> ocrResultDTO;
            }
            <span class="hljs-keyword">catch</span>
            {
                ocrResultDTO.DetectedText = <span class="hljs-string">"Error occurred. Try again"</span>;
                ocrResultDTO.Language = <span class="hljs-string">"unk"</span>;
                <span class="hljs-keyword">return</span> ocrResultDTO;
            }
        }

        <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">async</span> Task&lt;<span class="hljs-keyword">string</span>&gt; <span class="hljs-title">ReadTextFromStream</span>(<span class="hljs-params"><span class="hljs-keyword">byte</span>[] byteData</span>)</span>
        {
            <span class="hljs-keyword">try</span>
            {
                HttpClient client = <span class="hljs-keyword">new</span> HttpClient();
                client.DefaultRequestHeaders.Add(<span class="hljs-string">"Ocp-Apim-Subscription-Key"</span>, subscriptionKey);
                <span class="hljs-keyword">string</span> requestParameters = <span class="hljs-string">"language=unk&amp;detectOrientation=true"</span>;
                <span class="hljs-keyword">string</span> uri = uriBase + <span class="hljs-string">"?"</span> + requestParameters;
                HttpResponseMessage response;

                <span class="hljs-keyword">using</span> (ByteArrayContent content = <span class="hljs-keyword">new</span> ByteArrayContent(byteData))
                {
                    content.Headers.ContentType = <span class="hljs-keyword">new</span> MediaTypeHeaderValue(<span class="hljs-string">"application/octet-stream"</span>);
                    response = <span class="hljs-keyword">await</span> client.PostAsync(uri, content);
                }

                <span class="hljs-keyword">string</span> contentString = <span class="hljs-keyword">await</span> response.Content.ReadAsStringAsync();
                <span class="hljs-keyword">string</span> result = JToken.Parse(contentString).ToString();
                <span class="hljs-keyword">return</span> result;
            }
            <span class="hljs-keyword">catch</span> (Exception e)
            {
                <span class="hljs-keyword">return</span> e.Message;
            }
        }

        [<span class="hljs-meta">HttpGet</span>]
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;List&lt;AvailableLanguageDTO&gt;&gt; GetAvailableLanguages()
        {
            <span class="hljs-keyword">string</span> endpoint = <span class="hljs-string">"https://api.cognitive.microsofttranslator.com/languages?api-version=3.0&amp;scope=translation"</span>;
            <span class="hljs-keyword">var</span> client = <span class="hljs-keyword">new</span> HttpClient();
            <span class="hljs-keyword">using</span> (<span class="hljs-keyword">var</span> request = <span class="hljs-keyword">new</span> HttpRequestMessage())
            {
                request.Method = HttpMethod.Get;
                request.RequestUri = <span class="hljs-keyword">new</span> Uri(endpoint);
                <span class="hljs-keyword">var</span> response = <span class="hljs-keyword">await</span> client.SendAsync(request).ConfigureAwait(<span class="hljs-literal">false</span>);
                <span class="hljs-keyword">string</span> result = <span class="hljs-keyword">await</span> response.Content.ReadAsStringAsync();

                AvailableLanguage deserializedOutput = JsonConvert.DeserializeObject&lt;AvailableLanguage&gt;(result);

                List&lt;AvailableLanguageDTO&gt; availableLanguage = <span class="hljs-keyword">new</span> List&lt;AvailableLanguageDTO&gt;();

                <span class="hljs-keyword">foreach</span> (KeyValuePair&lt;<span class="hljs-keyword">string</span>, LanguageDetails&gt; translation <span class="hljs-keyword">in</span> deserializedOutput.Translation)
                {
                    AvailableLanguageDTO language = <span class="hljs-keyword">new</span> AvailableLanguageDTO();
                    language.LanguageID = translation.Key;
                    language.LanguageName = translation.Value.Name;

                    availableLanguage.Add(language);
                }
                <span class="hljs-keyword">return</span> availableLanguage;
            }
        }
    }
}
</code></pre>
<p>In the constructor of the class, we have initialized the key and the endpoint URL for the OCR API.</p>
<p>The Post method will receive the image data as a file collection in the request body and return an object of type <code>OcrResultDTO</code>. We will convert the image data to a byte array and invoke the <code>ReadTextFromStream</code> method. We will deserialize the response into an object of type <code>OcrResult</code>. We will then form the sentence by iterating over the <code>OcrWord</code> object.</p>
<p>Inside the <code>ReadTextFromStream</code> method, we will create a new <code>HttpRequestMessage</code>. This HTTP request is a Post request. We will pass the subscription key in the header of the request. The OCR API will return a JSON object having each word from the image as well as the detected language of the text.</p>
<p>The <code>GetAvailableLanguages</code> method will return the list of all the language supported by the Translate Text API. We will set the request URI and create a <code>HttpRequestMessage</code> which will be a Get request. This request URI will return a JSON object which will be deserialized to an object of type <code>AvailableLanguage</code>.</p>
<h3 id="heading-why-do-we-need-to-fetch-the-list-of-supported-languages"><strong>Why do we need to fetch the list of supported languages?</strong></h3>
<p>The OCR API returns the language code (e.g. en for English, de for German, etc.) of the detected language. But we cannot display the language code on the UI as it is not user-friendly. Therefore, we need a dictionary to look up the language name corresponding to the language code.</p>
<p>The Azure Computer Vision OCR API supports 25 languages. To know all the languages supported by OCR API see the list of <a target="_blank" href="https://docs.microsoft.com/en-us/azure/cognitive-services/computer-vision/language-support">supported languages</a>. These languages are a subset of the languages supported by the Azure Translate Text API. </p>
<p>Since there is no dedicated API endpoint to fetch the list of languages supported by OCR API, we are using the Translate Text API endpoint to fetch the list of languages. We will create the language lookup dictionary using the JSON response from this API call and filter the result based on the language code returned by the OCR API.</p>
<h2 id="heading-working-on-the-client-side-of-the-application">Working on the Client side of the application</h2>
<p>The code for the client-side is available in the ClientApp folder. We will use Angular CLI to work with the client code.</p>
<blockquote>
<p>Using Angular CLI is not mandatory. I am using Angular CLI here as it is user-friendly and easy to use. If you don’t want to use CLI then you can create the files for components and services manually.</p>
</blockquote>
<p>Navigate to the ngComputerVision\ClientApp folder in your machine and open a command window. We will execute all our Angular CLI commands in this window.</p>
<h2 id="heading-create-the-client-side-models">Create the client-side models</h2>
<p>Create a folder called models inside the <code>ClientApp\src\app</code> folder. Now we will create a file <a target="_blank" href="https://github.com/AnkitSharma-007/Angular-Computer-Vision-Azure-Cognitive-Services/blob/master/ngComputerVision/ClientApp/src/app/models/availablelanguage.ts">availablelanguage.ts</a> in the models folder. Put the following code in it.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AvailableLanguage {
    languageID: <span class="hljs-built_in">string</span>;
    languageName: <span class="hljs-built_in">string</span>;
}
</code></pre>
<p>Similarly, create another file inside the models folder called <a target="_blank" href="https://github.com/AnkitSharma-007/Angular-Computer-Vision-Azure-Cognitive-Services/blob/master/ngComputerVision/ClientApp/src/app/models/ocrresult.ts">ocrresult.ts</a>. Put the following code in it.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> OcrResult {
    language: <span class="hljs-built_in">string</span>;
    detectedText: <span class="hljs-built_in">string</span>
}
</code></pre>
<p>You can observe that both these classes have the same definition as the DTO classes we created on the server-side. This will allow us to bind the data returned from the server directly to our models.</p>
<h2 id="heading-create-the-computervision-service">Create the Computervision Service</h2>
<p>We will create an Angular service which will invoke the Web API endpoints, convert the Web API response to JSON and pass it to our component. Run the following command.</p>
<pre><code>ng g s services\Computervision
</code></pre><p>This command will create a folder name as services and then create the following two files inside it.</p>
<ul>
<li>computervision.service.ts — the service class file.</li>
<li>computervision.service.spec.ts — the unit test file for service.</li>
</ul>
<p>Open <a target="_blank" href="https://github.com/AnkitSharma-007/Angular-Computer-Vision-Azure-Cognitive-Services/blob/master/ngComputerVision/ClientApp/src/app/services/computervision.service.ts">computervision.service.ts</a> file and put the following code inside it.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/core'</span>;
<span class="hljs-keyword">import</span> { HttpClient } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/common/http'</span>;

<span class="hljs-meta">@Injectable</span>({
  providedIn: <span class="hljs-string">'root'</span>
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ComputervisionService {

  baseURL: <span class="hljs-built_in">string</span>;

  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> http: HttpClient</span>) {
    <span class="hljs-built_in">this</span>.baseURL = <span class="hljs-string">'/api/OCR'</span>;
  }

  getAvailableLanguage() {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.http.get(<span class="hljs-built_in">this</span>.baseURL)
      .pipe(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> {
        <span class="hljs-keyword">return</span> response;
      });
  }

  getTextFromImage(image: FormData) {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.http.post(<span class="hljs-built_in">this</span>.baseURL, image)
      .pipe(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> {
        <span class="hljs-keyword">return</span> response;
      });
  }
}
</code></pre>
<p>We have defined a variable baseURL which will hold the endpoint URL of our API. We will initialize the baseURL in the constructor and set it to the endpoint of the <code>OCRController</code>.</p>
<p>The <code>getAvailableLanguage</code> method will send a Get request to the <code>GetAvailableLanguages</code> method of the <code>OCRController</code> to fetch the list of supported languages for OCR.</p>
<p>The <code>getTextFromImage</code> method will send a Post request to the <code>OCRController</code> and supply the parameter of type <code>FormData</code>. It will fetch the detected text from the image and language code of the text.</p>
<h3 id="heading-create-the-ocr-component"><strong>Create the Ocr component</strong></h3>
<p>Run the following command in the command prompt to create the <code>OcrComponent</code>.</p>
<pre><code>ng g c ocr --<span class="hljs-built_in">module</span> app
</code></pre><p>The <code>--module</code> flag will ensure that this component will get registered at <code>app.module.ts</code>.</p>
<p>Open <a target="_blank" href="https://github.com/AnkitSharma-007/Angular-Computer-Vision-Azure-Cognitive-Services/blob/master/ngComputerVision/ClientApp/src/app/ocr/ocr.component.html">ocr.component.html</a> and put the following code in it.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Optical Character Recognition (OCR) using Angular and Azure Computer Vision Cognitive Services<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-5"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span> <span class="hljs-attr">disabled</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control"</span> <span class="hljs-attr">rows</span>=<span class="hljs-string">"10"</span> <span class="hljs-attr">cols</span>=<span class="hljs-string">"15"</span>&gt;</span>{{ocrResult?.detectedText}}<span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">hr</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-sm-5"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span> Detected Language :<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-sm-6"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">disabled</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{{DetectedTextLanguage}}</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-5"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"image-container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"preview-image"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{{imagePreview}}</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"file"</span> (<span class="hljs-attr">change</span>)=<span class="hljs-string">"uploadImage($event)"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{{status}}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">hr</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> [<span class="hljs-attr">disabled</span>]=<span class="hljs-string">"loading"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-primary btn-lg"</span> (<span class="hljs-attr">click</span>)=<span class="hljs-string">"GetText()"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">span</span> *<span class="hljs-attr">ngIf</span>=<span class="hljs-string">"loading"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"spinner-border spinner-border-sm mr-1"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>Extract Text
    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>We have defined a text area to display the detected text and a text box for displaying the detected language. We have defined a file upload control which will allow us to upload an image. After uploading the image, the preview of the image will be displayed using an <code>&lt;img&gt;</code> element.</p>
<p>Open <a target="_blank" href="https://github.com/AnkitSharma-007/Angular-Computer-Vision-Azure-Cognitive-Services/blob/master/ngComputerVision/ClientApp/src/app/ocr/ocr.component.ts">ocr.component.ts</a> and put the following code in it.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Component, OnInit } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/core'</span>;
<span class="hljs-keyword">import</span> { ComputervisionService } <span class="hljs-keyword">from</span> <span class="hljs-string">'../services/computervision.service'</span>;
<span class="hljs-keyword">import</span> { AvailableLanguage } <span class="hljs-keyword">from</span> <span class="hljs-string">'../models/availablelanguage'</span>;
<span class="hljs-keyword">import</span> { OcrResult } <span class="hljs-keyword">from</span> <span class="hljs-string">'../models/ocrresult'</span>;

<span class="hljs-meta">@Component</span>({
  selector: <span class="hljs-string">'app-ocr'</span>,
  templateUrl: <span class="hljs-string">'./ocr.component.html'</span>,
  styleUrls: [<span class="hljs-string">'./ocr.component.css'</span>]
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> OcrComponent <span class="hljs-keyword">implements</span> OnInit {

  loading = <span class="hljs-literal">false</span>;
  imageFile;
  imagePreview;
  imageData = <span class="hljs-keyword">new</span> FormData();
  availableLanguage: AvailableLanguage[];
  DetectedTextLanguage: <span class="hljs-built_in">string</span>;
  ocrResult: OcrResult;
  DefaultStatus: <span class="hljs-built_in">string</span>;
  status: <span class="hljs-built_in">string</span>;
  maxFileSize: <span class="hljs-built_in">number</span>;
  isValidFile = <span class="hljs-literal">true</span>;

  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> computervisionService: ComputervisionService</span>) {
    <span class="hljs-built_in">this</span>.DefaultStatus = <span class="hljs-string">"Maximum size allowed for the image is 4 MB"</span>;
    <span class="hljs-built_in">this</span>.status = <span class="hljs-built_in">this</span>.DefaultStatus;
    <span class="hljs-built_in">this</span>.maxFileSize = <span class="hljs-number">4</span> * <span class="hljs-number">1024</span> * <span class="hljs-number">1024</span>; <span class="hljs-comment">// 4MB</span>
  }

  ngOnInit() {
    <span class="hljs-built_in">this</span>.computervisionService.getAvailableLanguage().subscribe(
      <span class="hljs-function">(<span class="hljs-params">result: AvailableLanguage[]</span>) =&gt;</span> <span class="hljs-built_in">this</span>.availableLanguage = result
    );
  }

  uploadImage(event) {
    <span class="hljs-built_in">this</span>.imageFile = event.target.files[<span class="hljs-number">0</span>];
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.imageFile.size &gt; <span class="hljs-built_in">this</span>.maxFileSize) {
      <span class="hljs-built_in">this</span>.status = <span class="hljs-string">`The file size is <span class="hljs-subst">${<span class="hljs-built_in">this</span>.imageFile.size}</span> bytes, this is more than the allowed limit of <span class="hljs-subst">${<span class="hljs-built_in">this</span>.maxFileSize}</span> bytes.`</span>;
      <span class="hljs-built_in">this</span>.isValidFile = <span class="hljs-literal">false</span>;
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.imageFile.type.indexOf(<span class="hljs-string">'image'</span>) == <span class="hljs-number">-1</span>) {
      <span class="hljs-built_in">this</span>.status = <span class="hljs-string">"Please upload a valid image file"</span>;
      <span class="hljs-built_in">this</span>.isValidFile = <span class="hljs-literal">false</span>;
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-keyword">const</span> reader = <span class="hljs-keyword">new</span> FileReader();
      reader.readAsDataURL(event.target.files[<span class="hljs-number">0</span>]);
      reader.onload = <span class="hljs-function">() =&gt;</span> {
        <span class="hljs-built_in">this</span>.imagePreview = reader.result;
      };
      <span class="hljs-built_in">this</span>.status = <span class="hljs-built_in">this</span>.DefaultStatus;
      <span class="hljs-built_in">this</span>.isValidFile = <span class="hljs-literal">true</span>;
    }
  }

  GetText() {
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.isValidFile) {

      <span class="hljs-built_in">this</span>.loading = <span class="hljs-literal">true</span>;
      <span class="hljs-built_in">this</span>.imageData.append(<span class="hljs-string">'imageFile'</span>, <span class="hljs-built_in">this</span>.imageFile);

      <span class="hljs-built_in">this</span>.computervisionService.getTextFromImage(<span class="hljs-built_in">this</span>.imageData).subscribe(
        <span class="hljs-function">(<span class="hljs-params">result: OcrResult</span>) =&gt;</span> {
          <span class="hljs-built_in">this</span>.ocrResult = result;
          <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.availableLanguage.find(<span class="hljs-function"><span class="hljs-params">x</span> =&gt;</span> x.languageID === <span class="hljs-built_in">this</span>.ocrResult.language)) {
            <span class="hljs-built_in">this</span>.DetectedTextLanguage = <span class="hljs-built_in">this</span>.availableLanguage.find(<span class="hljs-function"><span class="hljs-params">x</span> =&gt;</span> x.languageID === <span class="hljs-built_in">this</span>.ocrResult.language).languageName;
          } <span class="hljs-keyword">else</span> {
            <span class="hljs-built_in">this</span>.DetectedTextLanguage = <span class="hljs-string">"unknown"</span>;
          }
          <span class="hljs-built_in">this</span>.loading = <span class="hljs-literal">false</span>;
        });
    }
  }
}
</code></pre>
<p>We will inject the <code>ComputervisionService</code> in the constructor of the <code>OcrComponent</code> and set a message and the value for the max image size allowed inside the constructor.</p>
<p>We will invoke the <code>getAvailableLanguage</code> method of our service in the <code>ngOnInit</code> and store the result in an array of type <code>AvailableLanguage</code>.</p>
<p>The <code>uploadImage</code> method will be invoked upon uploading an image. We will check if the uploaded file is a valid image and within the allowed size limit. We will process the image data using a <code>FileReader</code> object. The <code>readAsDataURL</code> method will read the contents of the uploaded file. </p>
<p>Upon successful completion of the read operation, the <code>reader.onload</code> event will be triggered. The value of <code>imagePreview</code> will be set to the result returned by the fileReader object, which is of type <code>ArrayBuffer</code>.</p>
<p>Inside the <code>GetText</code> method, we will append the image file to a variable for type <code>FormData</code>. We will invoke the <code>getTextFromImage</code> of the service and bind the result to an object of type <code>OcrResult</code>. We will search for the language name from the array <code>availableLanguage</code>, based on the language code returned from the service. If the language code is not found, we will set the language as unknown.</p>
<p>We will add the styling for the text area in <a target="_blank" href="https://github.com/AnkitSharma-007/Angular-Computer-Vision-Azure-Cognitive-Services/blob/master/ngComputerVision/ClientApp/src/app/ocr/ocr.component.css">ocr.component.css</a> as shown below.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.preview-image</span> {
    <span class="hljs-attribute">max-height</span>: <span class="hljs-number">300px</span>;
    <span class="hljs-attribute">max-width</span>: <span class="hljs-number">300px</span>;
}

<span class="hljs-selector-class">.image-container</span>{
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">15px</span>;
  <span class="hljs-attribute">align-content</span>: center;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">2px</span> dashed skyblue;
}
</code></pre>
<h2 id="heading-adding-the-links-in-nav-menu">Adding the links in Nav Menu</h2>
<p>We will add the navigation links for our components in the nav menu. Open <a target="_blank" href="https://github.com/AnkitSharma-007/Angular-Computer-Vision-Azure-Cognitive-Services/blob/master/ngComputerVision/ClientApp/src/app/nav-menu/nav-menu.component.html#L14-L16">nav-menu.component.html</a> and remove the links for Counter and Fetch data components. Add the following lines in the list of navigation links.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"nav-item"</span> [<span class="hljs-attr">routerLinkActive</span>]=<span class="hljs-string">"['link-active']"</span>&gt;</span>
 <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"nav-link text-dark"</span> <span class="hljs-attr">routerLink</span>=<span class="hljs-string">'/computer-vision-ocr'</span>&gt;</span>Computer Vision<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
</code></pre>
<h2 id="heading-execution-demo">Execution Demo</h2>
<p>Press F5 to launch the application. Click on the Computer Vision button on the nav menu at the top. You can upload an image and extract the text from the image as shown in the image below.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/ngComputerVision.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Execution Demo</em></p>
<h2 id="heading-summary">Summary</h2>
<p>We have created an optical character recognition (OCR) application using Angular and the Computer Vision Azure Cognitive Service. The application is able to extract the printed text from the uploaded image and recognizes the language of the text. The OCR API of the Computer Vision is used which can recognize text in 25 languages.</p>
<p>I just released a free eBook on Angular and Firebase. You can download the free book from <a target="_blank" href="https://www.c-sharpcorner.com/ebooks/build-a-full-stack-web-application-using-angular-and-firebase">Build a Full-Stack Web Application Using Angular &amp; Firebase</a></p>
<h2 id="heading-see-also">See Also</h2>
<ul>
<li><a target="_blank" href="https://ankitsharmablogs.com/template-driven-form-validation-in-angular/">Template-Driven Form Validation In Angular</a></li>
<li><a target="_blank" href="https://ankitsharmablogs.com/reactive-form-validation-in-angular/">Reactive Form Validation In Angular</a></li>
<li><a target="_blank" href="https://ankitsharmablogs.com/continuous-deployment-for-angular-app-using-heroku-and-github/">Continuous Deployment For Angular App Using Heroku And GitHub</a></li>
<li><a target="_blank" href="https://ankitsharmablogs.com/policy-based-authorization-in-angular-using-jwt/">Policy-Based Authorization In Angular Using JWT</a></li>
<li><a target="_blank" href="https://ankitsharmablogs.com/optical-character-reader-using-blazor-and-computer-vision/">Optical Character Reader Using Blazor And Computer Vision</a></li>
</ul>
<p>If you like the article, share with you friends. You can also connect with me on <a target="_blank" href="https://twitter.com/ankitsharma_007">Twitter</a> and <a target="_blank" href="https://www.linkedin.com/in/ankitsharma-007/">LinkedIn</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to use image preprocessing to improve the accuracy of Tesseract ]]>
                </title>
                <description>
                    <![CDATA[ By Berk Kaan Kuguoglu Previously, on How to get started with Tesseract, I gave you a practical quick-start tutorial on Tesseract using Python. It is a pretty simple overview, but it should help you get started with Tesseract and clear some hurdles th... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/getting-started-with-tesseract-part-ii-f7f9a0899b3f/</link>
                <guid isPermaLink="false">66c34b625ced6d98e4bd32e0</guid>
                
                    <category>
                        <![CDATA[ OCR  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ opencv ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tesseract ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 06 Jun 2018 13:25:41 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*iZwvUAtgcOAVgjO23Hd2ig.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Berk Kaan Kuguoglu</p>
<p>Previously, on <a target="_blank" href="https://medium.com/@bkaankuguoglu/getting-started-with-tesseract-part-i-2a6a6b1cf75e">How to get started with Tesseract</a>, I gave you a practical quick-start tutorial on Tesseract using Python. It is a pretty simple overview, but it should help you get started with Tesseract and clear some hurdles that I faced when I was in your shoes. Now, I’m keen on showing you a few more tricks and stuff you can do with Tesseract and OpenCV to improve your overall accuracy.</p>
<h3 id="heading-where-did-we-leave-off-last-time">Where did we leave off last time?</h3>
<p>In <a target="_blank" href="https://medium.com/@bkaankuguoglu/getting-started-with-tesseract-part-i-2a6a6b1cf75e">the previous story</a>, I didn’t bother going into details for the most part. But if you liked the first story, here comes the sequel! So where did we leave off?</p>
<p>Ah, we had a brief overview of rescaling, noise removal, and binarization. Now, it’s time to get down to details and show you a few settings you can play with.</p>
<h3 id="heading-rescaling">Rescaling</h3>
<p>The images that are rescaled are either shrunk or enlarged. If you’re interested in shrinking your image, <strong>INTER_AREA</strong> is the way to go for you. (Btw, the parameters <em>fx</em> and <em>fy</em> denote the scaling factor in the function below.)</p>
<pre><code>img = cv2.resize(img, None, fx=<span class="hljs-number">0.5</span>, fy=<span class="hljs-number">0.5</span>, interpolation=cv2.INTER_AREA)
</code></pre><p>On the other hand, as in most cases, you may need to scale your image to a larger size to recognize small characters. In this case, <strong>INTER_CUBIC</strong> generally performs better than other alternatives, though it’s also slower than others.</p>
<pre><code>img = cv2.resize(img, None, fx=<span class="hljs-number">2</span>, fy=<span class="hljs-number">2</span>, interpolation=cv2.INTER_CUBIC)
</code></pre><p>If you’d like to trade off some of your image quality for faster performance, you may want to try <strong>INTER_LINEAR</strong> for enlarging images.</p>
<pre><code>img = cv2.resize(img, None, fx=<span class="hljs-number">2</span>, fy=<span class="hljs-number">2</span>, interpolation=cv2.INTER_LINEAR)
</code></pre><h3 id="heading-blurring"><strong>Blurring</strong></h3>
<p>It’s worth mentioning that there are a few blur filters available in the <a target="_blank" href="https://docs.opencv.org/3.4.0/d4/d13/tutorial_py_filtering.html">OpenCV library</a>. Image blurring is usually achieved by convolving the image with a low-pass filter kernel. While filters are usually used to blur the image or to reduce noise, there are a few differences between them.</p>
<h4 id="heading-1-averaging">1. Averaging</h4>
<p>After convolving an image with a normalized box filter, this simply takes the average of all the pixels under the kernel area and replaces the central element. It’s pretty self-explanatory, I guess.</p>
<pre><code>img = cv.blur(img,(<span class="hljs-number">5</span>,<span class="hljs-number">5</span>))
</code></pre><h4 id="heading-2-gaussian-blurring">2. Gaussian blurring</h4>
<p>This works in a similar fashion to Averaging, but it uses Gaussian kernel, instead of a normalized box filter, for convolution. Here, the dimensions of the kernel and standard deviations in both directions can be determined independently. Gaussian blurring is very useful for removing — guess what? — gaussian noise from the image. On the contrary, gaussian blurring does not preserve the edges in the input.</p>
<pre><code>img = cv2.GaussianBlur(img, (<span class="hljs-number">5</span>, <span class="hljs-number">5</span>), <span class="hljs-number">0</span>)
</code></pre><h4 id="heading-3-median-blurring">3. Median blurring</h4>
<p>The central element in the kernel area is replaced with the median of all the pixels under the kernel. Particularly, this outperforms other blurring methods in removing salt-and-pepper noise in the images.</p>
<p>Median blurring is a non-linear filter. Unlike linear filters, median blurring replaces the pixel values with the median value available in the neighborhood values. So, median blurring preserves edges as the median value must be the value of one of neighboring pixels.</p>
<pre><code>img = cv2.medianBlur(img, <span class="hljs-number">3</span>)
</code></pre><h4 id="heading-4-bilateral-filtering">4. Bilateral filtering</h4>
<p>Speaking of keeping edges sharp, bilateral filtering is quite useful for removing the noise without smoothing the edges. Similar to gaussian blurring, bilateral filtering also uses a gaussian filter to find the gaussian weighted average in the neighborhood. However, it also takes pixel difference into account while blurring the nearby pixels.</p>
<p>Thus, it ensures only those pixels with similar intensity to the central pixel are blurred, whereas the pixels with distinct pixel values are not blurred. In doing so, the edges that have larger intensity variation, so-called edges, are preserved.</p>
<pre><code>img = cv.bilateralFilter(img,<span class="hljs-number">9</span>,<span class="hljs-number">75</span>,<span class="hljs-number">75</span>)
</code></pre><p>Overall, if you are interested in preserving the edges, go with median blurring or bilateral filtering. On the contrary, gaussian blurring is likely to be faster than median blurring. Due to its computational complexity, bilateral filtering is the slowest of all methods.</p>
<p>Again, you do you.</p>
<h3 id="heading-image-thresholding">Image Thresholding</h3>
<p>There’s not a single image thresholding method that fits all types of documents. In reality, all filters perform differently on varying images. For instance, while some filters successfully binarize some images, they may fail to binarize others. Likewise, some filters may work well with those images that other filters cannot binarize well.</p>
<p>I’ll try to cover the basics here, though I do recommend that you read the official documentation of <a target="_blank" href="https://docs.opencv.org/3.4.0/d7/d4d/tutorial_py_thresholding.html">OpenCV on Image Thresholding</a> for more information and the theory behind it.</p>
<h4 id="heading-1-simple-threshold">1. Simple Threshold</h4>
<p>You might recall a friend of yours giving you some advice about your life by saying “things are not always black and white”. Well, for a simple threshold, things are pretty straight-forward.</p>
<pre><code>cv.threshold(img,<span class="hljs-number">127</span>,<span class="hljs-number">255</span>,cv.THRESH_BINARY)
</code></pre><p>First, you pick a threshold value, say 127. If the pixel value is greater than the threshold, it becomes black. If less, it becomes white. OpenCV provides us with different types of thresholding methods that can be passed as the fourth parameter. I often use binary threshold for most tasks, but for other thresholding methods you may visit <a target="_blank" href="https://docs.opencv.org/3.4.0/d7/d4d/tutorial_py_thresholding.html">the official documentation.</a></p>
<h4 id="heading-2-adaptive-threshold">2. Adaptive Threshold</h4>
<p>Rather than setting a one global threshold value, we let the algorithm calculate the threshold for small regions of the image. Thus, we end up having various threshold values for different regions of the image, which is great!</p>
<pre><code>cv2.adaptiveThreshold(img, <span class="hljs-number">255</span>, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, <span class="hljs-number">31</span>, <span class="hljs-number">2</span>)
</code></pre><p>There are two adaptive methods for calculating the threshold value. While <strong>Adaptive Thresh Mean</strong> returns the mean of the neighborhood area, <strong>Adaptive Gaussian Mean</strong> calculates the weighted sum of the neighborhood values.</p>
<p>We’ve got two more parameters that determine the size of the neighborhood area and the constant value that is subtracted from the result: the fifth and sixth parameters, respectively.</p>
<h4 id="heading-3-otsus-threshold">3. Otsu’s Threshold</h4>
<p>This method particularly works well with <strong>bimodal images</strong>, which is an image whose histogram has two peaks. If this is the case, we might be keen on picking a threshold value between these peaks. This is what Otsu’s Binarization actually does, though.</p>
<pre><code>cv2.threshold(img, <span class="hljs-number">0</span>, <span class="hljs-number">255</span>, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[<span class="hljs-number">1</span>]
</code></pre><p>It’s pretty useful for some cases. But it may fail to binarize images that are not bimodal. So, please take this filter with a grain of salt.</p>
<h4 id="heading-types-of-thresholding">Types of thresholding</h4>
<p>You might have already noticed there is a parameter, or in some cases a combination of a few parameters, that are passed as arguments to determine the type of thresholding, such as THRESH_BINARY. I’m not going into the detail here now, as it is explained clearly in <a target="_blank" href="https://docs.opencv.org/3.4.0/d7/d4d/tutorial_py_thresholding.html">the official documentation</a>.</p>
<h3 id="heading-what-next">What next?</h3>
<p>So far, we’ve discussed some of the techniques of image pre-processing. You might wonder when exactly you’re going to get your hands dirty. Well, the time has come. Before you get back to your favorite Python IDE — mine is <a target="_blank" href="https://www.jetbrains.com/pycharm/">PyCharm</a>, btw — I’m going to show you few lines of code that will save you some time while trying to find which combination of filters and image manipulations work well with your documents.</p>
<p>Let’s start by defining a switcher function that holds a few combinations of thresholding filters and blurring methods. Once you get the idea, you could also add more filters, incorporating other image pre-processing methods like rescaling into your filter set.</p>
<p>Here I’ve created 20 different combinations of image thresholding methods, blurring methods, and kernel sizes. The switcher function, _apply<em>threshold</em>, takes two arguments, namely OpenCV image and an integer that denotes the filter. Likewise, since this function returns the OpenCV image as a result, it could easily be integrated into our _get<em>string</em> function from the previous post.</p>
<pre><code>def apply_threshold(img, argument):    switcher = {        <span class="hljs-number">1</span>: cv2.threshold(cv2.GaussianBlur(img, (<span class="hljs-number">9</span>, <span class="hljs-number">9</span>), <span class="hljs-number">0</span>), <span class="hljs-number">0</span>, <span class="hljs-number">255</span>, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[<span class="hljs-number">1</span>],        <span class="hljs-number">2</span>: cv2.threshold(cv2.GaussianBlur(img, (<span class="hljs-number">7</span>, <span class="hljs-number">7</span>), <span class="hljs-number">0</span>), <span class="hljs-number">0</span>, <span class="hljs-number">255</span>, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[<span class="hljs-number">1</span>],        <span class="hljs-number">3</span>: cv2.threshold(cv2.GaussianBlur(img, (<span class="hljs-number">5</span>, <span class="hljs-number">5</span>), <span class="hljs-number">0</span>), <span class="hljs-number">0</span>, <span class="hljs-number">255</span>, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[<span class="hljs-number">1</span>],
</code></pre><pre><code>                              ...
</code></pre><pre><code>        <span class="hljs-number">18</span>: cv2.adaptiveThreshold(cv2.medianBlur(img, <span class="hljs-number">7</span>), <span class="hljs-number">255</span>, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, <span class="hljs-number">31</span>, <span class="hljs-number">2</span>),        <span class="hljs-number">19</span>: cv2.adaptiveThreshold(cv2.medianBlur(img, <span class="hljs-number">5</span>), <span class="hljs-number">255</span>, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, <span class="hljs-number">31</span>, <span class="hljs-number">2</span>),        <span class="hljs-number">20</span>: cv2.adaptiveThreshold(cv2.medianBlur(img, <span class="hljs-number">3</span>), <span class="hljs-number">255</span>, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, <span class="hljs-number">31</span>, <span class="hljs-number">2</span>)    }    <span class="hljs-keyword">return</span> switcher.get(argument, <span class="hljs-string">"Invalid method"</span>)
</code></pre><p>And, here it comes.</p>
<pre><code>def get_string(img_path, method):    # Read image using opencv    img = cv2.imread(img_path)    # Extract the file name without the file extension    file_name = os.path.basename(img_path).split(<span class="hljs-string">'.'</span>)[<span class="hljs-number">0</span>]    file_name = file_name.split()[<span class="hljs-number">0</span>]    # Create a directory <span class="hljs-keyword">for</span> outputs    output_path = os.path.join(output_dir, file_name)    <span class="hljs-keyword">if</span> not os.path.exists(output_path):        os.makedirs(output_path)
</code></pre><pre><code>    # Rescale the image, <span class="hljs-keyword">if</span> needed.    img = cv2.resize(img, None, fx=<span class="hljs-number">1.5</span>, fy=<span class="hljs-number">1.5</span>, interpolation=cv2.INTER_CUBIC)
</code></pre><pre><code>    # Convert to gray    img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)    # Apply dilation and erosion to remove some noise    kernel = np.ones((<span class="hljs-number">1</span>, <span class="hljs-number">1</span>), np.uint8)    img = cv2.dilate(img, kernel, iterations=<span class="hljs-number">1</span>)    img = cv2.erode(img, kernel, iterations=<span class="hljs-number">1</span>)
</code></pre><pre><code>    # Apply threshold to get image <span class="hljs-keyword">with</span> only black and white    img = apply_threshold(img, method)
</code></pre><pre><code>    # Save the filtered image <span class="hljs-keyword">in</span> the output directory    save_path = os.path.join(output_path, file_name + <span class="hljs-string">"_filter_"</span> + str(method) + <span class="hljs-string">".jpg"</span>)    cv2.imwrite(save_path, img)    # Recognize text <span class="hljs-keyword">with</span> tesseract <span class="hljs-keyword">for</span> python    result = pytesseract.image_to_string(img, lang=<span class="hljs-string">"eng"</span>)
</code></pre><pre><code>    <span class="hljs-keyword">return</span> result
</code></pre><h3 id="heading-last-words">Last words</h3>
<p>Now, all we need to do is to write a simple for loop that iterates over the input directory to collect images and applies each filter on the images gathered. I prefer to use <em>glob</em>, or <em>os</em>, for collecting images from directories, and <em>argparse</em> for passing arguments via terminal, like any other sane person would do.</p>
<p>Here I’ve done pretty much the same thing as in my <a target="_blank" href="https://gist.github.com/bkaankuguoglu/111f9f5e0c30b5f57d7c5338d6dcb6fc">gist</a>, if you’d like have a look at it. However, feel free to use the tools you feel comfortable with.</p>
<p>So far, I’ve tried to cover a few useful image pre-processing concepts and implementations, though it’s probably just the tip of the iceberg. I don’t know how much “leisure time” I’m going to have in the upcoming weeks, so, I can’t give you a specific time frame for publishing my next post. However, I’m considering adding at least one more part to this series that explains a few things I left out, such as rotation and de-skewing on images.</p>
<p>Until then, best bet is to just keep your wits about you and continue to look for signs.<a target="_blank" href="https://www.youtube.com/watch?v=B_CHjYoqPUU">*</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How you can get started with Tesseract ]]>
                </title>
                <description>
                    <![CDATA[ By Berk Kaan Kuguoglu It’s far from a secret that Tesseract is not an all-in-one OCR tool that recognizes all sort of texts and drawings. In fact, this couldn’t be further from the truth. If this was a secret, I’ve already spoiled it and it’s already... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/getting-started-with-tesseract-part-i-2a6a6b1cf75e/</link>
                <guid isPermaLink="false">66c34b604f7405e6476b01c7</guid>
                
                    <category>
                        <![CDATA[ OCR  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ opencv ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tesseract ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Tutorial ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 05 Jun 2018 18:42:00 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*pv8wGtNSz5Xe5OCrOIJxyw.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Berk Kaan Kuguoglu</p>
<p>It’s far from a secret that Tesseract is not an all-in-one OCR tool that recognizes all sort of texts and drawings. In fact, this couldn’t be further from the truth. If this was a secret, I’ve already spoiled it and it’s already too late to go back anyway. So, why not dive deep into Tesseract and share few tips and tricks that could improve your results?</p>
<h3 id="heading-i-love-free-stuff">I love free stuff!</h3>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
