<%@ Page Title="EXIF Orientation" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" %>
<%@ Register Assembly="AjaxUploader" Namespace="AjaxUploader.Controls" TagPrefix="au" %> 
<asp:Content ID="TitleContent" ContentPlaceHolderID="TitleContent" runat="server">EXIF Orientation - AjaxUploader v5.2 Demos</asp:Content>
<asp:Content ID="HeaderContent" ContentPlaceHolderID="HeaderTitle" runat="server">EXIF Orientation</asp:Content> 
<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server"> 
<div class="demo-card"> <div class="demo-card-header">EXIF Auto-Rotation Awareness</div> <div class="demo-card-body"> <p class="demo-description"> Photos from cameras and phones often contain EXIF orientation metadata. This demo
 detects the EXIF orientation tag and displays both the raw image and the correctly
 oriented version using canvas transforms.
 </p> <div class="demo-expect"><strong>What you should see:</strong> sideways phone photos (JPEG) are straightened automatically from their EXIF orientation before upload. Auto-upload is off so you can compare before sending.</div> <au:AjaxFileUpload ID="Uploader1" runat="server"
 EnableExifOrient="true"
 AllowedExtensions=".jpg,.jpeg"
 AutoUpload="false" /> <div id="exifResult" class="mt-3" role="status" aria-live="polite" style="display:none;"> <div class="row"> <div class="col-md-6 text-center"> <h6>Raw (No Correction)</h6> <img id="rawPreview" alt="Selected image before orientation correction" style="max-width:100%;max-height:200px;border:1px solid #dee2e6;border-radius:4px;"> </div> <div class="col-md-6 text-center"> <h6>Corrected Orientation</h6> <canvas id="correctedCanvas" role="img" aria-label="Corrected image orientation preview" style="max-width:100%;max-height:200px;border:1px solid #dee2e6;border-radius:4px;"></canvas> </div> </div> <div class="mt-2 p-2 bg-light border rounded small"> <strong>EXIF Data:</strong> <span id="exifInfo">Reading...</span> </div> </div> <div class="code-panel"> <pre><code>&lt;au:AjaxFileUpload ID="Uploader1" runat="server"
 EnableExifOrient="true"
 AllowedExtensions=".jpg,.jpeg"
 AutoUpload="false" /&gt;

// JavaScript: Read EXIF orientation from binary data
function getExifOrientation(file, callback) {
 var reader = new FileReader();
 reader.onload = function(e) {
 var view = new DataView(e.target.result);
 // Parse JPEG markers to find EXIF orientation tag (0x0112)
 // Returns orientation value 1-8
 };
 reader.readAsArrayBuffer(file.slice(0, 65536));
}

// Apply orientation transform to canvas context
function applyOrientation(ctx, orientation, w, h) {
 switch (orientation) {
 case 3: ctx.rotate(Math.PI); ctx.translate(-w, -h); break;
 case 6: ctx.rotate(Math.PI / 2); ctx.translate(0, -h); break;
 case 8: ctx.rotate(-Math.PI / 2); ctx.translate(-w, 0); break;
 }
}</code></pre> </div> </div>
</div> 
</asp:Content> 
<asp:Content ID="ScriptsContent" ContentPlaceHolderID="ScriptsContent" runat="server">
<script> var exifResult = document.getElementById('exifResult');
 var rawPreview = document.getElementById('rawPreview');
 var correctedCanvas = document.getElementById('correctedCanvas');
 var exifInfo = document.getElementById('exifInfo');
 var orientationLabels = {
 1: 'Normal', 2: 'Flipped Horizontal', 3: 'Rotated 180',
 4: 'Flipped Vertical', 5: 'Transposed', 6: 'Rotated 90 CW',
 7: 'Transversed', 8: 'Rotated 90 CCW'
 };

 var uploader = window.AjaxUploader && AjaxUploader.getInstance ? AjaxUploader.getInstance('Uploader1') : null;
 if (uploader) {
 uploader.on('select', function(files) {
 var first = files && files[0];
 var file = first && (first.file || first);
 if (!file) return false;
 if (!rawPreview || !correctedCanvas || !exifResult || !exifInfo) return false;
 var rawUrl = URL.createObjectURL(file);
 rawPreview.onload = function() { URL.revokeObjectURL(rawUrl); };
 rawPreview.onerror = function() { URL.revokeObjectURL(rawUrl); };
 rawPreview.src = rawUrl;
 exifResult.style.display = 'block';
 getExifOrientation(file, function(orientation) {
 exifInfo.textContent = 'Orientation: ' + orientation +
 ' (' + (orientationLabels[orientation] || 'Unknown') + ')';
 var img = new Image();
 var correctedUrl = URL.createObjectURL(file);
 img.onload = function() {
 URL.revokeObjectURL(correctedUrl);
 var swap = orientation >= 5;
 correctedCanvas.width = swap ? img.height : img.width;
 correctedCanvas.height = swap ? img.width : img.height;
 var ctx = correctedCanvas.getContext('2d');
 applyOrientation(ctx, orientation, img.width, img.height);
 ctx.drawImage(img, 0, 0);
 };
 img.onerror = function() { URL.revokeObjectURL(correctedUrl); };
 img.src = correctedUrl;
 });
 return false;
 });
 }

 function getExifOrientation(file, callback) {
 var reader = new FileReader();
 reader.onload = function(e) {
 var view = new DataView(e.target.result);
 if (view.getUint16(0) !== 0xFFD8) return callback(1);
 var offset = 2;
 while (offset < view.byteLength) {
 if (offset + 4 > view.byteLength) break;
 var marker = view.getUint16(offset);
 if (marker === 0xFFE1) {
 var exifOffset = offset + 10;
 if (exifOffset + 10 > view.byteLength) return callback(1);
 var little = view.getUint16(exifOffset) === 0x4949;
 var tags = view.getUint16(exifOffset + 8, little);
 for (var i = 0; i < tags; i++) {
 var tagOffset = exifOffset + 10 + i * 12;
 if (tagOffset + 12 > view.byteLength) break;
 if (view.getUint16(tagOffset, little) === 0x0112) {
 return callback(view.getUint16(tagOffset + 8, little));
 }
 }
 return callback(1);
 }
 if (offset + 2 + 2 > view.byteLength) break;
 offset += 2 + view.getUint16(offset + 2);
 }
 callback(1);
 };
 reader.onerror = function() { callback(1); };
 reader.readAsArrayBuffer(file.slice(0, 65536));
 }

 function applyOrientation(ctx, orientation, w, h) {
 switch (orientation) {
 case 2: ctx.scale(-1, 1); ctx.translate(-w, 0); break;
 case 3: ctx.rotate(Math.PI); ctx.translate(-w, -h); break;
 case 4: ctx.scale(1, -1); ctx.translate(0, -h); break;
 case 5: ctx.rotate(Math.PI / 2); ctx.scale(1, -1); break;
 case 6: ctx.rotate(Math.PI / 2); ctx.translate(0, -h); break;
 case 7: ctx.rotate(-Math.PI / 2); ctx.scale(1, -1); ctx.translate(-w, 0); break;
 case 8: ctx.rotate(-Math.PI / 2); ctx.translate(-w, 0); break;
 }
 }
</script>
</asp:Content>
