Commit a5826509 authored by jan.koester's avatar jan.koester
Browse files

test

parent c433d76b
Loading
Loading
Loading
Loading
+3 −19
Original line number Diff line number Diff line
@@ -486,27 +486,11 @@ extern "C" {
                img.setAttribute("alt", alt.c_str());
                img.setAttribute("class", responsiveClass.c_str());

                // Set intrinsic width/height attributes for CLS prevention (aspect-ratio hint)
                if (realWidth > 0 && realHeight > 0) {
                // Set intrinsic width/height attributes for CLS prevention
                if (realWidth > 0)
                    img.setAttribute("width", std::to_string(realWidth).c_str());
                if (realHeight > 0)
                    img.setAttribute("height", std::to_string(realHeight).c_str());
                } else {
                    // Fallback: set width/height from CSS values if they are pixel values
                    auto extractPx = [](const std::string &val) -> int {
                        if (val.empty() || val == "auto") return 0;
                        std::string v = val;
                        if (v.size() > 2 && v.substr(v.size()-2) == "px")
                            v = v.substr(0, v.size()-2);
                        else if (v.find('%') != std::string::npos || v.find("em") != std::string::npos
                                 || v.find("vw") != std::string::npos || v.find("vh") != std::string::npos)
                            return 0;
                        try { return static_cast<int>(std::stod(v) + 0.5); } catch(...) { return 0; }
                    };
                    int pw = extractPx(width);
                    int ph = extractPx(height);
                    if (pw > 0) img.setAttribute("width", std::to_string(pw).c_str());
                    if (ph > 0) img.setAttribute("height", std::to_string(ph).c_str());
                }

                // Compute effective width/height, auto-calculating from aspect ratio
                std::string effWidth = width;
+88 −8
Original line number Diff line number Diff line
@@ -1412,9 +1412,9 @@ namespace blogi {
                int width = 0, height = 0;
                if(json_object_object_get_ex(request, "width", &jw)) width = json_object_get_int(jw);
                if(json_object_object_get_ex(request, "height", &jh)) height = json_object_get_int(jh);
                if(width <= 0 || height <= 0){
                if(width <= 0 && height <= 0){
                    json_object_object_add(response, "status", json_object_new_string("error"));
                    json_object_object_add(response, "message", json_object_new_string("width and height must be > 0"));
                    json_object_object_add(response, "message", json_object_new_string("width or height must be > 0"));
                    return;
                }
                try {
@@ -1428,14 +1428,29 @@ namespace blogi {
                    opts.height = height;
                    opts.fmt = ext;
                    std::string ct;
                    _mdb[tid]->get_preview(mediaId, opts, &ct);
                    _addAllowedSize(tid, width, height);
                    std::string url = Args->config->buildurl("media/getimage/") + mi.id + "." + ext
                                     + "?w=" + std::to_string(width) + "&h=" + std::to_string(height);
                    auto previewData = _mdb[tid]->get_preview(mediaId, opts, &ct);

                    // Parse actual dimensions from preview image header
                    int actualW = width, actualH = height;
                    if((width <= 0 || height <= 0) && previewData.size() > 30){
                        _parseImageDimensions(previewData, ct, actualW, actualH);
                    }
                    if(actualW <= 0) actualW = width;
                    if(actualH <= 0) actualH = height;

                    if(actualW > 0 && actualH > 0)
                        _addAllowedSize(tid, actualW, actualH);
                    std::string url = Args->config->buildurl("media/getimage/") + mi.id + "." + ext;
                    if(actualW > 0 || actualH > 0){
                        url += "?";
                        if(actualW > 0) url += "w=" + std::to_string(actualW);
                        if(actualW > 0 && actualH > 0) url += "&";
                        if(actualH > 0) url += "h=" + std::to_string(actualH);
                    }
                    json_object_object_add(response, "status", json_object_new_string("success"));
                    json_object_object_add(response, "url", json_object_new_string(url.c_str()));
                    json_object_object_add(response, "width", json_object_new_int(width));
                    json_object_object_add(response, "height", json_object_new_int(height));
                    json_object_object_add(response, "width", json_object_new_int(actualW));
                    json_object_object_add(response, "height", json_object_new_int(actualH));
                } catch(std::exception &e) {
                    json_object_object_add(response, "status", json_object_new_string("error"));
                    json_object_object_add(response, "message", json_object_new_string(e.what()));
@@ -1777,6 +1792,71 @@ namespace blogi {
            return std::make_unique<libhttppp::HttpClient>(*_mdbHttpUrl, true);
        }

        // ---- image dimension parsing ----

        static void _parseImageDimensions(const std::vector<std::uint8_t> &data,
                                          const std::string &contentType,
                                          int &outW, int &outH) {
            if(data.size() < 30) return;
            const uint8_t *d = data.data();

            // WebP
            if(data.size() > 30 && d[0]=='R' && d[1]=='I' && d[2]=='F' && d[3]=='F'
               && d[8]=='W' && d[9]=='E' && d[10]=='B' && d[11]=='P'){
                // VP8X (extended)
                if(d[12]=='V' && d[13]=='P' && d[14]=='8' && d[15]=='X' && data.size() > 29){
                    outW = 1 + (d[24] | (d[25] << 8) | (d[26] << 16));
                    outH = 1 + (d[27] | (d[28] << 8) | (d[29] << 16));
                    return;
                }
                // VP8 (lossy)
                if(d[12]=='V' && d[13]=='P' && d[14]=='8' && d[15]==' ' && data.size() > 29){
                    // frame tag at offset 20, key frame signature at 23
                    if(d[23]==0x9D && d[24]==0x01 && d[25]==0x2A){
                        outW = (d[26] | (d[27] << 8)) & 0x3FFF;
                        outH = (d[28] | (d[29] << 8)) & 0x3FFF;
                        return;
                    }
                }
                // VP8L (lossless)
                if(d[12]=='V' && d[13]=='P' && d[14]=='8' && d[15]=='L' && data.size() > 24){
                    if(d[20] == 0x2F){
                        uint32_t bits = d[21] | (d[22] << 8) | (d[23] << 16) | (d[24] << 24);
                        outW = (bits & 0x3FFF) + 1;
                        outH = ((bits >> 14) & 0x3FFF) + 1;
                        return;
                    }
                }
                return;
            }

            // PNG
            if(data.size() > 24 && d[0]==0x89 && d[1]=='P' && d[2]=='N' && d[3]=='G'){
                outW = (d[16] << 24) | (d[17] << 16) | (d[18] << 8) | d[19];
                outH = (d[20] << 24) | (d[21] << 16) | (d[22] << 8) | d[23];
                return;
            }

            // JPEG
            if(data.size() > 4 && d[0]==0xFF && d[1]==0xD8){
                size_t pos = 2;
                while(pos + 4 < data.size()){
                    if(d[pos] != 0xFF) break;
                    uint8_t marker = d[pos+1];
                    if(marker == 0xC0 || marker == 0xC2){ // SOF0 or SOF2
                        if(pos + 9 < data.size()){
                            outH = (d[pos+5] << 8) | d[pos+6];
                            outW = (d[pos+7] << 8) | d[pos+8];
                        }
                        return;
                    }
                    uint16_t segLen = (d[pos+2] << 8) | d[pos+3];
                    pos += 2 + segLen;
                }
                return;
            }
        }

        // ---- member state ----

        std::string _mdbUrl;