def fromBytes(self,data,index=0): """ decode a byte buffer :param data: data buffer to decode :param index: index within the buffer to start at """ io=IO(data,index,boolSize=32) print(io.data[0:50]) self.name=io.sz754 self.uniqueId=io.u32 self.visible=io.bool self.linked=io.bool numParasites=io.u32 numStrokes=io.u32 raise Exception('Parasites=%d Strokes=%d'%(numParasites,numStrokes)) for _ in range(numParasites): p=GimpParasite() io.index=p.fromBytes(io.data,io.index) self.parasites.append(p) for _ in range(numStrokes): gs=GimpStroke(self) io.index=gs.fromBytes(io.data,io.index) self.strokes.append(p) return io.index
def _parasitesEncode_(self): """ encode list of parasites """ io=IO() for parasite in self.parasites: io.addBytes(parasite.toBytes()) return io.data
def _propertiesEncode_(self): """ encode a list of properties """ io=IO() for propertyType in range(1,self.PROP_NUM_PROPS): moData=self._propertyEncode_(propertyType) if moData: io.addBytes(moData) return io.data
def _pointerEncode_(self,ptr,io=None)->bytearray: if not isinstance(ptr,int): raise Exception('pointer is wrong type = '+str(type(ptr))) if io is None: io=IO() if self._POINTER_SIZE_==64: io.u64=ptr else: io.u32=ptr return io.data
def fromBytes(self,data:Union[bytes,bytearray],index:int=0)->int: """ decode a byte buffer :param data: data buffer to decode :param index: index within the buffer to start at """ if not data: #raise Exception('No data!') print("WARN: No image data!") return 0 io=IO(data,index) #print('Decoding channel at',index) self.width=io.u32 self.height=io.u32 self.bpp=io.u32 if self.bpp<1 or self.bpp>4: msg="""'Unespected bytes-per-pixel for image data ("""+str(self.bpp)+"""). Probably means file corruption.""" raise Exception(msg) while True: ptr=self._pointerDecode_(io) if ptr==0: break self._levelPtrs.append(ptr) if self._levelPtrs: # remove "dummy" level pointers self._levelPtrs=[self._levelPtrs[0]] self._data=bytearray(data) return io.index
def fromBytes(self,data,index=0,numFloatsPerPoint=0): """ decode a byte buffer :param data: data buffer to decode :param index: index within the buffer to start at :param numFloatsPerPoint: required so we know how many different brush dynamic measurements are inside each point """ io=IO(data,index,boolSize=32) self.pressure=1.0 self.xTilt=0.5 self.yTilt=0.5 self.wheel=0.5 self.pointType=io.u32 if numFloatsPerPoint<1: numFloatsPerPoint=(len(io.data)-io.index)/4 self.x=io.float self.y=io.float if numFloatsPerPoint>2: self.pressure=io.float if numFloatsPerPoint>3: self.xTilt=io.float if numFloatsPerPoint>4: self.yTilt=io.float if numFloatsPerPoint>5: self.wheel=io.float return io.index
def fromBytes(self,data:bytes,index:int=0): """ decode a byte buffer :param data: data buffer to decode :param index: index within the buffer to start at """ io=IO(data,index,boolSize=32) self.strokeType=io.u32 self.closedShape=io.bool self.numFloatsPerPoint=io.u32 self.numPoints=io.u32 for _ in range(self.numPoints): gp=GimpPoint(self) io.index=gp.fromBytes(io.data,io.index,self.numFloatsPerPoint) self.points.append(gp) return io.index
def _decode_(self, data: bytes, index: int = 0): """ decode a byte buffer :param data: data buffer to decode :param index: index within the buffer to start at """ io = IO(data, index) if io.getBytes(9) != "gimp xcf ".encode('ascii'): raise Exception('Not a valid GIMP file') version = io.cString if version == 'file': self.version = 0 else: self.version = int(version[1:]) self.width = io.u32 self.height = io.u32 self.baseColorMode = io.u32 self.precision = Precision() self.precision.decode(self.version, io) self._propertiesDecode_(io) self._layerPtr = [] self._layers = [] while True: ptr = self._pointerDecode_(io) if ptr == 0: break self._layerPtr.append(ptr) l = GimpLayer(self) l._decode_(io.data, ptr) self._layers.append(l) self._channelPtr = [] self.channels = [] while True: ptr = self._pointerDecode_(io) if ptr == 0: break self._channelPtr.append(ptr) c = GimpChannel(self) c.fromBytes(io.data, ptr) self.channels.append(c) return io.index
def _decode_(self, data: bytes, index: int = 0) -> None: """ decode a byte buffer :param data: data buffer to decode :param index: index within the buffer to start at """ io = IO(data, index) headerSize = io.u32 self.version = io.u32 self.width = io.u32 self.height = io.u32 self.bpp = io.u32 self.mode = self.COLOR_MODES[self.bpp] magic = io.getBytes(4) if magic.decode('ascii') != 'GPAT': raise Exception('File format error. Magic value mismatch.') nameLen = headerSize - io.index self.name = io.getBytes(nameLen).decode('UTF-8') self._rawImage = io.getBytes(self.width * self.height * self.bpp) self._image = None
def toBytes(self)->bytes: """ encode this object to a byte buffer """ io=IO() io.u32=self.width io.u32=self.height io.sz754=self.name io.addBytes(self._propertiesEncode_()) ih=self._imageHierarchyPtr if ih is None: ih=0 io.addBytes(self._pointerEncode_(ih)) return io.data
def toBytes(self): """ encode this object to a byte array """ io = IO() io.addBytes(self.brush.toBytes()) io.addBytes(self.pattern.toBytes()) return io.data
def toBytes(self): """ encode to binary data """ io=IO(boolSize=32) io.u32=self.strokeType io.bool=self.closedShape io.u32=self.numFloatsPerPoint io.u32=self.numPoints for gp in self.points: io.addBytes(gp.toBytes()) return io.data
def _propertiesDecode_(self,io: IO) -> int: """ decode a list of properties """ while True: try: propertyType=io.u32 dataLength=io.u32 except struct.error: # end of data, so that's that. break if propertyType==0: break self._propertyDecode_(propertyType,io.getBytes(dataLength)) return io.index
def toBytes(self): """ convert this object to raw bytes """ io=IO() io.float32=self.factor io.u32=self.numDigits io.sz754=self.id io.sz754=self.symbol io.sz754=self.abbrev io.sz754=self.sname io.sz754=self.pname return io.data
def toBytes(self): """ encode to binary data """ io=IO(boolSize=32) io.u32=self.pointType io.float=self.x io.float=self.y if self.pressure is not None: io.float=self.pressure if self.xTilt is not None: io.float=self.xTilt if self.yTilt is not None: io.float=self.yTilt if self.wheel is not None: io.float=self.wheel return io.data
def fromBytes(self,data:bytes,index:int=0)->int: """ decode a byte buffer :param data: data buffer to decode :param index: index within the buffer to start at """ io=IO(data,index) #print('Decoding channel at',index) self.width=io.u32 self.height=io.u32 self.name=io.sz754 self._propertiesDecode_(io) self._imageHierarchyPtr=self._pointerDecode_(io) self._data=io.data return io.index
def fromBytes(self,data,index=0): """ decode a byte buffer :param data: data buffer to decode :param index: index within the buffer to start at """ io=IO(data,index) self.factor=io.float32 self.numDigits=io.u32 self.id=io.sz754 self.symbol=io.sz754 self.abbrev=io.sz754 self.sname=io.sz754 self.pname=io.sz754 return io.index
def _decode_(self, data, index=0): """ decode a byte buffer :param data: data buffer to decode :param index: index within the buffer to start at """ io = IO(data, index) #print('Decoding Layer at',index) self.width = io.u32 self.height = io.u32 self.colorMode = io.u32 # one of self.COLOR_MODES self.name = io.sz754 self._propertiesDecode_(io) self._imageHierarchyPtr = self._pointerDecode_(io) self._maskPtr = self._pointerDecode_(io) self._mask = None self._data = data return io.index
def toBytes(self) -> bytearray: """ encode this object to a byte array """ io = IO() io.textLine = self.name # add the second line of data secondLine = [str(len(self.brushes))] for k, v in self.params.items(): secondLine.append(k + ':' + str(v)) secondLine = ' '.join(secondLine) io.textLine = secondLine # add the brushes for brush in self.brushes: #TODO: currently broken. This results in header insterted twice for some reason! io.addBytes(brush.toBytes()) return io.data
def fromBytes(self,data:Union[bytes,bytearray],index:int=0): """ decode a byte buffer :param data: data buffer to decode :param index: index within the buffer to start at """ io=IO(data,index) #print('Decoding image level at',io.index) self.width=io.u32 self.height=io.u32 if self.width!=self.parent.width or self.height!=self.parent.height: currentSize='('+str(self.width)+','+str(self.height)+')' expectedSize='('+str(self.parent.width)+','+str(self.parent.height)+')' msg=' Usually this implies file corruption.' raise Exception('Image data size mismatch. '+currentSize+'!='+expectedSize+msg) self._tiles=[] self._image=None for y in range(0,self.height,64): for x in range(0,self.width,64): ptr=self._pointerDecode_(io) size=(min(self.width-x,64),min(self.height-y,64)) totalBytes=size[0]*size[1]*self.bpp if self.doc.compression==0: # none data=io.data[ptr:ptr+totalBytes] elif self.doc.compression==1: # RLE data=self._decodeRLE(io.data,size[0]*size[1],self.bpp,ptr) elif self.doc.compression==2: # zip # guess how many bytes are needed data=zlib.decompress(io.data[ptr:ptr+totalBytes+24]) else: raise Exception('ERR: unsupported compression mode %s'%self.doc.compression) subImage=PIL.Image.frombytes(self.mode,size,bytes(data),decoder_name='raw') self._tiles.append(subImage) _=self._pointerDecode_(io) # list ends with nul character return io.index
def _decode_(self, data: bytes, index: int = 0) -> int: """ decode a byte buffer :param data: data buffer to decode :param index: index within the buffer to start at """ io = IO(data, index) self.name = io.textLine secondLine = io.textLine.split(' ') self.params = OrderedDict() numBrushes = int(secondLine[0]) # everything that's left in line 2 is a gimp-image-pipe-parameters parasite for i in range(1, len(secondLine)): param = secondLine[i].split(':', 1) self.params[param[0].strip()] = param[1].strip() self.brushes = [] for _ in range(numBrushes): b = GimpGbrBrush() # NOTE: expects GimpGbrBrush._decode_ to be the number of bytes read # I don't know whether this is right, wrong, or sideways, but there you have it io.index += b._decode_(io.data, io.index) self.brushes.append(b) return io.index
def toBytes(self) -> bytearray: """ encode to a byte buffer """ io = IO() io.u32 = 24 + len(self.name) io.u32 = self.version io.u32 = self.width io.u32 = self.height io.u32 = len(self.image.mode) io.addBytes('GPAT') io.addBytes(self.name.encode('utf-8')) if self._rawImage is None: rawImage = self.image.tobytes(encoder_name='raw') else: rawImage = self._rawImage io.addBytes(rawImage) return io.data
def toBytes(self): """ encode to binary data """ io=IO(boolSize=32) io.sz754=self.name io.u32=self.uniqueId io.bool=self.visible io.bool=self.linked io.u32=len(self.parasites) io.u32=len(self.strokes) for p in self.parasites: io.addBytes(p.toBytes()) for gs in self.strokes: io.addBytes(gs.toBytes()) return io.data
def toBytes(self)->bytearray: """ encode this object to a byte buffer """ dataIO=IO() io=IO() io.u32=self.width io.u32=self.height tiles=self.tiles if tiles is not None: dataIndex=io.index+self._POINTER_SIZE_*(len(tiles)+1) for tile in tiles: io.addBytes(self._pointerEncode_(dataIndex+dataIO.index)) data=tile.tobytes() if self.doc.compression==0: # none pass elif self.doc.compression==1: # RLE data=self._encodeRLE(data,self.bpp) elif self.doc.compression==2: # zip data=zlib.compress(data) else: raise Exception('ERR: unsupported compression mode '+str(self.doc.compression)) dataIO.addBytes(data) io.addBytes(self._pointerEncode_(0)) io.addBytes(dataIO.data) return io.data
def toBytes(self)->bytearray: """ encode this object to a byte buffer """ dataIO=IO() io=IO() io.u32=self.width io.u32=self.height io.u32=self.bpp levels=self.levels if levels is not None: dataIndex=io.index+self._POINTER_SIZE_*(len(levels)+1) for level in levels: io.addBytes(self._pointerEncode_(dataIndex+io.index)) dataIO.addBytes(level.toBytes()) io.addBytes(self._pointerEncode_(0)) io.addBytes(dataIO.data) return io.data
def _propertyDecode_(self,propertyType: int,data: bytearray) -> int: """ decode a single property """ io=IO(data,boolSize=32) #print('DECODING PROPERTY',propertyType,len(data)) if propertyType==self.PROP_COLORMAP: self._colormapDecode_(io) elif propertyType==self.PROP_ACTIVE_LAYER: self.selected=True elif propertyType==self.PROP_ACTIVE_CHANNEL: self.selected=True elif propertyType==self.PROP_SELECTION: self.isSelection=True elif propertyType==self.PROP_FLOATING_SELECTION: self.selectionAttachedTo=io.u32 elif propertyType==self.PROP_OPACITY: self.opacity=io.u32 elif propertyType==self.PROP_MODE: self.blendMode=io.u32 elif propertyType==self.PROP_VISIBLE: self.visible=True elif propertyType==self.PROP_LINKED: self.isLinked=io.bool elif propertyType==self.PROP_LOCK_ALPHA: self.lockAlpha=io.bool elif propertyType==self.PROP_APPLY_MASK: self.applyMask=io.bool elif propertyType==self.PROP_EDIT_MASK: self.editingMask=io.bool elif propertyType==self.PROP_SHOW_MASK: self.showMask=io.bool elif propertyType==self.PROP_SHOW_MASKED: self.showMasked=io.bool elif propertyType==self.PROP_OFFSETS: self.xOffset=io.i32 self.yOffset=io.i32 elif propertyType==self.PROP_COLOR: r=io.byte g=io.byte b=io.byte self.color=(r,g,b) elif propertyType==self.PROP_COMPRESSION: self.compression=io.byte elif propertyType==self.PROP_GUIDES: self._guidelinesDecode_(data) elif propertyType==self.PROP_RESOLUTION: self.horizontalResolution=io.float32 self.verticalResolution=io.float32 elif propertyType==self.PROP_TATTOO: self.uniqueId=data.hex() elif propertyType==self.PROP_PARASITES: self._parasitesDecode_(data) elif propertyType==self.PROP_UNIT: self.units=io.u32 elif propertyType==self.PROP_PATHS: numPaths=io.u32 for _ in range(numPaths): nRead,path=self._itemPathDecode_(data[io.index:]) self.paths.append(path) io.index+=nRead elif propertyType==self.PROP_USER_UNIT: self._userUnitsDecode_(data) elif propertyType==self.PROP_VECTORS: self._vectorsDecode_(data) elif propertyType==self.PROP_TEXT_LAYER_FLAGS: self.textLayerFlags=int(data) elif propertyType==self.PROP_OLD_SAMPLE_POINTS: raise Exception("ERR: old sample points structure not supported") elif propertyType==self.PROP_LOCK_CONTENT: self.locked=io.bool elif propertyType==self.PROP_GROUP_ITEM: self.isGroup=True elif propertyType==self.PROP_ITEM_PATH: self._itemPathDecode_(data) elif propertyType==self.PROP_GROUP_ITEM_FLAGS: self.groupItemFlags=io.u32 elif propertyType==self.PROP_LOCK_POSITION: self.positionLocked=io.bool elif propertyType==self.PROP_FLOAT_OPACITY: self.opacity=io.float32 elif propertyType==self.PROP_COLOR_TAG: self.colorTag=io.u32 elif propertyType==self.PROP_COMPOSITE_MODE: self.compositeMode=io.i32 elif propertyType==self.PROP_COMPOSITE_SPACE: self.compositeSpace=io.i32 elif propertyType==self.PROP_BLEND_SPACE: self.blendSpace=io.u32 elif propertyType==self.PROP_FLOAT_COLOR: r=io.float32 g=io.float32 b=io.float32 self.color=(r,g,b) elif propertyType==self.PROP_SAMPLE_POINTS: self._samplePointsDecode_(data) else: raise Exception('Unknown property id '+str(propertyType)) return io.index
def toBytes(self): """ encode to byte array """ dataAreaIO = IO() io = IO() io.u32 = self.width io.u32 = self.height io.u32 = self.colorMode io.sz754 = self.name dataAreaIndex = io.index + self._POINTER_SIZE_ * 2 io.addBytes(self._pointerEncode_(dataAreaIndex)) dataAreaIO.addBytes(self._propertiesEncode_()) io.addBytes(self._pointerEncode_(dataAreaIndex)) if self.mask is not None: dataAreaIO.addBytes(self.mask.toBytes()) io.addBytes(self._pointerEncode_(dataAreaIndex + dataAreaIO.index)) io.addBytes(dataAreaIO) return io.data
def toBytes(self) -> bytes: """ encode to a byte array """ io = IO() io.addBytes("gimp xcf ") io.addBytes(str(self.version) + '\0') io.u32 = self.width io.u32 = self.height io.u32 = self.baseColorMode if self.precision is None: self.precision = Precision() self.precision.encode(self.version, io) io.addBytes(self._propertiesEncode_()) dataAreaIdx = io.index + self._POINTER_SIZE_ * (len(self.layers) + len(self.channels)) dataAreaIo = IO() for layer in self.layers: io.pointer = dataAreaIdx + dataAreaIo.index dataAreaIo.addBytes(layer.toBytes()) for channel in self.channels: io.pointer = dataAreaIdx + dataAreaIo.index dataAreaIo.addBytes(channel.toBytes()) return io.data
def _propertyEncode_(self,propertyType): """ encode a single property If the property is the same as the default, or not specified, returns empty array """ io=IO(boolSize=32) if propertyType==self.PROP_COLORMAP: if self.colorMap is not None and self.colorMap: io.u32=self.PROP_COLORMAP io.addBytes(self._colormapEncode_()) elif propertyType==self.PROP_ACTIVE_LAYER: if self.selected is not None and self.selected: io.u32=self.PROP_ACTIVE_LAYER elif propertyType==self.PROP_ACTIVE_CHANNEL: if self.selected is not None and self.selected: io.u32=self.PROP_ACTIVE_LAYER elif propertyType==self.PROP_SELECTION: if self.isSelection is not None and self.isSelection: io.u32=self.PROP_SELECTION elif propertyType==self.PROP_FLOATING_SELECTION: if self.selectionAttachedTo is not None: io.u32=self.PROP_FLOATING_SELECTION io.u32=self.selectionAttachedTo elif propertyType==self.PROP_OPACITY: if self.opacity is not None and not isinstance(self.opacity,float): io.u32=self.PROP_OPACITY io.u32=self.opacity elif propertyType==self.PROP_MODE: if self.blendMode is not None: io.u32=self.PROP_MODE io.u32=self.blendMode elif propertyType==self.PROP_VISIBLE: if self.visible is not None and self.visible: io.u32=self.PROP_VISIBLE elif propertyType==self.PROP_LINKED: if self.isLinked is not None and self.isLinked: io.u32=self.PROP_LINKED io.bool=self.isLinked elif propertyType==self.PROP_LOCK_ALPHA: if self.lockAlpha is not None and self.lockAlpha: io.u32=self.PROP_LOCK_ALPHA io.bool=self.lockAlpha elif propertyType==self.PROP_APPLY_MASK: if self.applyMask is not None: io.u32=self.PROP_APPLY_MASK io.bool=self.applyMask elif propertyType==self.PROP_EDIT_MASK: if self.editingMask is not None and self.editingMask: io.u32=self.PROP_EDIT_MASK io.bool=self.editingMask elif propertyType==self.PROP_SHOW_MASK: if self.showMask is not None and self.showMask: io.u32=self.PROP_SHOW_MASK io.bool=self.showMask elif propertyType==self.PROP_SHOW_MASKED: if self.showMasked is not None: io.u32=self.PROP_SHOW_MASKED io.bool=self.showMasked elif propertyType==self.PROP_OFFSETS: if self.xOffset is not None and self.yOffset is not None: io.u32=self.PROP_OFFSETS io.i32=self.xOffset io.i32=self.yOffset elif propertyType==self.PROP_COLOR: if self.color is not None and not self.isFloatColor(self.color): io.u32=self.PROP_COLOR io.byte=self.color[0] io.byte=self.color[1] io.byte=self.color[2] elif propertyType==self.PROP_COMPRESSION: if self.compression is not None: io.u32=self.PROP_COMPRESSION io.u32=self.compression elif propertyType==self.PROP_GUIDES: if self.guidelines is not None and self.guidelines: io.u32=self.PROP_GUIDES io.addBytes(self._guidelinesEncode_()) elif propertyType==self.PROP_RESOLUTION: if self.horizontalResolution is not None and self.verticalResolution is not None: io.u32=self.PROP_RESOLUTION io.u32=self.horizontalResolution io.i32=self.verticalResolution elif propertyType==self.PROP_TATTOO: if self.uniqueId is not None: io.u32=int(self.uniqueId,16) elif propertyType==self.PROP_PARASITES: if self.parasites is not None and self.parasites: io.u32=self.PROP_PARASITES io.addBytes(self._parasitesEncode_()) elif propertyType==self.PROP_UNIT: if self.units is not None: io.u32=self.PROP_UNIT io.u32=self.units elif propertyType==self.PROP_PATHS: if self.paths is not None and self.paths: io.u32=self.PROP_PATHS io.u32=len(self.paths) for path in self.paths: io.addBytes(self._pathEncode_(path)) elif propertyType==self.PROP_USER_UNIT: if self.userUnits is not None: io.u32=self.PROP_USER_UNIT io.addBytes(self._userUnitsEncode_()) elif propertyType==self.PROP_VECTORS: if self.vectors is not None and self.vectors: io.u32=self.PROP_VECTORS io.addBytes(self._vectorsEncode_()) elif propertyType==self.PROP_TEXT_LAYER_FLAGS: if self.textLayerFlags is not None: io.u32=self.PROP_TEXT_LAYER_FLAGS io.u32=self.textLayerFlags elif propertyType==self.PROP_OLD_SAMPLE_POINTS: pass elif propertyType==self.PROP_LOCK_CONTENT: if self.locked is not None and self.locked: io.u32=self.PROP_LOCK_CONTENT io.bool=self.locked elif propertyType==self.PROP_GROUP_ITEM: if self.isGroup is not None and self.isGroup: io.u32=self.PROP_GROUP_ITEM elif propertyType==self.PROP_ITEM_PATH: if self.itemPath is not None: io.u32=self.PROP_ITEM_PATH io.addBytes(self._itemPathEncode_()) elif propertyType==self.PROP_GROUP_ITEM_FLAGS: if self.groupItemFlags is not None: io.u32=self.PROP_GROUP_ITEM_FLAGS io.u32=self.groupItemFlags elif propertyType==self.PROP_LOCK_POSITION: if self.positionLocked is not None and self.positionLocked: io.u32=self.PROP_LOCK_POSITION io.bool=self.positionLocked elif propertyType==self.PROP_FLOAT_OPACITY: if self.opacity is not None and isinstance(self.opacity,float): io.u32=self.PROP_FLOAT_OPACITY io.float32=self.opacity elif propertyType==self.PROP_COLOR_TAG: if self.colorTag is not None: io.u32=self.PROP_COLOR_TAG io.u32=self.colorTag elif propertyType==self.PROP_COMPOSITE_MODE: if self.compositeMode is not None: io.u32=self.PROP_COMPOSITE_MODE io.i32=self.compositeMode elif propertyType==self.PROP_COMPOSITE_SPACE: if self.compositeSpace is not None: io.u32=self.PROP_COMPOSITE_SPACE io.i32=self.compositeSpace elif propertyType==self.PROP_BLEND_SPACE: if self.blendSpace is not None: io.u32=self.PROP_BLEND_SPACE io.u32=self.blendSpace elif propertyType==self.PROP_FLOAT_COLOR: if self.color is not None and self.isFloatColor(self.color): io.u32=self.PROP_FLOAT_COLOR io.float32=self.color[0] io.float32=self.color[1] io.float32=self.color[2] elif propertyType==self.PROP_SAMPLE_POINTS: if self.samplePoints is not None and self.samplePoints: io.u32=self.PROP_SAMPLE_POINTS io.addBytes(self._samplePointsEncode_()) else: raise Exception('Unknown property id '+str(propertyType)) return io.data