Beispiel #1
0
    def load_from_file(self):  # producer slot
        self.ui.label.setText("Select an image file")
        file_name, t = QFileDialog.getOpenFileName(self, None, None,
                                                   "Images (*.png *.jpg)")
        if not file_name:
            return

        image = QImage()
        if not image.load(file_name):
            self.ui.label.setText(
                "Selected file is not an image, please select another.")
            return

        self.ui.label.setPixmap(QPixmap.fromImage(image))

        # Get the image data:
        buf = QBuffer()
        buf.open(QBuffer.ReadWrite)
        out = QDataStream(buf)
        out << image

        try:
            from prodcon_ipc.producer_ipc import ScopedProducer
            with ScopedProducer(self.producer_ipc, buf.size()) as sp:
                # Copy image data from buf into shared memory area:
                sp.data()[:sp.size()] = buf.data().data()[:sp.size()]
        except Exception as err:
            self.ui.label.setText(str(err))

        if SHARED_STRUCT == 1:
            # Read from shared memory, increase value and write it back:
            if self.shmem_config.isAttached() or self.shmem_config.attach():
                if self.shmem_config.lock():
                    counter, stop_flag, _ = struct.unpack(
                        STRUCT_FORMAT, self.shmem_config.constData())
                    data = struct.pack(STRUCT_FORMAT, counter + 1, stop_flag,
                                       str(os.path.basename(file_name)[:30]))
                    size = min(struct.calcsize(STRUCT_FORMAT),
                               self.shmem_config.size())

                    self.shmem_config.data()[:size] = data[:size]
                    self.shmem_config.unlock()
                    if stop_flag:  # stop producing?
                        logzero.logger.info(
                            "Consumer requested to stop the production.")
                        sys.exit(0)
                else:
                    logzero.logger.error("unable to lock " +
                                         self.shmem_config.key())
                #self.shmem_config.detach()
            else:
                logzero.logger.error("unable to attach " +
                                     self.shmem_config.key())
Beispiel #2
0
    def sendMessage(self):
        textbuf = QBuffer()
        textbuf.open(QBuffer.ReadWrite)
        messageText = QDataStream(textbuf)
        messageText << self.ui.messageBox.text
        size = textbuf.size()

        if not self.shareMemory.create(size):
            return

        size = min(self.shareMemory.size(), size)
        self.sharedMemory.lock()
Beispiel #3
0
    def sendMessage(self):
        textbuf = QBuffer()
        textbuf.open(QBuffer.ReadWrite)
        messageText = QDataStream(textbuf)
        messageText << self.ui.messageBox.text
        size = textbuf.size()

        if not self.shareMemory.create(size):
            return

        size = min(self.shareMemory.size(), size)
        self.sharedMemory.lock()
Beispiel #4
0
    def loadFromFile(self):
        """ This slot function is called when the "Load Image From File..."
        button is pressed on the firs Dialog process.  First, it tests whether
        the process is already connected to a shared memory segment and, if so,
        detaches from that segment.  This ensures that we always start the
        example from the beginning if we run it multiple times with the same
        two Dialog processes.  After detaching from an existing shared memory
        segment, the user is prompted to select an image file.  The selected
        file is loaded into a QImage.  The QImage is displayed in the Dialog
        and streamed into a QBuffer with a QDataStream.  Next, it gets a new
        shared memory segment from the system big enough to hold the image data
        in the QBuffer, and it locks the segment to prevent the second Dialog
        process from accessing it.  Then it copies the image from the QBuffer
        into the shared memory segment.  Finally, it unlocks the shared memory
        segment so the second Dialog process can access it.  After self
        function runs, the user is expected to press the "Load Image from
        Shared Memory" button on the second Dialog process.
        """

        if self.sharedMemory.isAttached():
            self.detach()

        self.ui.label.setText("Select an image file")
        fileName, _ = QFileDialog.getOpenFileName(
            self, None, None, "Images (*.png *.xpm *.jpg)")
        image = QImage()
        if not image.load(fileName):
            self.ui.label.setText(
                "Selected file is not an image, please select another.")
            return

        self.ui.label.setPixmap(QPixmap.fromImage(image))

        # Load into shared memory.
        buf = QBuffer()
        buf.open(QBuffer.ReadWrite)
        out = QDataStream(buf)
        out << image
        size = buf.size()

        if not self.sharedMemory.create(size):
            self.ui.label.setText("Unable to create shared memory segment.")
            return

        size = min(self.sharedMemory.size(), size)
        self.sharedMemory.lock()

        # Copy image data from buf into shared memory area.
        self.sharedMemory.data()[:] = buf.data().data()
        self.sharedMemory.unlock()
Beispiel #5
0
 def render_to_file(self, res, file_object):
     """
     Renders the image into a File resource.
     Returns the size of the data that has been written.
     """
     qt_format = self.format  # this may not be constant due to processEvents()
     image = self.render(res)
     q_buffer = QBuffer()
     image.save(q_buffer, qt_format)
     output = q_buffer.buffer().data()
     if type(file_object) is not _io.BufferedRandom:
         output = str(output)
     file_object.write(output)
     return q_buffer.size()
Beispiel #6
0
    def loadFromFile(self):
        """ This slot function is called when the "Load Image From File..."
        button is pressed on the firs Dialog process.  First, it tests whether
        the process is already connected to a shared memory segment and, if so,
        detaches from that segment.  This ensures that we always start the
        example from the beginning if we run it multiple times with the same
        two Dialog processes.  After detaching from an existing shared memory
        segment, the user is prompted to select an image file.  The selected
        file is loaded into a QImage.  The QImage is displayed in the Dialog
        and streamed into a QBuffer with a QDataStream.  Next, it gets a new
        shared memory segment from the system big enough to hold the image data
        in the QBuffer, and it locks the segment to prevent the second Dialog
        process from accessing it.  Then it copies the image from the QBuffer
        into the shared memory segment.  Finally, it unlocks the shared memory
        segment so the second Dialog process can access it.  After self
        function runs, the user is expected to press the "Load Image from
        Shared Memory" button on the second Dialog process.
        """

        if self.sharedMemory.isAttached():
            self.detach()

        self.ui.label.setText("Select an image file")
        fileName, _ = QFileDialog.getOpenFileName(self, None, None,
                "Images (*.png *.xpm *.jpg)")
        image = QImage()
        if not image.load(fileName):
            self.ui.label.setText(
                    "Selected file is not an image, please select another.")
            return

        self.ui.label.setPixmap(QPixmap.fromImage(image))

        # Load into shared memory.
        buf = QBuffer()
        buf.open(QBuffer.ReadWrite)
        out = QDataStream(buf)
        out << image
        size = buf.size()

        if not self.sharedMemory.create(size):
            self.ui.label.setText("Unable to create shared memory segment.")
            return

        size = min(self.sharedMemory.size(), size)
        self.sharedMemory.lock()

        # Copy image data from buf into shared memory area.
        self.sharedMemory.data()[:] = buf.data().data()
        self.sharedMemory.unlock()
Beispiel #7
0
class MayRenderer(QWidget):

    shouldSave = pyqtSignal()

    texsize = 512
    samplerate = 44100

    shaderHeader = '#version 130\nuniform float iTexSize;\nuniform float iBlockOffset;\nuniform float iSampleRate;\n\n'

    def __init__(self, parent):
        super().__init__()
        self.parent = parent

        self.blocksize = (self.texsize * self.texsize) / self.samplerate

        self.initState()
        self.initUI()
        self.initAudio()

    def initState(self):
        self.playing = False
        self.initVolume = 1

        self.useWatchFile = False
        self.watchFileName = ''
        self.storeCodeIfNotWatching = ''

        self.useSynDump = False
        self.synDrumName = ''
        self.synFileName = ''

    def initUI(self):
        self.mainLayout = QVBoxLayout()
        self.codeLayout = QVBoxLayout()
        self.codeButtonBar = QHBoxLayout()
        self.codeWatchFileBar = QHBoxLayout()
        self.renderBar = QHBoxLayout()
        self.playbackBar = QHBoxLayout()
        self.renderGroup = QGroupBox()
        self.renderGroupLayout = QVBoxLayout()
        self.renderGroupLayout.addLayout(self.renderBar)
        self.renderGroupLayout.addLayout(self.playbackBar)
        self.renderGroup.setLayout(self.renderGroupLayout)
        self.renderGroup.setObjectName("renderGroup")
        self.synGroupLayout = QHBoxLayout()
        self.synGroup = QGroupBox()
        self.synGroup.setLayout(self.synGroupLayout)

        self.synDumpCheckBox = QCheckBox('Dump as')
        self.synDrumNameBox = QLineEdit(self)
        self.synFileNameBox = QLineEdit(self)
        self.synFileButton = QPushButton('...')
        self.synGroupLayout.addWidget(self.synDumpCheckBox, 1)
        self.synGroupLayout.addWidget(self.synDrumNameBox, 2)
        self.synGroupLayout.addWidget(QLabel('in'), .1)
        self.synGroupLayout.addWidget(self.synFileNameBox, 5)
        self.synGroupLayout.addWidget(self.synFileButton, 0.1)
        self.synDumpCheckBox.stateChanged.connect(self.toggleSynDump)
        self.synDrumNameBox.setPlaceholderText('drumname')
        self.synDrumNameBox.textChanged.connect(self.setSynDrumName)
        self.synFileNameBox.setPlaceholderText('some aMaySyn .syn file')
        self.synFileNameBox.textChanged.connect(self.setSynFileName)
        self.synFileButton.setMaximumWidth(40)
        self.synFileButton.clicked.connect(self.chooseSynFile)

        self.codeGroup = QGroupBox()
        self.buttonCopy = QPushButton('↬ Clipboard', self)
        self.buttonCopy.clicked.connect(self.copyToClipboard)
        self.buttonPaste = QPushButton('Paste ↴', self)
        self.buttonPaste.clicked.connect(self.pasteClipboard)
        self.buttonClear = QPushButton('×', self)
        self.buttonClear.clicked.connect(self.clearEditor)
        self.codeEditor = QPlainTextEdit(self)
        self.codeEditor.setLineWrapMode(QPlainTextEdit.WidgetWidth)
        #self.codeEditor.setCenterOnScroll(True)
        #self.codeEditor.textChanged.formatEditor()) # this gives a recursion problem, but how to filter e.g. tabs?
        self.codeEditor.cursorPositionChanged.connect(self.updatePosLabel)
        self.codeEditor.setTabStopWidth(14)
        self.watchFileCheckBox = QCheckBox('watch file:', self)
        self.watchFileCheckBox.stateChanged.connect(self.toggleWatchFile)
        self.watchFileNameBox = QLineEdit(self)
        self.watchFileNameBox.setPlaceholderText(
            'use GLSL code file instead of the above editor...')
        self.watchFileNameBox.textChanged.connect(self.setWatchFileName)
        self.buttonWatchFile = QPushButton('...', self)
        self.buttonWatchFile.setMaximumWidth(40)
        self.buttonWatchFile.clicked.connect(self.chooseWatchFile)

        self.renderButton = QPushButton(self)
        self.renderButton.clicked.connect(self.pressRenderShader)
        self.renderLengthBox = QDoubleSpinBox(self)
        self.renderLengthBox.setMinimum(0)
        self.renderLengthBox.setValue(4 * self.blocksize - .01)
        self.renderLengthBox.setSingleStep(self.blocksize)
        self.renderLengthBox.setSuffix(' sec')
        self.renderLengthBox.setToolTip('render length')
        self.renderBpmBox = QSpinBox(self)
        self.renderBpmBox.setRange(1, 999)
        self.renderBpmBox.setValue(160)
        self.renderBpmBox.setPrefix('BPM ')
        self.renderBpmBox.setToolTip('--> determines SPB')
        self.playbackVolumeSlider = QSlider(Qt.Horizontal)
        self.playbackVolumeSlider.setMaximum(100)
        self.playbackVolumeSlider.setValue(self.initVolume * 100)
        self.playbackVolumeSlider.setToolTip('volume')
        self.playbackVolumeSlider.sliderMoved.connect(self.setVolume)
        self.renderBar.addWidget(self.renderButton, 60)
        self.renderBar.addWidget(self.renderBpmBox, 20)
        self.renderBar.addWidget(self.renderLengthBox, 20)

        self.progressBar = QProgressBar(self)
        self.progressBar.setEnabled(False)
        self.pauseButton = QPushButton(self)
        self.pauseButton.setEnabled(False)
        self.pauseButton.clicked.connect(self.pressPauseButton)
        self.playbackBar.addWidget(self.progressBar, 60)
        self.playbackBar.addWidget(self.playbackVolumeSlider, 20)
        self.playbackBar.addWidget(self.pauseButton, 20)

        self.codeButtonBar.addWidget(self.buttonCopy)
        self.codeButtonBar.addWidget(self.buttonPaste)
        self.codeButtonBar.addWidget(self.buttonClear)
        self.codeWatchFileBar.addWidget(self.watchFileCheckBox)
        self.codeWatchFileBar.addWidget(self.watchFileNameBox)
        self.codeWatchFileBar.addWidget(self.buttonWatchFile)
        self.codeHeader = QHBoxLayout()
        self.codePosLabel = QLabel('(0,0)')
        self.codeHeader.addWidget(QLabel('GLSL code'))
        self.codeHeader.addStretch()
        self.codeHeader.addWidget(self.codePosLabel)
        self.codeLayout.addLayout(self.codeHeader)
        self.codeLayout.addLayout(self.codeButtonBar)
        self.codeLayout.addWidget(self.codeEditor)
        self.codeLayout.addLayout(self.codeWatchFileBar)
        self.codeGroup.setLayout(self.codeLayout)

        self.mainLayout.addWidget(self.synGroup)
        self.mainLayout.addWidget(self.codeGroup)
        self.mainLayout.addWidget(self.renderGroup)

        self.updatePlayingUI()

        self.setLayout(self.mainLayout)

    def updatePlayingUI(self, keepActive=False):
        self.renderButton.setText(
            'shut the f**k up' if self.playing else 'send to hell')
        if not self.playing and not keepActive:
            self.progressBar.setValue(0)
        self.progressBar.setEnabled(self.playing if not keepActive else True)
        self.pauseButton.setEnabled(self.playing if not keepActive else True)
        self.pauseButton.setText('||' if (
            self.playing and self.audiooutput.state() != QAudio.SuspendedState
        ) else '▶')

    def initAudio(self):
        self.audioformat = QAudioFormat()
        self.audioformat.setSampleRate(self.samplerate)
        self.audioformat.setChannelCount(2)
        self.audioformat.setSampleSize(32)
        self.audioformat.setCodec('audio/pcm')
        self.audioformat.setByteOrder(QAudioFormat.LittleEndian)
        self.audioformat.setSampleType(QAudioFormat.Float)
        # self.audiodeviceinfo = QAudioDeviceInfo(QAudioDeviceInfo.defaultOutputDevice())

        self.audiooutput = QAudioOutput(self.audioformat)
        self.audiooutput.setVolume(self.initVolume)

    def paste(self, source):
        self.codeEditor.clear()
        source = source.replace(4 * ' ', '\t').replace(3 * ' ', '\t')
        self.codeEditor.insertPlainText(source)
        #self.codeEditor.setFocus() #TODO: think about whether we want this
        self.codeEditor.ensureCursorVisible()

    def pasteClipboard(self):
        self.paste(self.shaderHeader + QApplication.clipboard().text())

    def copyToClipboard(self):
        text = self.codeEditor.toPlainText().replace('\t', 4 * ' ')
        QApplication.clipboard().setText(text)

    def clearEditor(self):
        self.codeEditor.setPlainText('')
        self.codeEditor.setFocus()

    def updatePosLabel(self):
        cursor = self.codeEditor.textCursor()
        self.codePosLabel.setText(
            f'({cursor.blockNumber()},{cursor.positionInBlock()})')

#    def formatEditor(self):
#        plainText = self.codeEditor.toPlainText().replace('\t', 4*' ')
#        self.codeEditor.setPlainText(plainText)

    def toggleSynDump(self, state):
        self.useSynDump = (state == Qt.Checked)
        self.shouldSave.emit()

    def chooseSynFile(self):
        dialogResult, _ = QFileDialog.getSaveFileName(
            self, 'Choose SYN definition file', '',
            'aMaySyn definition files (*.syn);;All files (*)')
        print(dialogResult)
        self.synFileNameBox.setText(dialogResult)
        self.synDumpCheckBox.setCheckState(Qt.Checked)
        if self.synFileName == '':
            self.synFileNameBox.setFocus()
        self.shouldSave.emit()

    def setSynFileName(self):
        self.synFileName = self.synFileNameBox.text()
        self.shouldSave.emit()

    def setSynDrumName(self):
        self.synDrumName = self.synDrumNameBox.text()
        self.shouldSave.emit()

    def setSynDumpParameters(self, useSynDump, synFileName, synDrumName):
        self.synDumpCheckBox.setChecked(useSynDump)
        self.synFileNameBox.setText(synFileName)
        self.synDrumNameBox.setText(synDrumName)

    def toggleWatchFile(self, state):
        if not self.useWatchFile and state == Qt.Checked:
            self.storeCodeIfNotWatching = self.codeEditor.toPlainText()

        self.useWatchFile = (state == Qt.Checked)
        self.codeEditor.setEnabled(not self.useWatchFile)

        if self.useWatchFile:
            self.showWatchFileInfo()
        else:
            self.codeEditor.setPlainText(self.storeCodeIfNotWatching)

    def chooseWatchFile(self):
        dialogResult = QFileDialog.getOpenFileName(
            self, 'Choose file with GLSL code', '',
            'GLSL files (*.glsl);;All files (*)')
        print(dialogResult)
        self.watchFileNameBox.setText(dialogResult[0])
        self.watchFileCheckBox.setCheckState(Qt.Checked)
        self.shouldSave.emit()

    def setWatchFileName(self):
        self.watchFileName = self.watchFileNameBox.text()
        self.showWatchFileInfo()

    def showWatchFileInfo(self):
        if self.useWatchFile:
            fileInfo = QFileInfo(self.watchFileName)
            infoText = 'use code from file:\n' + self.watchFileName + '\n' + (
                '(exists)' if fileInfo.exists() else '(doesn\'t exist)')
            self.codeEditor.setPlainText(infoText)

    def pressRenderShader(self):
        self.playing = not self.playing
        if self.playing:
            self.renderShaderAndPlay()
        else:
            self.stopShader()

    def pressPauseButton(self):
        state = self.audiooutput.state()

        if state == QAudio.ActiveState:
            self.audiooutput.suspend()
        elif state == QAudio.SuspendedState:
            self.audiooutput.resume()

        self.updatePlayingUI(keepActive=True)

    def stopShader(self):
        self.audiooutput.stop()
        self.updatePlayingUI()

    def renderShaderAndPlay(self, file=None):
        self.playing = True
        self.updatePlayingUI()

        shaderSource = self.shaderHeader + """
uniform float SPB;
void main()
{
   float t = (iBlockOffset + gl_FragCoord.x + gl_FragCoord.y*iTexSize) / iSampleRate;
   t = floor(t*BITS.) / BITS.;
   vec2 s = .2 * vec2(sin(2.*3.14159*49.*t*(1.+t)*SPB*2.667)); // let's make it fun and squeaky
   vec2 v  = floor((0.5+0.5*s)*65535.0);
   vec2 vl = mod(v,256.0)/255.0;
   vec2 vh = floor(v/256.0)/255.0;
   gl_FragColor = vec4(vl.x,vh.x,vl.y,vh.y);
}
"""
        # this is the SUPER FUN BITCRUSHER for the test shader
        nr_bits = randint(128, 8192)
        shaderSource = shaderSource.replace('BITS', str(nr_bits))
        print(nr_bits, 'bits for the SUPER FUN BITCRUSHER in the test shader.')

        starttime = datetime.now()

        try:
            if self.useWatchFile:
                watchFile = QFile(self.watchFileName)
                if not watchFile.open(QFile.ReadOnly | QFile.Text):
                    QMessageBox.warning(
                        self, "Öhm... blöd.",
                        "File öffnen ging nicht. Is genügend Pfeffer drauf?")
                    self.playing = False
                    self.updatePlayingUI()
                    return
                textStream = QTextStream(watchFile)
                textStream.setCodec('utf-8')
                shaderSource = self.shaderHeader + textStream.readAll()

            else:
                code = self.codeEditor.toPlainText()
                if code:
                    shaderSource = code

        except:
            raise

        uniforms = {}

        SPB = 60 / float(self.renderBpmBox.value())
        uniforms.update({'SPB': SPB})

        print(self.renderLengthBox.value())

        try:
            duration = self.renderLengthBox.value()
        except:
            print('couldn\'t read duration field. take 10secs.')
            duration = 10

        glwidget = SFXGLWidget(self,
                               self.audioformat.sampleRate(),
                               duration,
                               self.texsize,
                               moreUniforms=uniforms)

        glwidget.show()
        log = glwidget.newShader(shaderSource)
        print(log)
        self.music = glwidget.music
        floatmusic = glwidget.floatmusic
        glwidget.hide()
        glwidget.destroy()

        if self.music == None:
            return

        self.renderLengthBox.setValue(round(glwidget.duration_real, 2) - .01)

        self.bytearray = QByteArray(self.music)

        self.audiobuffer = QBuffer(self.bytearray)
        self.audiobuffer.open(QIODevice.ReadOnly)

        endtime = datetime.now()
        el = endtime - starttime
        print("Compile time: {:.3f}s".format(el.total_seconds()))

        self.audiooutput.stop()
        self.audiooutput.start(self.audiobuffer)

        self.audiooutput.setNotifyInterval(100)
        self.audiooutput.stateChanged.connect(self.updatePlayingUI)

        self.progressBar.setMaximum(self.audiobuffer.size())
        self.audiooutput.notify.connect(self.proceedAudio)

        if file is not None:
            floatmusic_L = []
            floatmusic_R = []
            for n, sample in enumerate(floatmusic):
                if n % 2 == 0:
                    floatmusic_L.append(sample)
                else:
                    floatmusic_R.append(sample)
            floatmusic_stereo = np.transpose(
                np.array([floatmusic_L, floatmusic_R], dtype=np.float32))
            wavfile.write(file, self.samplerate, floatmusic_stereo)

    def proceedAudio(self):
        # print(self.audiobuffer.pos() / self.audioformat.sampleRate())
        self.progressBar.setValue(self.audiobuffer.pos())
        if self.audiobuffer.atEnd():
            self.audiooutput.stop()
            self.playing = False
        self.updatePlayingUI()

    def setVolume(self):
        self.audiooutput.setVolume(self.playbackVolumeSlider.value() * .01)

    def dumpInSynFile(self, drumatizeL, drumatizeR, envCode, releaseTime):
        if not self.synDumpCheckBox.isChecked():
            return
        if self.synDrumName == '':
            print("specify a valid drum name!!")
            return
        if self.synFileName == '':
            print("specify a valid .syn filename!!")
            return
        if not path.exists(self.synFileName):
            open(self.synFileName, 'a').close()

        uniqueEnv = f'_{self.synDrumName}ENV'
        drumatizeL = drumatizeL.replace('__ENV', uniqueEnv)
        drumatizeR = drumatizeR.replace('__ENV', uniqueEnv)
        envCode = envCode.replace('__ENV', uniqueEnv).replace('\n', ' ')
        parLine = f'param include src="{envCode}"\n'
        synLine = f'maindrum {self.synDrumName} src="{drumatizeL}" srcr="{drumatizeR}" release={releaseTime}\n'
        print(parLine, '\n', synLine)

        tmpSynFile = 'tmp.syn'
        copyfile(self.synFileName, tmpSynFile)
        parWritten, synWritten = False, False
        with open(tmpSynFile, 'r') as synFileHandle:
            synFileLines = synFileHandle.readlines()
        with open(self.synFileName, 'w') as synFileHandle:
            for line in synFileLines:
                parseLine = line.strip('\n').split()
                if parseLine[0:2] == ['maindrum', self.synDrumName]:
                    synFileHandle.write(synLine)
                    synWritten = True
                elif parseLine[0:2] == ['param', 'include'
                                        ] and line.find(uniqueEnv) != -1:
                    synFileHandle.write(parLine)
                    parWritten = True
                else:
                    synFileHandle.write(line)
            if not parWritten:
                synFileHandle.write('\n' + parLine)
            if not synWritten:
                synFileHandle.write('\n' + synLine)
            synFileHandle.close()
Beispiel #8
0
def producer_repetitive_scope_test(
        path,
        repetitions=1,
        delay=0):  # producer with repetitive writes to shared memory
    import time
    from PyQt5.QtGui import QPainter, QPixmap, QColor, QFont, QPen
    from PyQt5.QtCore import Qt
    from prodcon_ipc.producer_ipc import ProducerIPC

    # FIXME: this is still buggy because when the images are not read sufficiently fast from the consumer (which
    #       only (?) happens in the non-async Python consumer), image data gets corrupted (may be overwritten by the
    #       producer?! but this SHOULD be prevented by the system semaphores and the producer/consumer sync...)

    producer_ipc = ProducerIPC(UNIQUE_SHARED_MEMORY_NAME,
                               SHARED_MEMORY_KEY_FILE)
    for i in range(repetitions):
        image = QImage()
        if not image.load(path):
            logzero.logger.error("Unable to load image " + path)
            sys.exit(1)
        else:
            pm = QPixmap.fromImage(
                image)  # .convertToFormat(QImage.Format_RGB32)

            p = QPainter()
            p.begin(pm)
            p.setPen(QPen(Qt.yellow))
            p.setFont(QFont("Times", 20, QFont.Bold))
            p.drawText(pm.rect(), Qt.AlignCenter,
                       str(i + 1) + " of " + str(repetitions))
            p.end()

            image = pm.toImage()

            # Load the image:
            buf = QBuffer()
            buf.open(QBuffer.ReadWrite)
            out = QDataStream(buf)
            out << image

            try:
                avail_size, mem_data = producer_ipc.begin(buf.size())
                if avail_size < buf.size():
                    logzero.logger.warn("Couldn't get enough memory!")
            except RuntimeError as err:
                logzero.logger.error(str(err))
                sys.exit(2)

            # Copy image data from buf into shared memory area:
            error_str = None
            try:
                mem_data[:avail_size] = buf.data().data()[:avail_size]
            except Exception as err:
                logzero.logger.error(str(err))

            try:
                producer_ipc.end()
            except RuntimeError as err:
                logzero.logger.error(str(err))
                sys.exit(3)
            if delay > 0:
                time.sleep(delay)
        logzero.logger.debug("Iteration " + str(i + 1) + " of " +
                             str(repetitions) + " completed.")

    logzero.logger.info("All okay")
    # IMPORTANT: The object should NOT go out of scope until the consumer has read the data, so (also) dont call:
    # del producer_ipc
    # ...or let the app exit right away. That's why we do here:
    try:
        input(
            "Press Enter to exit but let the consumer read the image first...")
    except:
        sys.stdout.write("\n")
        pass
    sys.exit(0)
Beispiel #9
0
class Chunks(QObject):
    def __init__(self, parent: QObject = None, device: QIODevice = None):
        super().__init__(parent)
        self.device = QBuffer(self) if device is None else device
        self.chunks: [Chunk] = []
        self.position = 0
        self.size = 0

        self.setIODevice(self.device)

    def setIODevice(self, device: QIODevice) -> bool:
        self.device = device
        status = self.device.open(QIODevice.ReadOnly)
        if status:
            self.size = self.device.size()
            self.device.close()
        else:
            # Fallback is an empty buffer
            self.size = 0
            self.device = QBuffer(self)
        self.chunks.clear()
        self.position = 0
        return status

    def data(self,
             position: int,
             maxSize: int = -1,
             highlighted: QByteArray = None) -> QByteArray:
        delta = 0
        chunkIdx = 0
        chunk = Chunk()
        buffer = QByteArray()
        if highlighted:
            highlighted.clear()
        if position >= self.size:
            return buffer
        if maxSize < 0:
            maxSize = self.size
        elif (position + maxSize) > self.size:
            maxSize = self.size - position

        self.device.open(QIODevice.ReadOnly)
        while maxSize > 0:
            chunk.absPos = sys.maxsize
            chunksLoopOngoing = True
            while chunkIdx < len(self.chunks) and chunksLoopOngoing:
                # In this section, we track changes before our required data and
                # we take the editdet data, if availible. ioDelta is a difference
                # counter to justify the read pointer to the original data, if
                # data in between was deleted or inserted.
                chunk = self.chunks[chunkIdx]
                if chunk.absPos > position:
                    chunksLoopOngoing = False
                else:
                    count = 0
                    chunkIdx += 1
                    chunkOfs = position - chunk.absPos
                    if maxSize > chunk.data.size() - chunkOfs:
                        count = chunk.data.size() - chunkOfs
                        delta += CHUNK_SIZE - chunk.data.size()
                    else:
                        count = maxSize

                    if count > 0:
                        buffer += chunk.data.mid(chunkOfs, count)
                        maxSize -= count
                        position += count
                        if highlighted:
                            highlighted += chunk.dataChanged.mid(
                                chunkOfs, count)
            if maxSize > 0 and position < chunk.absPos:
                byteCount = 0
                if (chunk.absPos - position) > maxSize:
                    byteCount = maxSize
                else:
                    byteCount = chunk.absPos - position
                maxSize -= byteCount
                self.device.seek(position + delta)
                readBuffer = self.device.read(byteCount)
                buffer += readBuffer
                if highlighted:
                    highlighted += QByteArray(readBuffer.size(), NORMAL)
                position += len(readBuffer)
        self.device.close()
        return buffer

    def write(self,
              device: QIODevice,
              position: int = 0,
              count: int = -1) -> bool:
        if count == -1:
            count = self.size
        status = device.open(QIODevice.WriteOnly)
        if status:
            for idx in range(position, count, BUFFER_SIZE):
                array = self.data(idx, BUFFER_SIZE)
                device.write(array)
            device.close()
        return status

    def setDataChanged(self, position: int, dataChanged: bool) -> None:
        pass

    def dataChanged(self, position: int) -> bool:
        pass

    def indexOf(self, array: QByteArray, _from: int) -> int:
        pass

    def lastIndexOf(self, array: QByteArray, _from: int) -> int:
        pass

    def insert(self, position: int, character: str) -> bool:
        pass

    def overwrite(self, position: int, character: str) -> bool:
        pass

    def removeAt(self, position: int) -> bool:
        pass

    def getPosition(self) -> int:
        pass

    def getSize(self) -> int:
        pass

    def __getitem__(self, item):
        pass