| Server IP : 127.0.0.1 / Your IP : 216.73.216.48 Web Server : Apache/2.4.58 (Win64) OpenSSL/3.1.3 PHP/8.2.12 System : Windows NT DESKTOP-3H4FHQJ 10.0 build 19045 (Windows 10) AMD64 User : win 10 ( 0) PHP Version : 8.2.12 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : OFF | Perl : OFF | Python : OFF | Sudo : OFF | Pkexec : OFF Directory : D:/xampp/htdocs-coblaa/CB_pdf_converter/ |
Upload File : |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CB Photo, Txt to PDF Converter</title>
<link rel="icon" type="image/png" href="http://localhost/CB_pdf_converter//main_icon/craneblue.png" />
<!-- Load Tailwind CSS from CDN -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Load React from CDN -->
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<!-- Load Babel for JSX support in the browser -->
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<!-- Load jsPDF from CDN -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
<link rel="stylesheet" type="text/css" href="main_css/index.css?v1" />
<meta name="google-adsense-account" content="ca-pub-4728417548940171"><!--gog ads -->
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4728417548940171"crossorigin="anonymous"></script><!-- ad unit --></head>
<style>
/* Custom styles for the spinner animation */
.spinner {
border: 4px solid rgba(0, 0, 0, 0.1);
border-left-color: #ffffff;
border-radius: 50%;
width: 20px;
height: 20px;
animation: spin 1s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
/* Styles for the PDF preview modal */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.75);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.modal-content {
background: white;
padding: 1rem;
border-radius: 1rem;
width: 90%;
max-width: 800px;
height: 90%;
display: flex;
flex-direction: column;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
}
.modal-header h2 {
font-weight: bold;
font-size: 1.25rem;
}
.modal-body {
flex-grow: 1;
overflow: hidden;
}
.modal-body iframe {
width: 100%;
height: 100%;
border-radius: 0.5rem;
border: 1px solid #e5e7eb;
}
</style>
</head>
<body class="bg-gray-100 font-sans antialiased">
<div class="main_home_div" >
<!--img src="main_icon/back_btn.png" Onclick="history.back();" class="back_btn" />
<h1 class="main_home_title">CB Photo to PDF Converter</h1>
<img src="main_icon/down_arrow.png" onClick="show_more_option();" class="down_arrow_btn" /-->
<a href=""><img src="main_icon/craneblue.png" id="main_log_home" alt="craneblue log" class="main_log_home" /></a>
<h1 id="hi_title" class="hi_title">CB Converter</h1>
<img src="main_icon/arrowDown.png" onClick="show_shell_home_btn();" alt="craneblue Dbtn" class="main_log_home_right" />
</div>
<div class="main_home_div_position" ></div>
<div id="shell_welcome_div" class="shell_home_btn" >
<div class="sub_home_btn" >
<a href=""><button class="home_btn">Home</button></a>
<a href="https://coblaa.com"><button class="home_btn" >CB Apps</button></a>
<a href="img_pdf_blog"><button class="home_btn" >Blog</button></a>
<button class="home_btn" >Contacts</button>
<button class="home_btn" > Policy</button>
<button onClick="close_shell_home_btn();" class="home_btn" > Close</button>
</div>
<div onClick="close_shell_home_btn();" class="shell_home_btn2" ></div>
</div>
<div id="root"></div>
<script type="text/babel">
function show_shell_home_btn()
{
document.getElementById('shell_welcome_div').style.display="block";
}
function close_shell_home_btn()
{
document.getElementById('shell_welcome_div').style.display="none";
}
const { useState, useRef } = React;
// React functional component for the Photo to PDF Converter application
const App = () => {
const [images, setImages] = useState([]);
const [isConverting, setIsConverting] = useState(false);
const [pdfUrl, setPdfUrl] = useState('');
const [error, setError] = useState('');
const [isPreviewOpen, setIsPreviewOpen] = useState(false);
const fileInputRef = useRef(null);
const cameraInputRef = useRef(null);
const pdfInputRef = useRef(null);
const textInputRef = useRef(null);
// Helper function to convert a File object to a Base64 data URI string
const fileToBase64 = (file) => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
reader.readAsDataURL(file);
});
};
// Corrects the image orientation using an off-screen canvas to respect EXIF data
const correctImageOrientation = (base64String) => {
return new Promise((resolve) => {
const img = new Image();
img.onload = () => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = img.width;
canvas.height = img.height;
// The browser's image object automatically respects EXIF orientation.
// Drawing it to a new canvas bakes this correction into a new image.
ctx.drawImage(img, 0, 0);
resolve(canvas.toDataURL('image/jpeg', 1.0));
};
img.src = base64String;
});
};
// Handle file selection from the file input
const handleFileChange = async (e) => {
setError('');
setPdfUrl('');
const files = Array.from(e.target.files);
if (files.length === 0) {
return;
}
const imageFiles = files.filter(file => file.type.startsWith('image/'));
if (imageFiles.length === 0) {
setError('Please select one or more image files.');
return;
}
const newImages = await Promise.all(imageFiles.map(async (file) => {
const base64Data = await fileToBase64(file);
const correctedBase64 = await correctImageOrientation(base64Data); // Correct orientation before use
return {
file,
url: correctedBase64, // Use the corrected Base64 data for display and PDF
id: file.name + '-' + Date.now()
};
}));
setImages(prevImages => [...prevImages, ...newImages]);
};
// Handle PDF file selection from the file input
const handlePdfFileChange = (e) => {
setError('');
setImages([]); // Clear images as we are now viewing a standalone PDF
const file = e.target.files[0];
if (file && file.type === 'application/pdf') {
const url = URL.createObjectURL(file);
setPdfUrl(url);
setIsPreviewOpen(true); // Automatically open the modal
} else if (file) {
setError('Please select a valid PDF file.');
}
};
// Handle text file selection and convert to PDF
const handleTextFileChange = (e) => {
setError('');
setImages([]); // Clear images
setPdfUrl('');
const file = e.target.files[0];
if (file && file.type === 'text/plain') {
const reader = new FileReader();
reader.onload = (event) => {
const textContent = event.target.result;
convertTextToPdf(textContent);
};
reader.onerror = () => {
setError('Failed to read the text file.');
};
reader.readAsText(file);
} else if (file) {
setError('Please select a valid .txt file.');
}
};
// Convert text content to a PDF
const convertTextToPdf = (text) => {
setIsConverting(true);
try {
const doc = new jspdf.jsPDF();
const pageWidth = doc.internal.pageSize.getWidth();
const margin = 10;
const textWidth = pageWidth - 2 * margin;
const splitText = doc.splitTextToSize(text, textWidth);
let y = margin + 5;
const lineHeight = 7;
doc.setFontSize(12);
splitText.forEach((line) => {
if (y + lineHeight > doc.internal.pageSize.getHeight() - margin) {
doc.addPage();
y = margin + 5;
}
doc.text(line, margin, y);
y += lineHeight;
});
const pdfBlob = doc.output('blob');
const url = URL.createObjectURL(pdfBlob);
setPdfUrl(url);
setIsPreviewOpen(true);
} catch (e) {
console.error(e);
setError('An error occurred while converting the text to PDF.');
} finally {
setIsConverting(false);
}
};
// Remove an image from the preview list
const handleRemoveImage = (id) => {
setImages(prevImages => {
const updatedImages = prevImages.filter(image => image.id !== id);
if (updatedImages.length === 0) {
setPdfUrl('');
}
return updatedImages;
});
};
// Convert the uploaded images to a single PDF document
const convertToPdf = async () => {
if (images.length === 0 || isConverting) {
return;
}
setIsConverting(true);
setError('');
setPdfUrl('');
try {
const doc = new jspdf.jsPDF('p', 'mm', 'a4');
const pageHeight = doc.internal.pageSize.getHeight();
const pageWidth = doc.internal.pageSize.getWidth();
for (let i = 0; i < images.length; i++) {
const image = images[i];
const img = new Image();
img.src = image.url;
await new Promise((resolve, reject) => {
img.onload = () => resolve();
img.onerror = () => {
console.error(`Failed to load image: ${image.id}`);
reject(new Error(`Failed to load image: ${image.id}`));
};
});
if (img.src) {
const imageData = image.url;
const imgWidth = img.width;
const imgHeight = img.height;
if (i > 0) {
doc.addPage();
}
// Calculate the ratio and position to fit the image on the A4 page
const ratio = Math.min(pageWidth / imgWidth, pageHeight / imgHeight);
const finalWidth = imgWidth * ratio;
const finalHeight = imgHeight * ratio;
const x = (pageWidth - finalWidth) / 2;
const y = (pageHeight - finalHeight) / 2;
// Add the image data to the PDF. The orientation is already corrected.
doc.addImage(imageData, 'JPEG', x, y, finalWidth, finalHeight);
}
}
const pdfBlob = doc.output('blob');
const url = URL.createObjectURL(pdfBlob);
setPdfUrl(url);
} catch (e) {
console.error(e);
setError('An error occurred while creating the PDF. Please try again.');
} finally {
setIsConverting(false);
}
};
// Open the PDF preview modal
const openPreview = () => {
if (pdfUrl) {
setIsPreviewOpen(true);
}
};
// Close the PDF preview modal
const closePreview = () => {
setIsPreviewOpen(false);
};
return (
<div className="min-h-screen bg-gray-100 flex items-center justify-center p-4 sm:p-6 lg:p-8">
<div className="w-full max-w-4xl bg-white rounded-xl shadow-lg p-6 sm:p-8 lg:p-10">
<h1 className="text-3xl sm:text-4xl font-bold text-center text-gray-900 mb-2">
Photo to PDF Converter
</h1>
<p className="text-center text-gray-600 mb-6 sm:mb-8">
Upload photos, take a picture with your camera, view a PDF from your device, or convert a simple text file to a PDF.
</p>
{/* File input and upload/camera buttons */}
<div className="flex flex-col sm:flex-row items-center justify-center gap-4 mb-8">
<input
type="file"
multiple
accept="image/*"
ref={fileInputRef}
onChange={handleFileChange}
className="hidden"
/>
<input
type="file"
accept="image/*"
capture="camera"
ref={cameraInputRef}
onChange={handleFileChange}
className="hidden"
/>
<input
type="file"
accept="application/pdf"
ref={pdfInputRef}
onChange={handlePdfFileChange}
className="hidden"
/>
<input
type="file"
accept=".txt"
ref={textInputRef}
onChange={handleTextFileChange}
className="hidden"
/>
<button
onClick={() => fileInputRef.current.click()}
className="w-full sm:w-auto px-6 py-3 bg-blue-600 text-white font-semibold rounded-lg shadow-md hover:bg-blue-700 transition duration-300 ease-in-out flex items-center justify-center gap-2"
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="w-6 h-6">
<path fillRule="evenodd" d="M11.47 2.47a.75.75 0 0 1 1.06 0l4.5 4.5a.75.75 0 0 1-1.06 1.06L12 4.81v9.84a.75.75 0 0 1-1.5 0V4.81L7.03 8.03a.75.75 0 0 1-1.06-1.06l4.5-4.5ZM3 15.75a.75.75 0 0 1 .75.75v2.25a1.5 1.5 0 0 0 1.5 1.5h13.5a1.5 1.5 0 0 0 1.5-1.5V16.5a.75.75 0 0 1 1.5 0v2.25a3 3 0 0 1-3 3H5.25a3 3 0 0 1-3-3V16.5a.75.75 0 0 1 .75-.75Z" clipRule="evenodd" />
</svg>
Upload Photos
</button>
<button
onClick={() => cameraInputRef.current.click()}
className="w-full sm:w-auto px-6 py-3 bg-sky-600 text-white font-semibold rounded-lg shadow-md hover:bg-sky-700 transition duration-300 ease-in-out flex items-center justify-center gap-2"
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="w-6 h-6">
<path d="M14.5 4.75a.75.75 0 0 0-1.5 0V6.5h-4.5V4.75a.75.75 0 0 0-1.5 0V6.5h-1a2.25 2.25 0 0 0-2.25 2.25v9a2.25 2.25 0 0 0 2.25 2.25h11.5A2.25 2.25 0 0 0 20 17.75v-9a2.25 2.25 0 0 0-2.25-2.25h-1V4.75Z" />
<path fillRule="evenodd" d="M3.75 9a2.25 2.25 0 0 1 2.25-2.25h1.5a.75.75 0 0 0 0-1.5h-1.5A3.75 3.75 0 0 0 2.25 9v9A3.75 3.75 0 0 0 6 21.75h12a3.75 3.75 0 0 0 3.75-3.75V9A3.75 3.75 0 0 0 18 5.25h-1.5a.75.75 0 0 0 0 1.5h1.5a2.25 2.25 0 0 1 2.25 2.25v9a2.25 2.25 0 0 1-2.25 2.25H6a2.25 2.25 0 0 1-2.25-2.25V9Z" clipRule="evenodd" />
</svg>
Scan with Camera
</button>
<button
onClick={() => pdfInputRef.current.click()}
className="w-full sm:w-auto px-6 py-3 bg-rose-600 text-white font-semibold rounded-lg shadow-md hover:bg-rose-700 transition duration-300 ease-in-out flex items-center justify-center gap-2"
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="w-6 h-6">
<path fillRule="evenodd" d="M.051 3.51a.75.75 0 0 1 .53-.518C2.56 2.52 4.183 2.25 6 2.25c1.817 0 3.44.27 5.419.742a.75.75 0 0 1 .582.733v9.424c0 .354-.4.544-.683.393-1.393-.72-2.99-1.125-4.737-1.125-1.747 0-3.344.405-4.737 1.125-.283.15-.683-.04-.683-.394V3.51ZM14.25 3.51a.75.75 0 0 1 .53-.518C16.56 2.52 18.183 2.25 20 2.25c1.817 0 3.44.27 5.419.742a.75.75 0 0 1 .582.733v9.424c0 .354-.4.544-.683.393-1.393-.72-2.99-1.125-4.737-1.125-1.747 0-3.344.405-4.737 1.125-.283.15-.683-.04-.683-.394V3.51Z" clipRule="evenodd" />
</svg>
View PDF from Device
</button>
<button
onClick={() => textInputRef.current.click()}
className="w-full sm:w-auto px-6 py-3 bg-fuchsia-600 text-white font-semibold rounded-lg shadow-md hover:bg-fuchsia-700 transition duration-300 ease-in-out flex items-center justify-center gap-2"
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="w-6 h-6">
<path d="M11.828 2.25c-.954 0-1.837.587-2.228 1.48L7.5 7.5h-1.5A2.25 2.25 0 0 0 3.75 9.75v9.5c0 1.241 1.009 2.25 2.25 2.25h11.5a2.25 2.25 0 0 0 2.25-2.25v-9.5c0-1.241-1.009-2.25-2.25-2.25H15.5l-2.09-3.77a2.25 2.25 0 0 0-2.227-1.48ZM12 9.75a.75.75 0 0 1 .75.75v4.5a.75.75 0 0 1-1.5 0V10.5a.75.75 0 0 1 .75-.75Z" />
</svg>
Convert Text to PDF
</button>
</div>
{/* Error message display */}
{error && (
<div className="bg-red-100 text-red-700 p-4 rounded-lg mb-6 text-center">
{error}
</div>
)}
{/* Image previews and conversion status */}
{images.length > 0 && (
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-4 mb-8">
{images.map(image => (
<div key={image.id} className="relative group w-full aspect-square rounded-lg overflow-hidden shadow-md">
<img
src={image.url}
alt="Uploaded photo preview"
className="w-full h-full object-cover transition-transform duration-300 group-hover:scale-105"
/>
<button
onClick={() => handleRemoveImage(image.id)}
className="absolute top-2 right-2 bg-red-500 text-white p-1 rounded-full opacity-0 group-hover:opacity-100 transition-opacity duration-300"
aria-label="Remove image"
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="w-4 h-4">
<path fillRule="evenodd" d="M12 2.25c-5.385 0-9.75 4.365-9.75 9.75s4.365 9.75 9.75 9.75 9.75-4.365 9.75-9.75S17.385 2.25 12 2.25Zm-1.72 6.97a.75.75 0 1 0-1.06 1.06L10.94 12l-1.72 1.72a.75.75 0 1 0 1.06 1.06L12 13.06l1.72 1.72a.75.75 0 1 0 1.06-1.06L13.06 12l1.72-1.72a.75.75 0 1 0-1.06-1.06L12 10.94l-1.72-1.72Z" clipRule="evenodd" />
</svg>
</button>
</div>
))}
</div>
)}
{/* Convert, Preview, and Download buttons */}
<div className="flex flex-col sm:flex-row items-center justify-center gap-4">
<button
onClick={convertToPdf}
disabled={images.length === 0 || isConverting}
className={`w-full sm:w-auto px-6 py-3 font-semibold rounded-lg shadow-md transition duration-300 ease-in-out flex items-center justify-center gap-2
${images.length === 0 || isConverting
? 'bg-gray-400 text-gray-700 cursor-not-allowed'
: 'bg-green-600 text-white hover:bg-green-700'
}`}
>
{isConverting ? (
<>
<div className="spinner"></div>
Converting...
</>
) : (
<>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="w-6 h-6">
<path d="M11.828 2.25c-.954 0-1.837.587-2.228 1.48L7.5 7.5h-1.5A2.25 2.25 0 0 0 3.75 9.75v9.5c0 1.241 1.009 2.25 2.25 2.25h11.5a2.25 2.25 0 0 0 2.25-2.25v-9.5c0-1.241-1.009-2.25-2.25-2.25H15.5l-2.09-3.77a2.25 2.25 0 0 0-2.227-1.48ZM12 9.75a.75.75 0 0 1 .75.75v4.5a.75.75 0 0 1-1.5 0V10.5a.75.75 0 0 1 .75-.75Z" />
</svg>
Convert to PDF
</>
)}
</button>
{pdfUrl && (
<>
<button
onClick={openPreview}
className="w-full sm:w-auto px-6 py-3 bg-sky-600 text-white font-semibold rounded-lg shadow-md hover:bg-sky-700 transition duration-300 ease-in-out flex items-center justify-center gap-2"
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="w-6 h-6">
<path d="M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z" />
<path fillRule="evenodd" d="M1.323 11.447C2.822 6.531 7.027 3.25 12 3.25s9.178 3.281 10.677 8.197a.75.75 0 0 1 0 .606C21.178 17.219 16.973 20.5 12 20.5s-9.178-3.281-10.677-8.197a.75.75 0 0 1 0-.606ZM12 18.5a6.5 6.5 0 1 0 0-13 6.5 6.5 0 0 0 0 13Z" clipRule="evenodd" />
</svg>
Preview PDF
</button>
<a
href={pdfUrl}
download="photos-to-pdf.pdf"
className="w-full sm:w-auto px-6 py-3 bg-indigo-600 text-white font-semibold rounded-lg shadow-md hover:bg-indigo-700 transition duration-300 ease-in-out flex items-center justify-center gap-2"
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="w-6 h-6">
<path fillRule="evenodd" d="M12 2.25a.75.75 0 0 1 .75.75v11.69l3.22-3.22a.75.75 0 1 1 1.06 1.06l-4.5 4.5a.75.75 0 0 1-1.06 0l-4.5-4.5a.75.75 0 1 1 1.06-1.06l3.22 3.22V3a.75.75 0 0 1 .75-.75ZM9 19.5a.75.75 0 0 1 .75-.75h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1-.75-.75Z" clipRule="evenodd" />
</svg>
Download PDF
</a>
</>
)}
</div>
</div>
{/* PDF Preview Modal */}
{isPreviewOpen && (
<div className="modal-overlay">
<div className="modal-content">
<div className="modal-header">
<h2>PDF Preview</h2>
<button onClick={closePreview} className="text-gray-500 hover:text-gray-700">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="w-6 h-6">
<path fillRule="evenodd" d="M5.47 5.47a.75.75 0 0 1 1.06 0L12 10.94l5.47-5.47a.75.75 0 1 1 1.06 1.06L13.06 12l5.47 5.47a.75.75 0 1 1-1.06 1.06L12 13.06l-5.47 5.47a.75.75 0 0 1-1.06-1.06L10.94 12 5.47 6.53a.75.75 0 0 1 0-1.06Z" clipRule="evenodd" />
</svg>
</button>
</div>
<div className="modal-body">
<iframe src={pdfUrl} title="PDF Preview"></iframe>
</div>
</div>
</div>
)}
</div>
);
};
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
</script>
<!-- Footer -->
<footer class="bg-gray-800 text-white mt-auto py-8">
<div class="container mx-auto px-4 sm:px-6 lg:px-8 text-center text-gray-400">
<p class="mb-2">© <?php echo $curr_year = date("Y"); ?> CB Photo to PDF Converter. All rights reserved.</p>
<p class="text-sm">
<a href="#" class="hover:text-white transition duration-300">Privacy Policy</a>
<span class="mx-2">|</span>
<a href="#" class="hover:text-white transition duration-300">Terms of Service</a>
</p>
</div>
</footer>
</body>
</html>