This repository has been archived on 2026-03-21. You can view files and clone it, but cannot push or open issues or pull requests.
payfrit-biz/api/menu/uploadItemPhoto.cfm

164 lines
5.1 KiB
Text

<cfsetting showdebugoutput="false">
<cfsetting enablecfoutputonly="true">
<cfcontent type="application/json; charset=utf-8" reset="true">
<cfheader name="Cache-Control" value="no-store">
<cftry>
<cfset itemsDir = expandPath("/uploads/items")>
<cfscript>
// Get ItemID from form
itemId = 0;
if (structKeyExists(form, "ItemID") && isNumeric(form.ItemID) && form.ItemID GT 0) {
itemId = int(form.ItemID);
}
if (itemId LTE 0) {
apiAbort({ "OK": false, "ERROR": "missing_itemid", "MESSAGE": "ItemID is required" });
}
// Fix EXIF orientation - rotate image based on EXIF Orientation tag
function fixOrientation(img) {
try {
exif = imageGetEXIFMetadata(img);
if (structKeyExists(exif, "Orientation")) {
orientation = val(exif.Orientation);
switch(orientation) {
case 3: imageRotate(img, 180); break;
case 6: imageRotate(img, 90); break;
case 8: imageRotate(img, 270); break;
// 2,4,5,7 involve flips which are rare, skip for now
}
}
} catch (any e) {
// No EXIF or can't read it - that's fine
}
return img;
}
// Resize image maintaining aspect ratio, fitting within maxSize box
function resizeToFit(img, maxSize) {
w = imageGetWidth(img);
h = imageGetHeight(img);
if (w <= maxSize && h <= maxSize) return img;
if (w > h) {
newW = maxSize;
newH = int(h * (maxSize / w));
} else {
newH = maxSize;
newW = int(w * (maxSize / h));
}
imageResize(img, newW, newH, "highQuality");
return img;
}
// Create square thumbnail (center crop)
function createSquareThumb(img, size) {
thumb = imageCopy(img, 0, 0, imageGetWidth(img), imageGetHeight(img));
w = imageGetWidth(thumb);
h = imageGetHeight(thumb);
// Resize so smallest dimension equals size
if (w > h) {
imageResize(thumb, "", size, "highQuality");
} else {
imageResize(thumb, size, "", "highQuality");
}
// Center crop to square
w = imageGetWidth(thumb);
h = imageGetHeight(thumb);
if (w > h) {
x = int((w - h) / 2);
imageCrop(thumb, x, 0, h, h);
} else if (h > w) {
y = int((h - w) / 2);
imageCrop(thumb, 0, y, w, w);
}
// Final resize to exact size
imageResize(thumb, size, size, "highQuality");
return thumb;
}
</cfscript>
<!--- Check if file was uploaded --->
<cfif NOT structKeyExists(form, "photo") OR form.photo EQ "">
<cfoutput>#serializeJSON({ "OK": false, "ERROR": "no_file", "MESSAGE": "No file was uploaded" })#</cfoutput>
<cfabort>
</cfif>
<!--- Upload the file to temp location first --->
<cffile action="UPLOAD" filefield="photo" destination="#itemsDir#/" nameconflict="MAKEUNIQUE" mode="755" result="uploadResult">
<!--- Validate file type (include HEIC/HEIF for iPhone) --->
<cfset allowedExtensions = "jpg,jpeg,gif,png,webp,heic,heif">
<cfset actualExt = lCase(uploadResult.ClientFileExt)>
<cfif NOT listFindNoCase(allowedExtensions, actualExt)>
<cffile action="DELETE" file="#itemsDir#/#uploadResult.ServerFile#">
<cfoutput>#serializeJSON({ "OK": false, "ERROR": "invalid_type", "MESSAGE": "Only image files are accepted (jpg, jpeg, gif, png, webp, heic). Got: #actualExt#" })#</cfoutput>
<cfabort>
</cfif>
<!--- Delete old photos and thumbnails if they exist --->
<cfscript>
for (ext in listToArray("jpg,jpeg,gif,png,webp")) {
for (suffix in ["", "_thumb", "_medium"]) {
oldFile = "#itemsDir#/#itemId##suffix#.#ext#";
if (fileExists(oldFile)) {
try { fileDelete(oldFile); } catch (any e) {}
}
}
}
</cfscript>
<!--- Read the uploaded image and process --->
<cfscript>
uploadedFile = "#itemsDir#/#uploadResult.ServerFile#";
img = imageNew(uploadedFile);
// Fix EXIF orientation (portrait photos appearing landscape)
img = fixOrientation(img);
// Create thumbnail (64x64 square for list view - 2x for retina)
thumb = createSquareThumb(img, 128);
thumbPath = "#itemsDir#/#itemId#_thumb.jpg";
imageWrite(thumb, thumbPath, 0.85);
fileSetAccessMode(thumbPath, "644");
// Create medium size (400px max for detail view)
medium = imageCopy(img, 0, 0, imageGetWidth(img), imageGetHeight(img));
medium = resizeToFit(medium, 400);
mediumPath = "#itemsDir#/#itemId#_medium.jpg";
imageWrite(medium, mediumPath, 0.85);
fileSetAccessMode(mediumPath, "644");
// Save full size (max 1200px to keep file sizes reasonable)
img = resizeToFit(img, 1200);
fullPath = "#itemsDir#/#itemId#.jpg";
imageWrite(img, fullPath, 0.90);
fileSetAccessMode(fullPath, "644");
// Delete the original uploaded file
try { fileDelete(uploadedFile); } catch (any e) {}
// Add cache buster
cacheBuster = dateFormat(now(), "yyyymmdd") & timeFormat(now(), "HHmmss");
</cfscript>
<!--- Return success with image URLs --->
<cfoutput>#serializeJSON({
"OK": true,
"ERROR": "",
"MESSAGE": "Photo uploaded successfully",
"IMAGEURL": "/uploads/items/#itemId#.jpg?v=#cacheBuster#",
"THUMBURL": "/uploads/items/#itemId#_thumb.jpg?v=#cacheBuster#",
"MEDIUMURL": "/uploads/items/#itemId#_medium.jpg?v=#cacheBuster#"
})#</cfoutput>
<cfcatch type="any">
<cfheader statuscode="200" statustext="OK">
<cfcontent type="application/json; charset=utf-8" reset="true">
<cfoutput>#serializeJSON({ "OK": false, "ERROR": "server_error", "MESSAGE": cfcatch.message, "DETAIL": cfcatch.detail })#</cfoutput>
</cfcatch>
</cftry>