def encode(self): """Encode to byte array. Steps: Create a new IO buffer (array of binary values) Set attributes as outlined in the spec List of properties Set the image hierarchy and mask pointers Return the data """ # Create a new IO buffer (array of binary values) dataAreaIO = IO() ioBuf = IO() # Set attributes as outlined in the spec ioBuf.u32 = self.width ioBuf.u32 = self.height ioBuf.u32 = self.colorMode ioBuf.sz754 = self.name # Layer properties ioBuf.addBytes(self._propertiesEncode()) # Pointer to the image heirachy structure dataAreaIndex = ioBuf.index + self.pointerSize * 2 ioBuf.addBytes(self._pointerEncode(dataAreaIndex)) dataAreaIO.addBytes(self.imageHierarchy.encode()) # ioBuf.addBytes(self._pointerEncode_(dataAreaIndex)) # Pointer to the layer mask if self.mask is not None: dataAreaIO.addBytes(self.mask.encode()) ioBuf.addBytes(self._pointerEncode(dataAreaIndex + dataAreaIO.index)) ioBuf.addBytes(dataAreaIO) # Return the data return ioBuf.data
def decode(self, data: bytes, index: int = 0) -> int: """Decode a byte buffer. Steps: Create a new IO buffer (array of binary values) Grab attributes as outlined in the spec List of properties Get the image hierarchy and mask pointers Return the offset Args: data (bytes): data buffer to decode index (int, optional): index within the buffer to start at]. Defaults to 0. Returns: int: offset """ # Create a new IO buffer (array of binary values) ioBuf = IO(data, index) # Grab attributes as outlined in the spec self.width = ioBuf.u32 self.height = ioBuf.u32 self.colorMode = ioBuf.u32 # one of self.COLOR_MODES self.name = ioBuf.sz754 # List of properties self._propertiesDecode(ioBuf) # Get the image hierarchy and mask pointers self._imageHierarchyPtr = self._pointerDecode(ioBuf) self._maskPtr = self._pointerDecode(ioBuf) self._mask = None self._data = data # Return the offset return ioBuf.index
def decode(self, data: bytes, index: int = 0) -> int: """Decode a byte buffer. Args: data (bytes): data buffer to decode index (int, optional): index within the buffer to start at. Defaults to 0. Raises: RuntimeError: "unknown brush version" RuntimeError: "File format error. Magic value mismatch" Returns: int: offset] """ ioBuf = IO(data, index) headerSize = ioBuf.u32 self.version = ioBuf.u32 if self.version != 2: raise RuntimeError(f"ERR: unknown brush version {self.version}") self.width = ioBuf.u32 self.height = ioBuf.u32 self.bpp = ioBuf.u32 # only allows grayscale or RGB self.mode = self.COLOR_MODES[self.bpp] magic = ioBuf.getBytes(4) if magic.decode("ascii") != "GIMP": raise RuntimeError('"' + magic.decode("ascii") + '" ' + str(index) + " File format error. Magic value mismatch.") self.spacing = ioBuf.u32 nameLen = headerSize - ioBuf.index self.name = ioBuf.getBytes(nameLen).decode("UTF-8") self.rawImage = ioBuf.getBytes(self.width * self.height * self.bpp) return ioBuf.index
def decode(self, data: bytes, index: int = 0) -> int: """Decode a byte buffer. Args: data (bytes): data buffer to decode index (int, optional): index within the buffer to start at. Defaults to 0. Returns: int: offset """ ioBuf = IO(data, index) self.name = ioBuf.textLine secondLine = ioBuf.textLine.split(" ") self.params = {} numBrushes = int(secondLine[0]) # everything that's left 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): brush = GimpGbrBrush() ioBuf.index = brush.decode( ioBuf.data, ioBuf.index ) # TODO: broken. For some reason there is extra data between brushes! self.brushes.append(brush) return ioBuf.index
def decode(self, data: bytes, index: int = 0, numFloatsPerPoint: int = 0): """Decode a byte buffer. Args: data (bytes): data buffer to decode index (int, optional): index within the buffer to start at. Defaults to 0. numFloatsPerPoint (int, optional): required so we know how many different brush dynamic measurements are inside each point. Defaults to 0. Returns: int: offset """ ioBuf = IO(data, index, boolSize=32) self.pressure = 1.0 self.xTilt = 0.5 self.yTilt = 0.5 self.wheel = 0.5 self.pointType = ioBuf.u32 if numFloatsPerPoint < 1: numFloatsPerPoint = int((len(ioBuf.data) - ioBuf.index) / 4) self.x = ioBuf.float32 self.y = ioBuf.float32 if numFloatsPerPoint > 2: self.pressure = ioBuf.float32 if numFloatsPerPoint > 3: self.xTilt = ioBuf.float32 if numFloatsPerPoint > 4: self.yTilt = ioBuf.float32 if numFloatsPerPoint > 5: self.wheel = ioBuf.float32 return ioBuf.index
def decode(self, data: bytes, index: int = 0) -> int: """Decode a byte buffer. Args: data (bytes): data buffer to decode index (int, optional): index within the buffer to start at. Defaults to 0. Returns: int: offset """ ioBuf = IO(data, index, boolSize=32) self.name = ioBuf.sz754 self.uniqueId = ioBuf.u32 self.visible = ioBuf.boolean self.linked = ioBuf.boolean numParasites = ioBuf.u32 numStrokes = ioBuf.u32 for _ in range(numParasites): parasite = GimpParasite() ioBuf.index = parasite.decode(ioBuf.data, ioBuf.index) self.parasites.append(parasite) for _ in range(numStrokes): gimpstroke = GimpStroke(self) ioBuf.index = gimpstroke.decode(ioBuf.data, ioBuf.index) self.strokes.append(gimpstroke) return ioBuf.index
def _propertiesEncode(self): """Encode a list of properties.""" ioBuf = IO() for propertyType in range(1, self.PROP_NUM_PROPS): moData = self._propertyEncode(propertyType) if moData: ioBuf.addBytes(moData) return ioBuf.data
def _pointerEncode(self, ptr: int, ioBuf: IO | None = None) -> bytearray: if ioBuf is None: ioBuf = IO() if self.pointerSize == 64: ioBuf.u64 = ptr else: ioBuf.u32 = ptr return ioBuf.data
def encode(self): """Encode to a byte array. Steps: Create a new IO buffer (array of binary values) The file is a valid gimp xcf Set the file version Set other attributes as outlined in the spec Set precision data using the class and ioBuf buffer List of properties Set the layers and add the pointers to them Set the channels and add the pointers to them Return the data """ # Create a new IO buffer (array of binary values) ioBuf = IO() # The file is a valid gimp xcf ioBuf.addBytes("gimp xcf ") # Set the file version ioBuf.addBytes(f"v{self.version:03d}\0") # Set other attributes as outlined in the spec ioBuf.u32 = self.width ioBuf.u32 = self.height ioBuf.u32 = self.baseColorMode # Set precision data using the class and ioBuf buffer if self.precision is None: self.precision = Precision() self.precision.encode(self.version, ioBuf) # List of properties ioBuf.addBytes(self._propertiesEncode()) dataAreaIdx = ioBuf.index + self.pointerSize * (len(self.layers) + len(self._channels)) dataAreaIO = IO() # Set the layers and add the pointers to them for layer in self.layers: ioBuf.index = dataAreaIdx + dataAreaIO.index dataAreaIO.addBytes(layer.encode()) # Set the channels and add the pointers to them for channel in self._channels: ioBuf.index = dataAreaIdx + dataAreaIO.index dataAreaIO.addBytes(channel.encode()) ioBuf.addBytes(dataAreaIO) # Return the data return ioBuf.data
def encode(self): """Encode to binary data.""" ioBuf = IO(boolSize=32) ioBuf.u32 = self.strokeType ioBuf.boolean = self.closedShape # ioBuf.u32 = numFloatsPerPoint # ioBuf.u32 = numPoints for gimpPoint in self.points: ioBuf.addBytes(gimpPoint.encode()) return ioBuf.data
def encode(self): """Convert this object to raw bytes.""" ioBuf = IO() ioBuf.float32 = self.factor ioBuf.u32 = self.numDigits ioBuf.sz754 = self.id ioBuf.sz754 = self.symbol ioBuf.sz754 = self.abbrev ioBuf.sz754 = self.sname ioBuf.sz754 = self.pname return ioBuf.data
def encode(self) -> bytearray: """Encode this object to a byte buffer.""" ioBuf = IO() ioBuf.u32 = self.width ioBuf.u32 = self.height ioBuf.sz754 = self.name ioBuf.addBytes(self._propertiesEncode()) imgH = self._imageHierarchyPtr if imgH is None: imgH = 0 ioBuf.addBytes(self._pointerEncode(imgH)) return ioBuf.data
def encode(self): """Encode a byte buffer :param data: data buffer to encode :param index: index within the buffer to start at """ ioBuf = IO() ioBuf.sz754 = self.name ioBuf.u32 = self.flags ioBuf.u32 = len(self.data) ioBuf.addBytes(self.data) return ioBuf.data
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 """ ioBuf = IO(data, index) self.name = ioBuf.sz754 self.flags = ioBuf.u32 dataLength = ioBuf.u32 self.data = ioBuf.getBytes(dataLength) return ioBuf.index
def encode(self) -> bytearray: """Encode this object to byte array.""" ioBuf = IO() ioBuf.u32 = 28 + len(self.name) ioBuf.u32 = self.version ioBuf.u32 = self.width ioBuf.u32 = self.height ioBuf.u32 = self.bpp ioBuf.addBytes("GIMP") ioBuf.u32 = self.spacing ioBuf.addBytes(self.name) ioBuf.addBytes(self.rawImage) return ioBuf.data
def encode(self): """Encode this object to a byte array.""" ioBuf = IO() ioBuf.textLine = self.name # add the second line of data secondLine = [str(len(self.brushes))] for key, value in self.params.items(): secondLine.append(f"{key}:{value}") ioBuf.textLine = " ".join(secondLine) # add the brushes for brush in self.brushes: ioBuf.addBytes(brush.encode()) return ioBuf.data
def encode(self): """Encode to binary data.""" ioBuf = IO(boolSize=32) ioBuf.sz754 = self.name ioBuf.u32 = self.uniqueId ioBuf.boolean = self.visible ioBuf.boolean = self.linked ioBuf.u32 = len(self.parasites) ioBuf.u32 = len(self.strokes) for parasite in self.parasites: ioBuf.addBytes(parasite.encode()) for gimpstroke in self.strokes: ioBuf.addBytes(gimpstroke.encode()) return ioBuf.data
def encode(self): """Encode to binary data.""" ioBuf = IO(boolSize=32) ioBuf.u32 = self.pointType ioBuf.float32 = self.x ioBuf.float32 = self.y if self.pressure is not None: ioBuf.float32 = self.pressure if self.xTilt is not None: ioBuf.float32 = self.xTilt if self.yTilt is not None: ioBuf.float32 = self.yTilt if self.wheel is not None: ioBuf.float32 = self.wheel return ioBuf.data
def decode(self, data: bytes, index: int = 0) -> int: """Decode a byte buffer. Args: data (bytes): data to decode index (int, optional): index to start from. Defaults to 0. Returns: int: pointer """ ioBuf = IO(data, index) # print 'Decoding channel at',index self.width = ioBuf.u32 self.height = ioBuf.u32 self.name = ioBuf.sz754 self._propertiesDecode(ioBuf) self._imageHierarchyPtr = self._pointerDecode(ioBuf) self._data = ioBuf.data return ioBuf.index
def decode(self, data: bytes, index: int = 0) -> int: """Decode a byte buffer. Args: data (bytes): data buffer to decode index (int, optional): index within the buffer to start at]. Defaults to 0. Returns: int: offset """ ioBuf = IO(data, index) self.factor = ioBuf.float32 self.numDigits = ioBuf.u32 self.id = ioBuf.sz754 self.symbol = ioBuf.sz754 self.abbrev = ioBuf.sz754 self.sname = ioBuf.sz754 self.pname = ioBuf.sz754 return ioBuf.index
def decode(self, data: bytes, index: int = 0) -> int: """Decode a byte buffer. Args: data (bytes): data buffer to decode index (int, optional): index within the buffer to start at. Defaults to 0. Returns: int: offset """ ioBuf = IO(data, index, boolSize=32) self.strokeType = ioBuf.u32 self.closedShape = ioBuf.boolean numFloatsPerPoint = ioBuf.u32 numPoints = ioBuf.u32 for _ in range(numPoints): gimpPoint = GimpPoint(self) ioBuf.index = gimpPoint.decode(ioBuf.data, ioBuf.index, numFloatsPerPoint) self.points.append(gimpPoint) return ioBuf.index
def encode(self): """Encode this object to a byte array.""" ioBuf = IO() ioBuf.addBytes(self.brush.encode()) ioBuf.addBytes(self.pattern.encode()) return ioBuf.data
def _parasitesEncode(self): """Encode list of parasites.""" ioBuf = IO() for parasite in self.parasites: ioBuf.addBytes(parasite.encode()) return ioBuf.data
def _propertyDecode(self, propertyType, data): """Decode a single property. Many properties are in the form propertyType: one of PROP_ lengthOfData: 4 data: varies but is often ioBuf.32 or ioBuf.boolean """ ioBuf = IO(data, boolSize=32) # print('DECODING PROPERTY',propertyType,len(data)) if propertyType == self.PROP_COLORMAP: self._colormapDecode(ioBuf) 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 = ioBuf.u32 elif propertyType == self.PROP_OPACITY: self.opacity = ioBuf.u32 elif propertyType == self.PROP_MODE: self.blendMode = ioBuf.u32 elif propertyType == self.PROP_VISIBLE: self.visible = ioBuf.boolean elif propertyType == self.PROP_LINKED: self.isLinked = ioBuf.boolean elif propertyType == self.PROP_LOCK_ALPHA: self.lockAlpha = ioBuf.boolean elif propertyType == self.PROP_APPLY_MASK: self.applyMask = ioBuf.boolean elif propertyType == self.PROP_EDIT_MASK: self.editingMask = ioBuf.boolean elif propertyType == self.PROP_SHOW_MASK: self.showMask = ioBuf.boolean elif propertyType == self.PROP_SHOW_MASKED: self.showMasked = ioBuf.boolean elif propertyType == self.PROP_OFFSETS: self.xOffset = ioBuf.i32 self.yOffset = ioBuf.i32 elif propertyType == self.PROP_COLOR: red = ioBuf.byte green = ioBuf.byte blue = ioBuf.byte self.color = [red, green, blue] elif propertyType == self.PROP_COMPRESSION: self.compression = ioBuf.byte elif propertyType == self.PROP_GUIDES: self._guidelinesDecode(data) elif propertyType == self.PROP_RESOLUTION: self.horizontalResolution = ioBuf.float32 self.verticalResolution = ioBuf.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 = ioBuf.u32 elif propertyType == self.PROP_PATHS: _numPaths = ioBuf.u32 """ for _ in range(numPaths): nRead, path = self._pathDecode_(data[index:]) self.paths.append(path) index += nRead """ elif propertyType == self.PROP_USER_UNIT: self._userUnitsDecode(data) elif propertyType == self.PROP_VECTORS: pass # self._vectorsDecode_(data) elif propertyType == self.PROP_TEXT_LAYER_FLAGS: if isinstance(data, bytes): self.textLayerFlags = int.from_bytes(data, byteorder="big") else: self.textLayerFlags = int(data) elif propertyType == self.PROP_OLD_SAMPLE_POINTS: raise RuntimeError("ERR: old sample points structure not supported") elif propertyType == self.PROP_LOCK_CONTENT: self.locked = ioBuf.boolean 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 = ioBuf.u32 elif propertyType == self.PROP_LOCK_POSITION: self.positionLocked = ioBuf.boolean elif propertyType == self.PROP_FLOAT_OPACITY: self.opacity = ioBuf.float32 elif propertyType == self.PROP_COLOR_TAG: self.colorTag = ioBuf.u32 elif propertyType == self.PROP_COMPOSITE_MODE: self.compositeMode = ioBuf.i32 elif propertyType == self.PROP_COMPOSITE_SPACE: self.compositeSpace = ioBuf.i32 elif propertyType == self.PROP_BLEND_SPACE: self.blendSpace = ioBuf.u32 elif propertyType == self.PROP_FLOAT_COLOR: red = ioBuf.float32 green = ioBuf.float32 blue = ioBuf.float32 self.color = [red, green, blue] elif propertyType == self.PROP_SAMPLE_POINTS: self._samplePointsDecode(data) else: raise RuntimeError(f"Unknown property id {propertyType}") return ioBuf.index
def _propertyEncode(self, propertyType): """Encode a single property. Many properties are in the form propertyType: one of PROP_ lengthOfData: 4 data: varies but is often ioBuf.32 or ioBuf.boolean If the property is the same as the default, or not specified, returns empty array """ ioBuf = IO(boolSize=32) if propertyType == self.PROP_COLORMAP: if self.colorMap is not None and self.colorMap: ioBuf.u32 = self.PROP_COLORMAP # ioBuf.addBytes(self._colormapEncode_()) elif propertyType == self.PROP_ACTIVE_LAYER: if self.selected is not None and self.selected: ioBuf.u32 = self.PROP_ACTIVE_LAYER elif propertyType == self.PROP_ACTIVE_CHANNEL: if self.selected is not None and self.selected: ioBuf.u32 = self.PROP_ACTIVE_LAYER elif propertyType == self.PROP_SELECTION: if self.isSelection is not None and self.isSelection: ioBuf.u32 = self.PROP_SELECTION elif propertyType == self.PROP_FLOATING_SELECTION: if self.selectionAttachedTo is not None: ioBuf.u32 = self.PROP_FLOATING_SELECTION ioBuf.u32 = self.selectionAttachedTo elif propertyType == self.PROP_OPACITY: if self.opacity is not None and not isinstance(self.opacity, float): ioBuf.u32 = self.PROP_OPACITY ioBuf.u32 = self.opacity elif propertyType == self.PROP_MODE: if self.blendMode is not None: ioBuf.u32 = self.PROP_MODE ioBuf.u32 = self.blendMode elif propertyType == self.PROP_VISIBLE: if self.visible is not None: ioBuf.u32 = self.PROP_VISIBLE ioBuf.boolean = self.visible elif propertyType == self.PROP_LINKED: if self.isLinked is not None and self.isLinked: ioBuf.u32 = self.PROP_LINKED ioBuf.boolean = self.isLinked elif propertyType == self.PROP_LOCK_ALPHA: if self.lockAlpha is not None and self.lockAlpha: ioBuf.u32 = self.PROP_LOCK_ALPHA ioBuf.boolean = self.lockAlpha elif propertyType == self.PROP_APPLY_MASK: if self.applyMask is not None: ioBuf.u32 = self.PROP_APPLY_MASK ioBuf.boolean = self.applyMask elif propertyType == self.PROP_EDIT_MASK: if self.editingMask is not None and self.editingMask: ioBuf.u32 = self.PROP_EDIT_MASK ioBuf.boolean = self.editingMask elif propertyType == self.PROP_SHOW_MASK: if self.showMask is not None and self.showMask: ioBuf.u32 = self.PROP_SHOW_MASK ioBuf.boolean = self.showMask elif propertyType == self.PROP_SHOW_MASKED: if self.showMasked is not None: ioBuf.u32 = self.PROP_SHOW_MASKED ioBuf.boolean = self.showMasked elif propertyType == self.PROP_OFFSETS: if self.xOffset is not None and self.yOffset is not None: ioBuf.u32 = self.PROP_OFFSETS ioBuf.i32 = self.xOffset ioBuf.i32 = self.yOffset elif propertyType == self.PROP_COLOR: if ( self.color is not None and not isinstance(self.color[0], float) and not isinstance(self.color[1], float) and not isinstance(self.color[2], float) ): ioBuf.u32 = self.PROP_COLOR ioBuf.byte = self.color[0] ioBuf.byte = self.color[1] ioBuf.byte = self.color[2] elif propertyType == self.PROP_COMPRESSION: if self.compression is not None: ioBuf.u32 = self.PROP_COMPRESSION ioBuf.u32 = self.compression elif propertyType == self.PROP_GUIDES: if self.guidelines is not None and self.guidelines: pass # ioBuf.u32 = self.PROP_GUIDES # ioBuf.addBytes(self._guidelinesEncode_()) elif propertyType == self.PROP_RESOLUTION: if self.horizontalResolution is not None and self.verticalResolution is not None: ioBuf.u32 = self.PROP_RESOLUTION ioBuf.u32 = int(self.horizontalResolution) ioBuf.i32 = int(self.verticalResolution) elif propertyType == self.PROP_TATTOO: if self.uniqueId is not None: ioBuf.u32 = int(self.uniqueId, 16) elif propertyType == self.PROP_PARASITES: if self.parasites is not None and self.parasites: ioBuf.u32 = self.PROP_PARASITES ioBuf.addBytes(self._parasitesEncode()) elif propertyType == self.PROP_UNIT: if self.units is not None: ioBuf.u32 = self.PROP_UNIT ioBuf.u32 = self.units elif propertyType == self.PROP_PATHS: if self.paths is not None and self.paths: # ioBuf.u32 = self.PROP_PATHS # ioBuf.u32 = len(self.paths) """ for path in self.paths: ioBuf.append(self._pathEncode_(path)) """ elif propertyType == self.PROP_USER_UNIT: if self.userUnits is not None: pass # ioBuf.u32 = self.PROP_USER_UNIT # ioBuf.addBytes(self._userUnitsEncode_()) elif propertyType == self.PROP_VECTORS: if self.vectors is not None and self.vectors: pass # ioBuf.u32 = self.PROP_VECTORS # ioBuf.addBytes(self._vectorsEncode_()) elif propertyType == self.PROP_TEXT_LAYER_FLAGS: if self.textLayerFlags is not None: ioBuf.u32 = self.PROP_TEXT_LAYER_FLAGS ioBuf.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: ioBuf.u32 = self.PROP_LOCK_CONTENT ioBuf.boolean = self.locked elif propertyType == self.PROP_GROUP_ITEM: if self.isGroup is not None and self.isGroup: ioBuf.u32 = self.PROP_GROUP_ITEM elif propertyType == self.PROP_ITEM_PATH: if self.itemPath is not None: pass # ioBuf.u32 = self.PROP_ITEM_PATH # ioBuf.addBytes(self._itemPathEncode_()) elif propertyType == self.PROP_GROUP_ITEM_FLAGS: if self.groupItemFlags is not None: ioBuf.u32 = self.PROP_GROUP_ITEM_FLAGS ioBuf.u32 = self.groupItemFlags elif propertyType == self.PROP_LOCK_POSITION: if self.positionLocked is not None and self.positionLocked: ioBuf.u32 = self.PROP_LOCK_POSITION ioBuf.boolean = self.positionLocked elif propertyType == self.PROP_FLOAT_OPACITY: if self.opacity is not None and isinstance(self.opacity, float): ioBuf.u32 = self.PROP_FLOAT_OPACITY ioBuf.float32 = self.opacity elif propertyType == self.PROP_COLOR_TAG: if self.colorTag is not None: ioBuf.u32 = self.PROP_COLOR_TAG ioBuf.u32 = self.colorTag elif propertyType == self.PROP_COMPOSITE_MODE: if self.compositeMode is not None: ioBuf.u32 = self.PROP_COMPOSITE_MODE ioBuf.i32 = self.compositeMode elif propertyType == self.PROP_COMPOSITE_SPACE: if self.compositeSpace is not None: ioBuf.u32 = self.PROP_COMPOSITE_SPACE ioBuf.i32 = self.compositeSpace elif propertyType == self.PROP_BLEND_SPACE: if self.blendSpace is not None: ioBuf.u32 = self.PROP_BLEND_SPACE ioBuf.u32 = self.blendSpace elif propertyType == self.PROP_FLOAT_COLOR: if ( self.color is not None and isinstance(self.color[0], float) and isinstance(self.color[1], float) and isinstance(self.color[2], float) ): ioBuf.u32 = self.PROP_FLOAT_COLOR ioBuf.float32 = self.color[0] ioBuf.float32 = self.color[1] ioBuf.float32 = self.color[2] elif propertyType == self.PROP_SAMPLE_POINTS: if self.samplePoints is not None and self.samplePoints: pass # ioBuf.u32 = self.PROP_SAMPLE_POINTS # self.addBytes(self._samplePointsEncode_()) else: raise RuntimeError(f"Unknown property id {propertyType}") return ioBuf.data
def decode(self, data: bytes, index: int = 0) -> int: """Decode a byte buffer. Steps: Create a new IO buffer (array of binary values) Check that the file is a valid gimp xcf Grab the file version Grab other attributes as outlined in the spec Get precision data using the class and ioBuf buffer List of properties Get the layers and add the pointers to them Get the channels and add the pointers to them Return the offset Args: data (bytes): data buffer to decode index (int, optional): index within the buffer to start at]. Defaults to 0. Raises: RuntimeError: "Not a valid GIMP file" Returns: int: offset """ # Create a new IO buffer (array of binary values) ioBuf = IO(data, index) # Check that the file is a valid gimp xcf if ioBuf.getBytes(9) != b"gimp xcf ": raise RuntimeError("Not a valid GIMP file") # Grab the file version version = ioBuf.cString if version == "file": self.version = 0 else: self.version = int(version[1:]) # Grab other attributes as outlined in the spec self.width = ioBuf.u32 self.height = ioBuf.u32 self.baseColorMode = ioBuf.u32 # Get precision data using the class and ioBuf buffer self.precision = Precision() self.precision.decode(self.version, ioBuf) # List of properties self._propertiesDecode(ioBuf) self._layerPtr = [] self._layers = [] # Get the layers and add the pointers to them while True: ptr = self._pointerDecode(ioBuf) if ptr == 0: break self._layerPtr.append(ptr) layer = GimpLayer(self) layer.decode(ioBuf.data, ptr) self._layers.append(layer) # Get the channels and add the pointers to them self._channelPtr = [] self._channels = [] while True: ptr = self._pointerDecode(ioBuf) if ptr == 0: break self._channelPtr.append(ptr) chnl = GimpChannel(self) chnl.decode(ioBuf.data, ptr) self._channels.append(chnl) # Return the offset return ioBuf.index