Как вы записываете изображение в браузер в виде двоичного потока в coldfusion?

#coldfusion #coldfusion-9

#coldfusion #coldfusion-9

Вопрос:

У меня есть сервис на сервере Coldfusion 9, который создает для нас графические баннеры «на лету». Отдельная машина должна сохранять эти файлы с чем-то вроде:

 wget http://myserver.com/services/local/bannerCreator/250x250-v3.cfm?prodID=3amp;percentSaving=19
  

Проблема в том, что я не могу придумать, как заставить coldfusion записывать двоичные данные без использования временного файла. На данный момент изображение отображается просто как тег изображения, подобный этому:

 <cfimage action = "writeToBrowser" source="#banner#" width="#banner.width#" height="#banner.height#" />
  

Есть идеи? Или я должен просто использовать временный файл?

Ответ №1:

Я не могу протестировать, потому что вы не даете никакого примера кода для того, как генерируются ваши изображения, но вы пробовали что-нибудь в этом роде?

 <cfcontent reset="true" variable="#imageData#" type="image/jpg" />
  

Обновление: Итак, я пошел дальше и создал свой собственный образ; Я предполагаю, что вы делаете что-то подобное. У меня это работает идеально:

 <cfset img = imageNew("",200,200,"rgb","red") />
<cfcontent variable="#toBinary(toBase64(img))#" type="image/png" reset="true" />
  

Это работает без записи в файл и без использования виртуальной файловой системы («ramdisk»)

Комментарии:

1. К вашему сведению: нет необходимости явно устанавливать для атрибута reset значение true , потому что true это значение по умолчанию.

Ответ №2:

Если у вас есть двоичные байты файла / изображения, вы можете заменить выходной буфер его содержимым следующим образом:

 <cfscript>
// eg. this is how you get a file as a binary stream
// var fileBytes = fileReadBinary( '/path/to/your/file.jpg' );

// get the http response
var response = getPageContext().getFusionContext().getResponse();

// set the appropriate mime type
response.setHeader( 'Content-Type', 'image/jpg' );

// replace the output stream contents with the binary
response.getOutputStream().writeThrough( fileBytes );

// leave immediately to ensure no whitespace is added
abort;
</cfscript>
  

В значительной степени то, что <cfcontent> делает, когда вы используете reset="true"

Преимущество этого метода перед <cfcontent> заключается в том, что мы можем записать его внутри наших cfcs на основе cfscript.

Ответ №3:

Я нашел решение выше

 <cfcontent variable="#toBinary(toBase64(img))#" type="image/png" reset="true" />
  

для меня это не совсем работает.

Установка type=»image / png» — это просто установка mime-типа ответа. Я не думаю, что это обязательно кодирование изображения в формате PNG. Таким образом, генерация прозрачного png (тип изображения «argb») давала мне странные цвета по сравнению с <cfimage action = "writeToBrowser"...> методом.

Я подумал, что каким-то образом мне нужно явно закодировать данные изображения в формате PNG и напрямую выводить двоичные данные.

Немного покопавшись в базовой java, я придумал это, которое пока, кажется, работает для меня.

В этом примере отображается прозрачный png-файл с черным кругом.

 <!--- create the image and draw it --->
<cfset img = ImageNew("", 23, 23, "argb")>
<cfset ImageSetDrawingColor(img, "black")>
<cfset ImageDrawOval(img, 0, 0, 21, 21, true)>

<!--- get the response object --->
<cfset response = getPageContext().getFusionContext().getResponse()>
<!--- set the response mime type --->
<cfset response.setHeader('Content-Type', 'image/png')>
<!--- get the underlying image data --->
<cfset bImage = ImageGetBufferedImage(img)>
<!--- get the magical object to do the png encoding --->
<cfset ImageIO = createObject("java", "javax.imageio.ImageIO")>
<!--- encode the image data as png and write it directly to the response stream --->
<cfset ImageIO.write(bImage, "png", response.getResponse().getOutputStream())>
  

Я надеюсь, что это кому-то поможет!

Комментарии:

1. Правильно, cfcontent только задает Content-Type заголовок (и необязательно возвращает содержимое файла или переменной). Не предполагается изменять содержимое. Какой код выдал вам «нечетные цвета по сравнению с writeToBrowser «?

2. Я получил нечетные цвета с помощью этого кода, Ли: <cfset img = imageNew(«»,1,1, «argb»,»»») /> <cfcontent variable=»#toBinary(toBase64(img))#» type=»image /png» reset =»true» /> Спасибо, Росс!

Ответ №4:

Уберите атрибуты height и width и добавьте атрибут format:

 <cfimage action = "writeToBrowser" source="#banner#" format="png" />
  

wget должен учитывать перенаправление на физический файл, который CF создает в папке CFFileServlet, но если этого не происходит, есть флаг, который вы можете установить, чтобы сделать это --max-redirect=10 .

И, как вы предлагаете, временный файл тоже будет работать. Просто запишите файл и используйте cfheader и cfcontent для его записи. Просто убедитесь, что имя временного файла более уникально.

 <cfimage action="write" destination="tempfile.png" source="#banner#" format="png" />
<cfheader name="content-disposition" value="attachment; filename=banner.png" />
<cfcontent file="tempfile.png" deletefile="true" type="image/png" />
  

Ответ №5:

Я делаю аналогичную вещь, и вам нужно объединить использование тегов и cfscript. Существуют функции изображения, которые требуются. Доступно множество функций изображения, если у вас есть изображение в памяти в качестве переменной. Вы можете загрузить изображение в память, используя CFFILE или CFHTTP, или несколькими другими способами.

В моем случае я считываю файл изображения в память, используя тег CFIMAGE, затем обрабатываю его с помощью функций изображения CFSCRIPT, добавляя текст внизу, затем выводя полученное изображение в формате .png (или .jpg, если вы предпочитаете) в браузере. Единственный файл, хранящийся на сервере, — это исходный файл изображения. В вашем случае вместо чтения в изображении вы бы вызвали его, используя тег cfhttp, как вы уже делаете. Вот мой код:

 <!---Get the image for processing ...--->
<cfimage action="read" source="#application.approotABS#webcamwebcam.jpg" name="CamImage" /> 
<!--- prepare the text for overlay --->
<cfscript>
  attr=structNew();
  attr.font = "Arial";
  attr.size = 15;
  ImageSetDrawingColor(CamImage, "white");
  ImageDrawText(CamImage, 'LIVE FROM STUDIO 1', 18,(ImageGetHeight(CamImage)-54), attr);
  ImageDrawText(CamImage, '#ShowOnNow.showname#', 18,(ImageGetHeight(CamImage)-36), attr);
  ImageDrawText(CamImage, datestring,18,(ImageGetHeight(CamImage)-18), attr);

</cfscript>

<!--- further down the page, output the manipulated image: ---->
 <div class="webcam">  
      <cfimage action="writeToBrowser" source="#Camimage#"  >
  </div>
  

Вы можете увидеть это в действии на http://hawkesburyradio.com.au/index.cfm?pid=111538

(Я использую CF9 с Windows Server)