+    def _write_pixel(self, x: int, y: int, value: int) -> None:
+        if self._read_only:
+            raise RuntimeError("Read-only")
+
+        # Writes the color index value into a pixel position
+        # Must update the dirty area separately
+
+        # Don't write if out of area
+        if x < 0 or x >= self._bmp_width or y < 0 or y >= self._bmp_height:
+            return
+
+        # Update one pixel of data
+        row_start = y * self._stride
+        bytes_per_value = self._bits_per_value // 8
+        if bytes_per_value < 1:
+            bit_position = 32 - ((x & self._x_mask) + 1) * self._bits_per_value
+            index = row_start + (x >> self._x_shift)
+            word = self._data[index]
+            word &= ~(self._bitmask << bit_position)
+            word |= (value & self._bitmask) << bit_position
+            self._data[index] = word
+        else:
+            row = memoryview(self._data)[row_start : row_start + self._stride]
+            if bytes_per_value == 1:
+                row[x] = value
+            elif bytes_per_value == 2:
+                struct.pack_into("<H", row, x * 2, value)
+            elif bytes_per_value == 4:
+                struct.pack_into("<I", row, x * 4, value)