Beispiel #1
0
 def tag_sof(self, tag):
     # 0xFFC1~0xFFC7 0xFFC9~0xFFCF Start Of Frame
     length = self.read_uint16()
     self.encodeType = 'sofx'
     self.bitsPerPixel = self.fileObject.read_uint8()
     self.height = self.read_uint16()
     self.width = self.read_uint16()
     if self.fileObject.read(1) != '\x03':
         LOGGER.error('[0x%x] Color type must be YCrCb(0x03) in JFIF.' %
                      self.fileObject.cur())
     comp = self.fileObject.read(9)
     return self.find_tag('SOFx')
Beispiel #2
0
 def find_tag(self, tagName):
     if self.fileObject.read(1) != '\xFF':
         curPos = '[0x%x]' % self.fileObject.cur()
         LOGGER.error('%s Can\'t find 0xFF in end of %s.' %
                      (curPos, tagName))
         data = []
         d = self.fileObject.read(1)
         while d != '\xFF':
             data.append(d)
             d = self.fileObject.read(1)
         LOGGER.log(CustomLoggingLevel.EXTRA_DATA,
                    '%s> %s' % (curPos, ''.join(data)))
     return '\xff' + self.fileObject.read(1)
Beispiel #3
0
 def start(self):
     if self.fileObject.read(2) == '\xff\xd8':  # start of JPEG file
         tag = self.fileObject.read(2)
         while self.scanFlag == False and tag != None:
             try:
                 tag = self.tagMap[tag](tag)
             except KeyError:
                 tag = self.tag_unknown(tag)
         LOGGER.log(
             CustomLoggingLevel.IMAGE_INFO,
             'JPEG (ver %d.%d): %d*%dpx , channel: %d, fileLength: 0x%x b.'
             % (self.version >> 8, self.version & 0xff, self.width,
                self.height, self.channel, self.fileObject.size))
     else:
         LOGGER.error('JPEG file start mark 0xFFD8 check failed.')
Beispiel #4
0
 def tag_sos(self, tag):
     # 0xFFDA Start Of Scan
     self.scanFlag = True
     length = self.read_uint16() - 2
     if self.fileObject.read(1) != '\x03':
         LOGGER.error('[0x%x] Color type must be YCrCb(0x03) in JFIF.' %
                      self.fileObject.cur())
     comp = self.fileObject.read(3)
     for i in range(3):
         self.scanQuantization[i] = {
             'DC': ord(comp[i]) >> 4,
             'AC': ord(comp[i]) & 0xf
         }
     self.scanSs = self.fileObject.read(1)
     self.scanSe = self.fileObject.read(1)
     self.scanAh = ord(self.fileObject.read(1))
     self.scanAl = self.scanAh & 0xf
     self.scanAh = self.scanAh >> 4
     self.fileObject.read(3)
Beispiel #5
0
 def tag_sof0(self, tag):
     # 0xFFC0 Start Of Frame
     length = self.read_uint16()
     self.encodeType = 'sof0'
     self.dctTransform = self.fileObject.read_uint8()
     self.bitsPerPixel = 8
     self.height = self.read_uint16()
     self.width = self.read_uint16()
     if self.fileObject.read(1) != '\x03':
         LOGGER.error('[0x%x] Color type must be YCrCb(0x03) in JFIF.' %
                      self.fileObject.cur())
     comp = self.fileObject.read(9)
     for i in range(3):
         self.colorQuantization[ord(comp[3 * i])] = {
             'Horz': ord(comp[3 * i + 1]) >> 4,
             'Vert': ord(comp[3 * i + 1]) & 0xf,
             'TableID': ord(comp[3 * i + 2])
         }
     return self.find_tag('SOF0')
Beispiel #6
0
    def decode_scandata(self):
        # init decode varible
        horzY = self.colorQuantization[1]['Horz']
        horzCr = self.colorQuantization[2]['Horz']
        horzCb = self.colorQuantization[3]['Horz']
        vertY = self.colorQuantization[1]['Vert']
        vertCr = self.colorQuantization[2]['Vert']
        vertCb = self.colorQuantization[3]['Vert']
        scanY = horzY * vertY
        scanCr = horzCr * vertCr
        scanCb = horzCb * vertCb
        LOGGER.log(
            CustomLoggingLevel.IMAGE_DEBUG,
            "scanY: %d, scanCr: %d, scanCb: %d." % (scanY, scanCr, scanCb))
        self.baseY = 0
        self.baseCr = 0
        self.baseCb = 0
        rowData = [[0, 0, 0] for i in range(self.width * self.height)]

        if vertCb != 1 or vertCr != 1 or horzCb != 1 or horzCr != 1:
            LOGGER.error(
                'Error in decode scan data, ONLY support vertCb==vertCr==horzCb==horzCr==1!'
            )
        else:
            LOGGER.log(CustomLoggingLevel.IMAGE_DEBUG,
                       'Start to decode scan data.')

        # calc block number
        hBlock = self.width / (horzY * 8)
        if self.width % (horzY * 8) != 0:
            hBlock += 1
        vBlock = self.height / (vertY * 8)
        if self.height % (vertY * 8) != 0:
            vBlock += 1

        widthIndex = 0
        heightIndex = 0
        unsualDataFlagRight = False
        unsualDataFlagBotton = False
        for vb in range(vBlock):
            for hb in range(hBlock):
                dataY = []
                dataCr = []
                dataCb = []
                [dataY, dataCr,
                 dataCb] = self.read_mcu_block(scanY, scanCr, scanCb, dataY,
                                               dataCr, dataCb)
                for i in range(vertY):
                    heightIndex = (vb * vertY + i) * 8
                    for j in range(horzY):
                        widthIndex = (hb * horzY + j) * 8
                        for k in range(8):
                            if heightIndex + k < self.height:
                                for l in range(8):
                                    if widthIndex + l < self.width:
                                        y = dataY[i * horzY + j][k * 8 + l]
                                        cr = dataCr[0][k * 8 + l]
                                        cb = dataCb[0][k * 8 + l]
                                        r = self.round(y + 1.402 * cr + 128)
                                        b = self.round(y + 1.772 * cb + 128)
                                        g = self.round(y - 0.34414 * cb -
                                                       0.71414 * cr + 128)
                                        rowData[(heightIndex + k) * self.width
                                                + widthIndex + l] = [r, g, b]
            LOGGER.info('Please wait, decoding ... (%d/%d)' % (vb, vBlock))
        self.clean_bitstream_remainder()
        if self.scanDataIndex < self.scanDataLength:
            self.showextradata(''.join(self.scanData[self.scanDataIndex:]),
                               self.scanDataPos + self.scanDataIndex)
        return rowData
Beispiel #7
0
    def __init__(self, file_object):
        # file_object.addHandler(logging.StreamHandler())
        self.fileObject = file_object
        if file_object.read(3) != 'GIF':
            LOGGER.error("File is not a gif file")
        self.type = "GIF"
        self.version = file_object.read(3)
        if self.version != '87a' and self.version != '89a':
            LOGGER.log(CustomLoggingLevel.OTHER_DATA, "Invalid version")
        else:
            LOGGER.log(CustomLoggingLevel.BASIC_DEBUG,
                       "version is " + self.version)
        self.logicScreenWidth = file_object.read_uint16()
        self.logicScreenHeight = file_object.read_uint16()
        mask = file_object.read_uint8()
        self.pixel = mask & 0b111
        mask >>= 3
        self.sortFlag = mask & 0b1
        mask >>= 1
        self.colorResolution = mask & 0b111
        mask >>= 3
        self.globalColorTableFlag = mask & 0b1
        if self.version == "89a":
            self.backgroundColorIndex = file_object.read_uint8()
            self.pixelAspectRatio = file_object.read_uint8()
        # self.globalColorTable = [[0, 0, 0]] * (2 ** (self.pixel + 1))
        if self.globalColorTableFlag:
            self.globalColorTable = [[0, 0, 0]
                                     for _ in range(2**(self.pixel + 1))]
        else:
            self.globalColorTable = []

        LOGGER.log(CustomLoggingLevel.OTHER_DATA,
                   "global table size is %d" % len(self.globalColorTable))

        for i in range(len(self.globalColorTable)):

            for j in range(3):  # 0 red 1 green 2 blue
                self.globalColorTable[i][j] = file_object.read_uint8()
        self.images = []
        image = {}
        while True:
            tag = file_object.read_uint8()

            if tag == 0x3b:
                LOGGER.log(CustomLoggingLevel.OTHER_DATA, "gif end")
                break  # end of gif

            if tag == 0x2c:  # start of a image descriptor
                # LOGGER.info("image descriptor")
                LOGGER.log(CustomLoggingLevel.IMAGE_DEBUG, "image descriptor")
                image["xOffset"] = file_object.read_uint16()
                image["yOffset"] = file_object.read_uint16()

                image["width"] = file_object.read_uint16()
                image["height"] = file_object.read_uint16()

                if image["xOffset"] + image["width"] > self.logicScreenWidth or \
                   image["yOffset"] + image["height"] > self.logicScreenHeight:
                    LOGGER.log(
                        CustomLoggingLevel.OTHER_DATA,
                        "some part out of logic screen at image %d" %
                        len(self.images) + 1)

                mask = file_object.read_uint8()
                image["pixel"] = mask & 0b111
                mask >>= 3
                image["reserved"] = mask & 0b11
                if image["reserved"] != 0:
                    LOGGER.log(
                        CustomLoggingLevel.OTHER_DATA,
                        "[0x%x] reserved data should be 0" %
                        self.fileObject.cur())
                mask >>= 2
                image["sortFlag"] = mask & 0b1
                mask >>= 1
                image["interlaceFlag"] = mask & 0b1
                mask >>= 1
                image["localColorTableFlag"] = mask & 0b1
                if image["localColorTableFlag"]:
                    image["localColorTable"] = [
                        [0, 0, 0] for _ in xrange((2**(image["pixel"] + 1)))
                    ]
                    for i in range(len(image["localColorTable"])):
                        for j in range(3):  # 0 red 1 green 2 blue
                            image["localColorTable"][i][
                                j] = file_object.read_uint8()
            elif tag == 0x21:
                if self.version != "89a":
                    LOGGER.log(CustomLoggingLevel.OTHER_DATA,
                               "not version 89a but has extension segment.")
                sub_tag = file_object.read_uint8()
                if sub_tag == 0xF9:  # Graphic Control Extension.
                    LOGGER.log(CustomLoggingLevel.IMAGE_DEBUG,
                               "Graphic Control Extension")
                    block_size = file_object.read_uint8()
                    if block_size != 4:
                        LOGGER.log(
                            CustomLoggingLevel.OTHER_DATA,
                            "block size is not 4 in Graphic Control Extension")
                    control = {}
                    mask = file_object.read_uint8()
                    control["transparentFlag"] = mask & 0b1
                    mask >>= 1
                    control["userInputFlag"] = mask & 0b1
                    mask >>= 1
                    control["disposalMethod"] = mask & 0b111
                    # 0 -   No disposal specified. The decoder is
                    # not required to take any action.
                    # 1 -   Do not dispose. The graphic is to be left
                    # in place.
                    # 2 -   Restore to background color. The area used by the
                    #           graphic must be restored to the background color.
                    #     3 -   Restore to previous. The decoder is required to
                    #           restore the area overwritten by the graphic with
                    #           what was there prior to rendering the graphic.
                    #  4-7 -    To be defined.
                    control["delayTime"] = file_object.read_uint16()
                    control["TransparentColonrIndex"] = file_object.read_uint8(
                    )
                    terminator = file_object.read_uint8()
                    if terminator != 0:
                        LOGGER.log(
                            CustomLoggingLevel.OTHER_DATA,
                            "[0x%x] terminator in block Graphic Control Extension is not 0"
                            % self.fileObject.cur())
                    image["control"] = control
                elif sub_tag == 0xFE:  # Comment Extension.
                    LOGGER.log(CustomLoggingLevel.IMAGE_DEBUG,
                               "Comment Extension.")
                    if "comment" not in image:
                        image["comment"] = ""
                    while True:
                        tmp = file_object.read(1)
                        if tmp == '\0':
                            break
                        image["comment"] += tmp
                    LOGGER.log(CustomLoggingLevel.ASCII_DATA, image["comment"])
                elif sub_tag == 0x01:  # plain text Extension
                    LOGGER.log(CustomLoggingLevel.IMAGE_DEBUG,
                               "plain text Extension")
                    block_size = file_object.read_uint8()
                    if block_size != 12:
                        LOGGER.warning("block size is not 12 in plain text")
                    text = {
                        "gridLeftPosition": file_object.read_uint16(),
                        "gridTopPosition": file_object.read_uint16(),
                        "textGridWidth": file_object.read_uint16(),
                        "textGridHeight": file_object.read_uint16(),
                        "characterCellWidth": file_object.read_uint8(),
                        "characterCellHeight": file_object.read_uint8(),
                        "textForegroundColorIndex": file_object.read_uint8(),
                        "textBackgroundColorIndex": file_object.read_uint8(),
                        "data": ""
                    }
                    while True:
                        tmp = file_object.read(1)
                        if tmp == '\0':
                            break
                        text["data"] += tmp
                    if "text" in image:
                        LOGGER.log(CustomLoggingLevel.OTHER_DATA,
                                   "text already in image")
                    image["text"] = text
                    LOGGER.log(CustomLoggingLevel.ASCII_DATA, image["text"])
                elif sub_tag == 0xFF:  # Application Extension.
                    LOGGER.log(CustomLoggingLevel.IMAGE_DEBUG,
                               "Application Extension.")
                    block_size = file_object.read_uint8()
                    if block_size != 11:
                        LOGGER.log(
                            CustomLoggingLevel.OTHER_DATA,
                            "[0x%x] block size is not 11 in application extension"
                            % self.fileObject.cur())
                    application = {
                        "identifier": file_object.read(8),
                        "authenticationCode": file_object.read(3)
                    }
                    data_size = file_object.read_uint8()
                    application["data"] = file_object.read(data_size)

                    if "application" in image:
                        LOGGER.log(CustomLoggingLevel.OTHER_DATA,
                                   "application Extension already in image")

                    image["application"] = application
                    terminator = file_object.read_uint8()
                    if terminator != 0:
                        LOGGER.log(
                            CustomLoggingLevel.OTHER_DATA,
                            "terminator is not 0 in Application Extension")
                else:
                    LOGGER.log(
                        CustomLoggingLevel.IMAGE_DEBUG,
                        "[0x%x] unknown extension at" % self.fileObject.cur())
            else:  # DATA
                # LOGGER.info("DATA")
                LOGGER.log(CustomLoggingLevel.IMAGE_DEBUG, "DATA")
                image["LZWMinimumCodeSize"] = tag

                image["data"] = []
                while True:
                    data_size = file_object.read_uint8()

                    if data_size == 0:
                        break
                    data = file_object.read(data_size)
                    image["data"] += data
                self.images.append(image)
                image = {}
Beispiel #8
0
    def start(self):
        self.version = struct.unpack('h', self.fileObject.read(2))[0]
        if self.version == 0:
            # ver 1
            # read file header
            self.version = 1
            self.width, self.height, self.rowDataLength = struct.unpack(
                '3h', self.fileObject.read(6))
            self.channel = ord(struct.unpack('b', self.fileObject.read(1))[0])
            self.bitsPerPixel = ord(
                struct.unpack('b', self.fileObject.read(1))[0])
            self.headerLength = 10

        elif self.version == 0x4D42:
            # ver 2  3  4
            # read file header
            self.length = struct.unpack('i', self.fileObject.read(4))[0]
            if self.fileObject.read(
                    4) != '\x00\x00\x00\x00':  # reserved always 0
                LOGGER.log(
                    CustomLoggingLevel.OTHER_DATA,
                    '[0x%x] File header reserved options is not 0' %
                    (self.fileObject.cur() - 4))
            bitmapOffset = struct.unpack('i', self.fileObject.read(4))[0]

            # read bitmap header
            bitmapHeaderLength = struct.unpack('l', self.fileObject.read(4))[0]

            if bitmapHeaderLength == 12:
                # ver 2
                self.version = 2
                self.width, self.height, self.channel, self.bitsPerPixel = struct.unpack(
                    '4h', self.fileObject.read(8))
                self.headerLength = 26
            elif bitmapHeaderLength == 40:
                # ver 3
                self.version = 3
                self.width, self.height, self.channel, self.bitsPerPixel = struct.unpack(
                    '2l2h', self.fileObject.read(12))
                self.compressionMethod, self.bitmapLength = struct.unpack(
                    '2L', self.fileObject.read(8))
                self.fileObject.read(16)  # skip useless header
                self.headerLength = 53
            elif bitmapHeaderLength == 108:
                # ver 4
                self.version = 4
            else:
                LOGGER.error('[0x%x] Unknown BMP file version.' %
                             (self.fileObject.cur() - 4))

            if self.version != 0x4D42:
                # calculate number of entries
                if self.bitsPerPixel < 24:
                    self.numberOfEntries = 1 << self.bitsPerPixel
                else:
                    self.numberOfEntries = 0

                # read color palette
                self.colorPalette = []
                if self.version == 3 and self.compressionMethod == 3:
                    self.fileObject.read(12 * self.numberOfEntries)
                else:
                    for i in range(self.numberOfEntries):
                        self.headerLength += 4
                        t = self.fileObject.read(4)
                        self.colorPalette.append(t[2] + t[1] + t[0] + t[3])
                        if t[3] != '\x00':
                            LOGGER.log(
                                CustomLoggingLevel.OTHER_DATA,
                                '[0x%x] Color palette reserved option(alpha channel) is not 0, is 0x%x!'
                                % (self.fileObject.cur() - 4, ord(t[3])))
        else:
            LOGGER.error('Magic value BM check failed.')

        self.padding = self.width * self.bitsPerPixel % 32
        if self.padding != 0:
            self.padding = 32 - self.padding
        self.rowDataLength = (self.width * self.bitsPerPixel +
                              self.padding) * self.height / 8
        LOGGER.log(
            CustomLoggingLevel.IMAGE_INFO,
            'BMP(ver %d): %d*%dpx , channel: %d, fileLength: 0x%x(0x%x) b, headerLength: %d b, rowDataLength: %d b'
            % (self.version, self.width, self.height, self.channel,
               self.fileObject.size, self.headerLength + self.rowDataLength,
               self.headerLength, self.rowDataLength))

        if self.channel != 1:
            LOGGER.log(CustomLoggingLevel.IMAGE_INFO,
                       'Warning: bmpfile channel is NOT 1!')
Beispiel #9
0
    def rowdata_ver23(self):
        rowData = []
        if self.compressionMethod != 0:
            # decompress bitmap data according to compression method
            if self.bitmapLength == 0:
                LOGGER.warning(
                    'BitmapLength shouldn\'t be 0 in bitmap header! There may have some extra data in end of the file.'
                )
                tdata = self.fileObject.read(self.fileObject.size -
                                             self.headerLength)
            else:
                tdata = self.fileObject.read(self.bitmapLength)
            # decompress
            data = []
            if self.compressionMethod == 1:
                specialFlag = -1
                for i in range(len(tdata)):
                    if specialFlag < 0:
                        if specialFlag == -1:
                            if tdata[i] == '\x00':
                                pass  # end of line
                            elif tdata == '\x01':
                                break  # end of RLE data
                            elif tdata[i] == '\x02':
                                data.append('\x00' *
                                            (ord(tdata[i + 1]) +
                                             self.width * ord(tdata[i + 2])) *
                                            self.bitsPerPixel / 8)
                            else:
                                specialFlag = ord(tdata[i]) + 1
                        specialFlag -= 1
                        if specialFlag == -3:
                            specialFlag = 0
                    elif specialFlag == 0:
                        if tdata[i] == '\x00':
                            specialFlag = -1
                    elif specialFlag > 1:
                        data.append(tdata[i])
                        specialFlag -= 1
                    else:
                        specialFlag -= 1
                if i < len(tdata) - 1:
                    self.showextradata(tdata[i:len(tdata) - 1],
                                       self.headerLength + i)
                data = ''.join(data)
            elif self.compressionMethod == 2:
                LOGGER.error(
                    'Compress method RLE4 of BMP file version 3 is not surported.'
                )
                return
            elif self.compressionMethod == 3:
                LOGGER.error(
                    'Compress method using RGB mask of BMP file version 3 is not surported.'
                )
                return
        else:
            data = self.fileObject.read(self.rowDataLength)

        if self.compressionMethod == 0 and self.bitmapLength != 0:
            LOGGER.warning(
                'BitmapLength should be 0 in bitmap header! Image pixel may be processed with wrong compress method!'
            )
        if self.bitsPerPixel in [1, 4, 8, 24, 32]:
            # return row data from stream
            if self.bitsPerPixel == 24:
                self.channel = 3
            else:
                self.channel = 4
            return self.decode_rgb_data(data)
        else:
            LOGGER.error(
                'BMP file bits per pixel is not in (1, 4, 8, 24, 32).')
Beispiel #10
0
 def rowdata_ver4(self):
     LOGGER.error('BMP file version 4 is not surported.')
Beispiel #11
0
 def rowdata_ver1(self):
     if self.fileObject.size - self.rowDataLength - 10 > 10 * (
             1 - detectSensitive):
         LOGGER.log(CustomLoggingLevel.EXTRA_DATA,
                    'Some extra data may in end of the file.')
     LOGGER.error('BMP file version 1 is not surported.')