// 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; } #serializeJSON({ "OK": false, "ERROR": "no_file", "MESSAGE": "No file was uploaded" })# #serializeJSON({ "OK": false, "ERROR": "invalid_type", "MESSAGE": "Only image files are accepted (jpg, jpeg, gif, png, webp, heic). Got: #actualExt#" })# 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) {} } } } 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); imageWrite(thumb, "#itemsDir#/#itemId#_thumb.jpg", 0.85); // Create medium size (400px max for detail view) medium = imageCopy(img, 0, 0, imageGetWidth(img), imageGetHeight(img)); medium = resizeToFit(medium, 400); imageWrite(medium, "#itemsDir#/#itemId#_medium.jpg", 0.85); // Save full size (max 1200px to keep file sizes reasonable) img = resizeToFit(img, 1200); imageWrite(img, "#itemsDir#/#itemId#.jpg", 0.90); // Delete the original uploaded file try { fileDelete(uploadedFile); } catch (any e) {} // Add cache buster cacheBuster = dateFormat(now(), "yyyymmdd") & timeFormat(now(), "HHmmss"); #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#" })# #serializeJSON({ "OK": false, "ERROR": "server_error", "MESSAGE": cfcatch.message, "DETAIL": cfcatch.detail })#