Върнете изображение от python CGI с помощта на javascript

Използвам Python CGI, за да създам уеб страница, която показва заглавие, падащо меню и изображение. Бих искал да мога да избера опция от падащото меню (бих искал да се отърва и от „изпращане“ и просто да стартирам, когато е избрана опция), да задействам моя код на Python (runthis.py) и да актуализирам изображението на уеб страницата. Искам да направя това БЕЗ отваряне на нови раздели и надявам се без опресняване на страницата. В момента стартирам този .py файл, за да получа моя html:

#!C:\Python27\python

print "Content-type: text/html"
print

print "<html>"
print "<head>"
print "<title>Tab Title</title>"

print "</head>"
print '''<body bgcolor="#ccffcc">'''

print '''<h1 align="center">Page Heading</h1>'''

print '''<form action="/cgi-bin/dropdown.py" method="post" target="_blank">'''
print '''<select name="dropdown">'''
print '''<option value="Option1" selected>Option1</option>'''
print '''<option value="Option2" selected>Option2</option>'''
print "</select>"
print '''<input type="submit" value="Submit"/>'''
print "</form>"

print "<img src = /test.png>"

print "</body>"
print "</html>"

Когато щракна върху „изпращане“, ще се отвори нов раздел, показващ същото оформление на страницата, само различно изображение (същото, например). Това се прави чрез моя dropdown.py файл в cgi-bin:

#!C:\Python27\python

import cgi,cgitb,os
cgitb.enable()

os.environ['HOME']='C:\python_cgi'

import matplotlib
matplotlib.use('Agg')

form = cgi.FieldStorage()

if form.getvalue('dropdown'):
    subject = form.getvalue('dropdown')
else:
    subject = "Not Entered"

from matplotlib.figure import Figure
from matplotlib.backends.backend_agg import FigureCanvasAgg
import StringIO

import msvcrt,sys, urllib, base64

fig = Figure(figsize=[4,4])
ax = fig.add_axes([.1,.1,.8,.8])
ax.scatter([1,2],[3,4])
canvas = FigureCanvasAgg(fig)

imgdata = StringIO.StringIO()
fig.savefig(imgdata, format='png')
imgdata.seek(0)

uri = 'data:image/png;base64,' + urllib.quote(base64.b64encode(imgdata.buf))

print "Content-Type: text/html"
print

print """\

<html>
<head>
<title>Tab Title</title>

</head>
<body>
  <body bgcolor="#ccffcc">
  <h1 align="center">Page Heading</h1>

  <form action="/cgi-bin/dropdown.py" method="post" target="_blank">
    <select name="dropdown">
      <option value="Option1" selected>Option1</option>
      <option value="Option2" selected>Option2</option>
    </select>
    <input type="submit" value="Submit"/>
  </form>

  <img src = %s/>

</body>
</html> """ % uri

За да обобщим - просто искам да променя картината/изображението на текущата страница, вместо да отварям изцяло нова страница. Интуицията ми подсказва да използвам javascript (за който не знам нищо). Някой има ли предложение за кодов блок, който трябва да въведа, за да направя такова нещо?

Благодаря!

РЕДАКТИРАНЕ

Според коментарите по-долу се опитвам да внедря този html файл:

<html>
<head>
<title>Tab Title</title>

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js" ></script>

</head>
<body>

<script>
  function changeImage(imgName)
{
     jQuery.get('/cgi-bin/dropdown.py', function(data) {
     image = document.getElementById('imgDisp');
     image.src = data;
    })

  }
</script>


  <body bgcolor="#ccffcc">
  <h1 align="center">Page Heading</h1>

  <select name="dropdown" onchange="changeImage(this.value)"> 
  <option value="Option1">Option1</option>
  <option value="Option2">Option2</option>
  </select>

  <img id="imgDisp" src="/test.png" />

</body>
</html>

Това зарежда страницата ми правилно, но нищо не се случва, когато направя избор от падащия списък. Надявах се изображението да се промени. Моят код "dropdown.py" сега изглежда така:

#!C:\Python27\python

import cgi,cgitb,os
cgitb.enable()

os.environ['HOME']='C:\python_cgi'

import matplotlib
matplotlib.use('Agg')

from matplotlib.figure import Figure
from matplotlib.backends.backend_agg import FigureCanvasAgg
import StringIO

import msvcrt,sys, urllib, base64

fig = Figure(figsize=[4,4])
ax = fig.add_axes([.1,.1,.8,.8])
ax.scatter([1,2],[3,4])
canvas = FigureCanvasAgg(fig)

imgdata = StringIO.StringIO()
fig.savefig(imgdata, format='png')
imgdata.seek(0)

uri = 'data:image/png;base64,' + urllib.quote(base64.b64encode(imgdata.buf))
return uri

Все още не съм стигнал до подхода на url параметъра -- не съм сигурен как се прави това. Всякакви повече съвети ще бъдат високо оценени!


person mcfly    schedule 10.02.2014    source източник
comment

Нека махнем едно нещо от пътя: няма няма масиви във вашата функция sum. Rust има три свързани типа и можете да търсите тук в Stack Overflow или The Rust Programming Language за повече информация за тях:

  1. Резени &[T].
  2. Вектори Vec<T>
  3. Масиви [T; n]

Аргументът v е срез, който е просто указател към част от данни и броя на елементите.

Защо и как работи това? Има ли автоматично кастинг между тези два типа?

Тук влиза в действие Deref характеристика. Има реализация на тази характеристика, която изглежда така:

impl<T> Deref for Vec<T> {
    type Target = [T];
    fn deref(&self) -> &[T];
}

Това означава, че всяка препратка към Vec<T> може да действа като препратка към [T] и печели всички методи от целевия тип. Deref се разбира от компилатора, но всеки тип може да го реализира, така че е само нещо специално.

Налага ли някакво наказание или просто взема местоположението на паметта на основния масив на вектора?

Това е трансформация с нулеви разходи, поради което компилаторът ще го направи вместо вас. Много е необичайно компилаторът да прави нещо за вас, което е скъпо.

Това означава ли, че за този тип използване е по-добре да се използва масив, а не вектор като API?

Абсолютно! В 100% от случаите трябва да приемете &[T] вместо &Vec<T>. Повече неща от просто Vec могат да предоставят &[T] и масивите са пример за това.

  -  person Michael Zalla    schedule 11.02.2014
comment
Най-добре е да отделите презентацията от логиката. Вашият „backend“ код трябва да приема само параметри и да показва отговор (изображение). Може би най-лесният начин да направите това е да създадете схема на URL параметри (като /cgi-bin/myscript.py?option=1), която вашият скрипт да следва, и да получите достъп до стойностите на параметрите в рамките на CGI скрипта, като използвате класа FieldStorage (вижте docs.python.org/2/library/cgi.html#id1). Стойността на този дизайн се крие в простотата на предния край.   -  person Michael Zalla    schedule 11.02.2014
comment
В този сценарий целта на вашия JavaScript код би била да прочете стойностите на формуляра, да създаде персонализиран URL адрес към вашия скрипт на Python (вижте stackoverflow.com /questions/6566456) и задайте атрибута src на елемент на изображение на този URL адрес.   -  person Michael Zalla    schedule 11.02.2014
comment
Ако използвам схемата на javascript в последния коментар, как да задействам кода на python в основния html файл? Ако разбирам, бих избрал опция за падащо меню, тогава javascript ще се задейства, за да създаде url - но тогава как да стартирам своя скрипт на python? Също така, къде да задам атрибута src-- в моя скрипт на python? Не съм сигурен как да върна данните. Благодаря!   -  person mcfly    schedule 11.02.2014


Отговори (1)


В отговор на вашия редактиран въпрос, решението всъщност може да бъде по-просто:

function changeImage(imgName) {
     jQuery.get('/cgi-bin/dropdown.py', function(data) {
     image = document.getElementById('imgDisp');
     image.src = data;
    })
}

Тук правите асинхронна заявка към вашия скрипт на Python и чакате някои данни да бъдат върнати. Въпреки това можете да разглеждате вашия скрипт на Python като самостоятелна услуга, която картографира, така да се каже, уникален набор от параметри към (динамично генерирано) изображение. Това изисква вашият скрипт на Python да извежда изображението в браузъра, вместо да връща данните за изображението чрез CGI:

imgdata = StringIO.StringIO()
fig.savefig(imgdata, format='png')
imgdata.seek(0)

#Something along these lines
print "Content-Type: img/png\n"
imgdata.seek(0)
print imgdata.read()

След като сте сигурни, че HTTP заявка към вашия скрипт на Python обслужва валиден PNG, вашият преден код трябва само да актуализира атрибута src на изображението, което показвате:

function changeImage(imgName) {
    var url = "http://localhost:8000/cgi-bin/dropdown.py?image=" + imgName;
    var img = jQuery('#imgDisp');
        img.src = url;
}

Когато на вашия елемент img бъде дадена нова стойност src, браузърът автоматично ще отправи заявка към този URL адрес и ще се опита да извлече изображение, което ще се зареди на вашата страница, замествайки предишното изображение. Ще трябва обаче да модифицирате своя скрипт на Python, за да очаквате параметър на заявка с име image, който съдържа низ. CGI има прост метод за достъп до тези стойности на параметри, предадени вътре в URL адреса:

#Example CGI script
if __name__ == "__main__":
    params = cgi.FieldStorage()
    if "image" in params:
        img = params['image']
        #Generate the image and output it with the correct headers
    else:
        #Exception handling
        print "Content-Type: text/html\n"
        print """<html><body>No image name was specified!</body></html>"""

Тази страница е чудесен ресурс, който можете да разгледате: http://lost-theory.org/python/dynamicimg.html

person Michael Zalla    schedule 11.02.2014