Можно ли отложенно загружать изображения с помощью cfthread Coldfusions?

Я запускаю coldfusion8/MySQL5.0.88, и у меня есть поиск товаров, для которого мне нужно загрузить и изменить размер изображений из различных внешних источников, прежде чем отображать их.

Хотя в основном я могу сделать это, когда продукты создаются (а не ищутся), я не могу гарантировать, что все изображения будут доступны в измененном формате с моего сервера, поэтому мне нужен какой-то запасной вариант внутри поиска продукта.

Прямо сейчас я проверяю, доступно ли изображение на сервере, и если нет, я запускаю процедуру для захвата и изменения размера изображения следующим образом:

// check if image is available
<cfif results.typ NEQ "img" AND results.typ NEQ "alt">
    <cfif results.bildpfad neq "" AND results.bilddateiname neq "">
    <cfset imgSuccess = form_img_handler.upload
        ( command   = "upload_search"
        , imgPath   = results.bildpfad
        , imgFile   = results.bilddateiname
        , sellerILN = results.iln
        , cookie    = variables.screenWidth
        )/>
    <cfif imgSuccess EQ "false">
        <cfset variables.imgFail = "true">
    </cfif>
 </cfelse>
     <cfset variables.imgFail = "true">
 </cfif>

// missing img
<cfif variables.imgFail EQ "true">
    <cfoutput><div class="resultsImgWrap noImgFound"></div></cfoutput> 
    <cfset variables.imgFail = "false">
<cfelse>
// show image
    <cfoutput><div class="resultsImgWrap"><img src="#variables.imageSrc#" /></div></cfoutput>
</cfif>

Функция upload обрабатывает запрос cfhttp и изменение размера и возвращает true/false.

Мне интересно, можно ли использовать cfthread в этом контексте, поэтому, когда пользователь выполняет поиск, я вывожу разметку, включая правильные URL-ссылки, но извлечение/изменение размера/сохранение изображения в место назначения будет выполнено в cfthread, в для ускорения отображения результатов для пользователя.

Вопрос:
Будут ли изображения отображаться после того, как cfthread закончит обработку, или этот подход приведет к ошибке 404 при попытке загрузить изображение, которое не было создано (вероятно)? Существуют ли какие-либо другие способы показать что-то пользователю и позволить пользователю продолжить, пока изображения загружаются и обрабатываются?

Спасибо за материалы!

EDIT:
Хорошо. На основании ответов я пришел к следующему. Пока еще не работает, я думаю, что это идет в правильном направлении.

// check media log, if image is logged (already created), if so, load it, if not pull it from external
<cfif results.typ NEQ "img" AND results.typ NEQ "alt">
    // check path and filename
    <cfif results.bildpfad neq "" AND results.bilddateiname neq "">
        // pull in
        // arguments: 
        // cm = form
        // pt = path to image
        // fl = filename
        // se = seller id  
        // ck = screen width (I'm using adaptive image sizes
        // ax = origin
        // gb = which image size to return
        <cfset variables.imgSrc = expandPath("../services/img_handler.cfc") & "?method=up&cm=results&pt=" & results.bildpfad & "&fl=" & results.bilddateiname & "&se=" & results.id & "&ck=" & variables.screenWidth & "&ax=rm&gb=s">
    <cfelse>
        cfset variables.imgFail = "true">
    </cfif>
</cfif>

<cfif variables.imgFail EQ "true">
    <cfoutput><div class="resultsImgWrap noImgFound"><img src="../images/not_found.png"></div></cfoutput>
    <cfset variables.imgFail = "false">
 <cfelse>
    <cfoutput><div class="resultsImgWrap"><a class="swipeMe" rel="external" href="#variables.zoomSrc#">
                <img src="#variables.imageSrc#" class="adaptImg ui-li-thumb" /></a>
              </div></cfoutput>
</cfif>

Таким образом, это проверит изображение в моем медиа-журнале, которое я запрашиваю, вместе с результатами (избегайте ненужной проверки s3 для существующего изображения). Если в журнале нет изображения, я проверяю, не является ли путь/имя файла пустым, и запускаю загрузчик изображений intelligent, который делает следующее:

<cfcomponent output="false" hint="image handler">
    <cffunction name="Init" access="public" returntype="any" output="false" hint="Initialize">
        <cfreturn true />
    </cffunction>       

    <cffunction name="upload" access="remote" output="false" hint="creates images and stores them to S3">
        <cfargument name="cm" type="string" required="true" hint="" /> 
        <cfargument name="pt" type="string" required="true" hint="" /> 
        <cfargument name="fl" type="string" required="true" hint="" />
        <cfargument name="se" type="string" required="true" hint="" />
        <cfargument name="ck" type="string" required="true" hint="" />
        <cfargument name="gb" type="string" required="false" hint="" />
        <cfargument name="ax" type="string" required="false" hint="" />

        <cfscript>  
           var LOCAL = {};  
           // arguments
           LOCAL.command = cm;
           LOCAL.imgPath = pt;
           LOCAL.imgFile = fl;
           LOCAL.sellerILN = se;
           LOCAL.cookie = LSParseNumber(ck);
           LOCAL.getBack = gb;
           LOCAL.access = ax;
           // s3
           // commander
           if ( LOCAL.command NEQ "" ) {
                LOCAL.action = LOCAL.command;
           } else {
                LOCAL.action = "upload";
                }
           // s3 misc
           LOCAL.bucketPath = Session.bucketPath;
           LOCAL.bucketName = Session.bucketName;
           LOCAL.acl = "public-read";
           LOCAL.storage = "";
           LOCAL.tempDirectory = expandPath( "../members/img/secure/" );
           LOCAL.allow = "png,jpg,jpeg";
           LOCAL.failedLoads = "";
           LOCAL.altFailedLoads = "";
           LOCAL.createBucket = "false";
           LOCAL.errorCount = 0;
           LOCAL.altErrorCount = 0;
           LOCAL.cacheControl = 1;
           LOCAL.contentType = "image";
           LOCAL.httptimeout = "300";
           LOCAL.cacheDays = "30";
           LOCAL.storageClass = "REDUCED_REDUNDANCY";
           LOCAL.keyName = "";
           LOCAL.baseUrl = "http://www.baseurl.com";
           LOCAL.imageSrc = "";
           LOCAL.testFilePath = LOCAL.imgPath & LOCAL.imgFile;
           LOCAL.fileExt = ListLast(LOCAL.testFilePath, ".");
           LOCAL.runner = "s,m,l,xl";
           LOCAL.worked = "true";
      </cfscript>   
      // runner is the file size setter, in results I only create two sizes, during imports I create all four
      <cftry>
        <cfhttp timeout="45" 
            throwonerror="no" 
            url="#LOCAL.testFilePath#" 
            method="get" 
            useragent="Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.12) Gecko/20080201 Firefox/2.0.0.12" 
            getasbinary="yes" 
            result="objGet">
        <cfscript>
            // set file sizes to create
            if ( LOCAL.command EQ "upload_search" ){
                if ( LOCAL.cookie LT 320 ) {
                    LOCAL.runner = "l,s";
                    }
                else if ( LOCAL.cookie GTE 320 AND LOCAL.cookie LTE 767 ) {
                    LOCAL.runner = "l,m";
                    }
                else if ( LOCAL.cookie GT 768 ) {
                    LOCAL.runner = "xl,m";
                    }
                else if ( LOCAL.cookie GT 1280 ){
                    LOCAL.runner = "xl,l";
                    }
                } else if ( LOCAL.command EQ "upload_import") {
                    LOCAL.runner = "xl,l,m,s";
                    }
            // validate
            if ( len(objGet.Filecontent) EQ 0 OR objGet.Mimetype EQ "text/html"  ){
                LOCAL.worked = "false length or mime";
                } else if ( NOT listfindnocase(LOCAL.allow, LOCAL.fileExt ) ){
                LOCAL.worked = "false wrong extension";
                } else {
                // create temp
                LOCAL.objImage = ImageNew(objGet.FileContent);
                LOCAL.basePath = LOCAL.tempDirectory & "_base_" & LOCAL.imgFile;
                imageWrite( LOCAL.objImage, LOCAL.basePath, ".99");
                LOCAL.base = imageRead( LOCAL.basePath );
                LOCAL.imageSrc = LOCAL.tempDirectory;

                // formats
                // S = 100x127, 
                // M = 180x230, 
                // L = 290x370, 
                // XL = 870x1110 

                // portrait
                if ( ImageGetWidth( LOCAL.base ) LT ImageGetHeight( LOCAL.base ) ){
                    for (LOCAL.i = 1; LOCAL.i LTE ListLen(LOCAL.runner,","); LOCAL.i = LOCAL.i+1){
                        LOCAL.lt = ListGetAt(LOCAL.runner, LOCAL.i, ",");
                        LOCAL.base = imageRead( LOCAL.basePath );
                        ImageSetAntialiasing(LOCAL.base,"on");
                        // default image width/height
                        LOCAL.height = Application.strConfig.respH[LOCAL.lt];
                        LOCAL.width = "";
                        ImageScaleToFit(LOCAL.base, LOCAL.width, LOCAL.height, "highestQuality");

                        LOCAL.filekey = LOCAL.lt & "_" & LOCAL.imgFile;
                        LOCAL.keyName = LOCAL.sellerILN & "/" & LOCAL.filekey;
                        LOCAL.filename = LOCAL.tempDirectory & LOCAL.filekey;
                        imageWrite( LOCAL.base, LOCAL.filename, ".99" );

                        // s3
                        Application.strObjs.s3.putObject(LOCAL.bucketName, LOCAL.filekey, LOCAL.contentType, LOCAL.httptimeout, LOCAL.cacheControl, LOCAL.cacheDays, LOCAL.acl, LOCAL.storageClass, LOCAL.keyName, LOCAL.imageSrc, "false" );
                        fileDelete( LOCAL.tempDirectory & LOCAL.lt & "_" & LOCAL.imgFile );
                        }
                    } else {
                    // same for landscape
                    ...
                    }
                }
                // cleanup
                fileDelete( LOCAL.tempDirectory & "_base_" & LOCAL.imgFile );
            } 
        </cfscript>
    // update media log
        ...
        <cfcatch>
        // dump errror message
        </cfcatch>
        </cftry>

    // return image 
        <cfif LOCAL.access EQ "rm">
            <cftry>
            <cfscript>
            if ( LOCAL.getBack EQ "s" ){
                LOCAL.passPath = Session.bucketPath & Session.bucketName & "/" & LOCAL.sellerILN & "/" & ListGetAt(LOCAL.runner, Listlen(LOCAL.runner), ",") & "_" & LOCAL.imgFile;
            } else if( LOCAL.getBack EQ "l" ) {
                LOCAL.passPath = Session.bucketPath & Session.bucketName & "/" & LOCAL.sellerILN & "/" & ListGetAt(LOCAL.runner, 1, ",") & "_" & LOCAL.imgFile;
            }
            LOCAL.mime = "image/" & LOCAL.fileExt;
            </cfscript>

            <cfcontent type="#LOCAL.mime#" file="#LOCAL.passPath#" />
            <cfcatch>
            // dump errors
            </cfcatch>                              
        </cftry>
    <cfelse>
        <cfreturn LOCAL.worked>
    </cfif>
    </cffunction>
</cfcomponent>

Итак, я устанавливаю, какие размеры файлов я хочу создать LOCAL.runner, и просматриваю этот список, изменяя размер базового изображения до заданных размеров изображения и сохраняя созданное изображение на s3.

Проблема: cfcontent пытается вернуть изображение до его создания. Я получаю ошибку The file specified in contentTag does not exist, когда запускаю приведенный выше код. Если я проверю на S3, изображение там, поэтому я предполагаю, что это проблема времени.

Спасибо за любые указания о том, как я могу заставить «cfcontent» ждать, пока изображение не будет создано!


person frequent    schedule 25.08.2012    source источник


Ответы (1)


А как насчет вывода ссылки на локальный CFM, который загрузит img? Я имею в виду, что для изображений, существующих на вашем сервере, вы выводите тег <img>, который указывает на него. Для изображений, которые вам нужно загрузить, вы выводите что-то вроде этого:

<img src="imagegetter.cfm?p=#urlofimagetoload#">

imagegetter.cfm будет отвечать за выполнение http для локального получения и изменения размера изображения. Затем он может обслуживать биты через cfcontent.

person Raymond Camden    schedule 25.08.2012
comment
в порядке. нашел это :-) Еще один вопрос: я используя вышеописанное с photoswipe, для чего требуется указать URL-адрес, с которого будет загружаться изображение, если photoswipe активирован . Если я запускаю отсутствующие изображения через imagegetter.cfm, у меня также будет правильный путь, когда я отправлю изображение обратно. Любая идея, как я могу заменить URL-адрес imageGetter.cfm?... новым путем? Если я уйду с пути, при активации photoswipe повторно запросит imagegetter.cfm. - person frequent; 26.08.2012
comment
Если imagegetter.cfm является «интеллектуальным» (т.е. он знает, когда он уже загружен/изменен размер), то не имеет значения, используете ли вы только этот URL-адрес. Верно? - person Raymond Camden; 26.08.2012
comment
Сидишь на нем, делаешь умным :-). Кроме того, поскольку я использую адаптивные размеры (= s,m,l,xl), я показываю маленькую версию с помощью imagegetter и вывожу обычную ссылку для фотосвайпа на большую версию, что должно быть сделано к тому времени, когда пользователь сработает. фотостирание. Все еще тестирую, я опубликую решение, как только все заработает. Еще раз спасибо! - person frequent; 26.08.2012
comment
В порядке. У меня это работает, и мой CfC напоминает какой-то интеллект... См. мою правку выше. Моя последняя проблема заключается в том, что cfcontent пытается вернуть изображение, пока оно еще создается — я получаю подробности: s3.amazonaws.com/folder/img_file.jpg` сообщение не найдено, хотя когда я проверяю ведро, изображение есть. Любая идея из моего кода, что может быть не так? - person frequent; 01.09.2012