Skip to content

Instantly share code, notes, and snippets.

@skyfly200
Last active August 9, 2020 19:28
Show Gist options
  • Save skyfly200/46b622e8c362866022757d5ddde4caf5 to your computer and use it in GitHub Desktop.
Save skyfly200/46b622e8c362866022757d5ddde4caf5 to your computer and use it in GitHub Desktop.
//SPDX-License-Identifier: Unlicensed
pragma solidity ^0.6.8;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.1.0/contracts/utils/Strings.sol";
import "./libraries/Utils.sol";
import "./libraries/FixidityLib.sol";
import "./libraries/SVGBuffer.sol";
contract ColorTest {
using SVGBuffer for *;
using Strings for uint256;
using Utils for *;
/**
* @dev Contract constructor.
*/
constructor() public {
}
// Test the Fixidity library
function test(int256 base, uint8 decimals, uint8 scheme) external view returns (string memory) {
// empty buffer for the SVG markup
bytes memory buffer = new bytes(8192);
int256 root = FixidityLib.newFixed(base, decimals);
uint8 printDecimals = 5;
buffer.append('Root Hue: ');
buffer.append(root.toString());
uint16[1] memory schemes1 = [
uint16(180) // complimentary
];
uint16[2][1] memory schemes2 = [
[uint16(30), uint16(330)], // analogous
[uint16(150), uint16(210)] // split complimentary
];
uint16[3][5] memory schemes3 = [
[uint16(150), uint16(180), uint16(210)], // complimentary and analogous
[uint16(30), uint16(330), uint16(180)], // analogous and complimentary
[uint16(30), uint16(330), uint16(180)], // split complimentary
[uint16(60), uint16(180), uint16(240)], // tetradic
[uint16(90), uint16(180), uint16(270)] // square
];
for (uint256 i = 0; i < schemes3[scheme].length; i++) {
int256 rel = FixidityLib.newFixed(int256(schemes3[scheme][i]));
int256 result = FixidityLib.add(root, rel);
buffer.append('\nColor ');
buffer.append((i + 1).toString());
buffer.append(': ');
buffer.append(FixidityLib.fromFixed(FixidityLib.integer(result)).toString());
buffer.append('.');
buffer.append(FixidityLib.fromFixed(FixidityLib.fractional(result), printDecimals).toString());
}
return buffer.toString();
}
}
//SPDX-License-Identifier: Unlicensed
pragma solidity ^0.6.4;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.1.0/contracts/math/SafeMath.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.1.0/contracts/math/SignedSafeMath.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.1.0/contracts/utils/Strings.sol";
import "../libraries/SVGBuffer.sol";
import "../structs/DecimalStruct.sol";
library DecimalUtils {
using SafeMath for uint256;
using SignedSafeMath for int256;
using SVGBuffer for bytes;
using Strings for *;
// compute decimal parts
function decimalParts(Decimal memory number) internal pure returns (int256, uint256) {
return (
int256(number.value).div(int256(10) ** number.decimals),
uint256(number.value).mod(uint256(10) ** number.decimals)
);
}
// convert a Decimal to a string
// TODO: fix overflow error
function toString(Decimal memory number) internal view returns (string memory) {
( int256 wholeComponent, uint256 decimalComponent ) = decimalParts(number);
bytes memory buffer = new bytes(20);
if (wholeComponent < 0) {
buffer.append("-");
buffer.append(uint256(wholeComponent.mul(-1)).toString());
} else {
buffer.append(uint256(wholeComponent).toString());
}
buffer.append(".");
buffer.append(decimalComponent.toString());
return buffer.toString();
}
// add two decimals
function add(Decimal memory a, Decimal memory b) internal pure returns (Decimal memory result) {
// decide the order to add by decimal length
(Decimal memory x, Decimal memory y) = a.decimals > b.decimals ? (a, b) : (b, a);
// scale less precise value to match larger decimals
int256 scaled = y.value.mul(int256(10)**(x.decimals - y.decimals));
// add scaled values and return a new decimal
return Decimal(scaled.add(x.value), x.decimals);
}
}
//SPDX-License-Identifier: Unlicensed
pragma solidity ^0.6.4;
struct Decimal {
int256 value;
uint8 decimals;
}
//SPDX-License-Identifier: MIT
pragma solidity ^0.6.8;
/**
* @title FixidityLib
* @author Gadi Guy, Alberto Cuesta Canada
* @notice This library provides fixed point arithmetic with protection against
* overflow.
* All operations are done with int256 and the operands must have been created
* with any of the newFrom* functions, which shift the comma digits() to the
* right and check for limits.
* When using this library be sure of using maxNewFixed() as the upper limit for
* creation of fixed point numbers. Use maxFixedMul(), maxFixedDiv() and
* maxFixedAdd() if you want to be certain that those operations don't
* overflow.
*/
library FixidityLib {
/**
* @notice Number of positions that the comma is shifted to the right.
*/
function digits() public pure returns(uint8) {
return 24;
}
/**
* @notice This is 1 in the fixed point units used in this library.
* @dev Test fixed1() equals 10^digits()
* Hardcoded to 24 digits.
*/
function fixed1() public pure returns(int256) {
return 1000000000000000000000000;
}
/**
* @notice The amount of decimals lost on each multiplication operand.
* @dev Test mulPrecision() equals sqrt(fixed1)
* Hardcoded to 24 digits.
*/
function mulPrecision() public pure returns(int256) {
return 1000000000000;
}
/**
* @notice Maximum value that can be represented in an int256
* @dev Test maxInt256() equals 2^255 -1
*/
function maxInt256() public pure returns(int256) {
return 57896044618658097711785492504343953926634992332820282019728792003956564819967;
}
/**
* @notice Minimum value that can be represented in an int256
* @dev Test minInt256 equals (2^255) * (-1)
*/
function minInt256() public pure returns(int256) {
return -57896044618658097711785492504343953926634992332820282019728792003956564819968;
}
/**
* @notice Maximum value that can be converted to fixed point. Optimize for
* @dev deployment.
* Test maxNewFixed() equals maxInt256() / fixed1()
* Hardcoded to 24 digits.
*/
function maxNewFixed() public pure returns(int256) {
return 57896044618658097711785492504343953926634992332820282;
}
/**
* @notice Maximum value that can be converted to fixed point. Optimize for
* deployment.
* @dev Test minNewFixed() equals -(maxInt256()) / fixed1()
* Hardcoded to 24 digits.
*/
function minNewFixed() public pure returns(int256) {
return -57896044618658097711785492504343953926634992332820282;
}
/**
* @notice Maximum value that can be safely used as an addition operator.
* @dev Test maxFixedAdd() equals maxInt256()-1 / 2
* Test add(maxFixedAdd(),maxFixedAdd()) equals maxFixedAdd() + maxFixedAdd()
* Test add(maxFixedAdd()+1,maxFixedAdd()) throws
* Test add(-maxFixedAdd(),-maxFixedAdd()) equals -maxFixedAdd() - maxFixedAdd()
* Test add(-maxFixedAdd(),-maxFixedAdd()-1) throws
*/
function maxFixedAdd() public pure returns(int256) {
return 28948022309329048855892746252171976963317496166410141009864396001978282409983;
}
/**
* @notice Maximum negative value that can be safely in a subtraction.
* @dev Test maxFixedSub() equals minInt256() / 2
*/
function maxFixedSub() public pure returns(int256) {
return -28948022309329048855892746252171976963317496166410141009864396001978282409984;
}
/**
* @notice Maximum value that can be safely used as a multiplication operator.
* @dev Calculated as sqrt(maxInt256()*fixed1()).
* Be careful with your sqrt() implementation. I couldn't find a calculator
* that would give the exact square root of maxInt256*fixed1 so this number
* is below the real number by no more than 3*10**28. It is safe to use as
* a limit for your multiplications, although powers of two of numbers over
* this value might still work.
* Test multiply(maxFixedMul(),maxFixedMul()) equals maxFixedMul() * maxFixedMul()
* Test multiply(maxFixedMul(),maxFixedMul()+1) throws
* Test multiply(-maxFixedMul(),maxFixedMul()) equals -maxFixedMul() * maxFixedMul()
* Test multiply(-maxFixedMul(),maxFixedMul()+1) throws
* Hardcoded to 24 digits.
*/
function maxFixedMul() public pure returns(int256) {
return 240615969168004498257251713877715648331380787511296;
}
/**
* @notice Maximum value that can be safely used as a dividend.
* @dev divide(maxFixedDiv,newFixedFraction(1,fixed1())) = maxInt256().
* Test maxFixedDiv() equals maxInt256()/fixed1()
* Test divide(maxFixedDiv(),multiply(mulPrecision(),mulPrecision())) = maxFixedDiv()*(10^digits())
* Test divide(maxFixedDiv()+1,multiply(mulPrecision(),mulPrecision())) throws
* Hardcoded to 24 digits.
*/
function maxFixedDiv() public pure returns(int256) {
return 57896044618658097711785492504343953926634992332820282;
}
/**
* @notice Maximum value that can be safely used as a divisor.
* @dev Test maxFixedDivisor() equals fixed1()*fixed1() - Or 10**(digits()*2)
* Test divide(10**(digits()*2 + 1),10**(digits()*2)) = returns 10*fixed1()
* Test divide(10**(digits()*2 + 1),10**(digits()*2 + 1)) = throws
* Hardcoded to 24 digits.
*/
function maxFixedDivisor() public pure returns(int256) {
return 1000000000000000000000000000000000000000000000000;
}
/**
* @notice Converts an int256 to fixed point units, equivalent to multiplying
* by 10^digits().
* @dev Test newFixed(0) returns 0
* Test newFixed(1) returns fixed1()
* Test newFixed(maxNewFixed()) returns maxNewFixed() * fixed1()
* Test newFixed(maxNewFixed()+1) fails
*/
function newFixed(int256 x)
public
pure
returns (int256)
{
assert(x <= maxNewFixed());
assert(x >= minNewFixed());
return x * fixed1();
}
/**
* @notice Converts an int256 in the fixed point representation of this
* library to a non decimal. All decimal digits will be truncated.
*/
function fromFixed(int256 x)
public
pure
returns (int256)
{
return x / fixed1();
}
/**
* @notice Converts an int256 which is already in some fixed point
* representation to a different fixed precision representation.
* Both the origin and destination precisions must be 38 or less digits.
* Origin values with a precision higher than the destination precision
* will be truncated accordingly.
* @dev
* Test convertFixed(1,0,0) returns 1;
* Test convertFixed(1,1,1) returns 1;
* Test convertFixed(1,1,0) returns 0;
* Test convertFixed(1,0,1) returns 10;
* Test convertFixed(10,1,0) returns 1;
* Test convertFixed(10,0,1) returns 100;
* Test convertFixed(100,1,0) returns 10;
* Test convertFixed(100,0,1) returns 1000;
* Test convertFixed(1000,2,0) returns 10;
* Test convertFixed(1000,0,2) returns 100000;
* Test convertFixed(1000,2,1) returns 100;
* Test convertFixed(1000,1,2) returns 10000;
* Test convertFixed(maxInt256,1,0) returns maxInt256/10;
* Test convertFixed(maxInt256,0,1) throws
* Test convertFixed(maxInt256,38,0) returns maxInt256/(10**38);
* Test convertFixed(1,0,38) returns 10**38;
* Test convertFixed(maxInt256,39,0) throws
* Test convertFixed(1,0,39) throws
*/
function convertFixed(int256 x, uint8 _originDigits, uint8 _destinationDigits)
public
pure
returns (int256)
{
assert(_originDigits <= 38 && _destinationDigits <= 38);
uint8 decimalDifference;
if ( _originDigits > _destinationDigits ){
decimalDifference = _originDigits - _destinationDigits;
return x/(uint128(10)**uint128(decimalDifference));
}
else if ( _originDigits < _destinationDigits ){
decimalDifference = _destinationDigits - _originDigits;
// Cast uint8 -> uint128 is safe
// Exponentiation is safe:
// _originDigits and _destinationDigits limited to 38 or less
// decimalDifference = abs(_destinationDigits - _originDigits)
// decimalDifference < 38
// 10**38 < 2**128-1
assert(x <= maxInt256()/uint128(10)**uint128(decimalDifference));
assert(x >= minInt256()/uint128(10)**uint128(decimalDifference));
return x*(uint128(10)**uint128(decimalDifference));
}
// _originDigits == digits())
return x;
}
/**
* @notice Converts an int256 which is already in some fixed point
* representation to that of this library. The _originDigits parameter is the
* precision of x. Values with a precision higher than FixidityLib.digits()
* will be truncated accordingly.
*/
function newFixed(int256 x, uint8 _originDigits)
public
pure
returns (int256)
{
return convertFixed(x, _originDigits, digits());
}
/**
* @notice Converts an int256 in the fixed point representation of this
* library to a different representation. The _destinationDigits parameter is the
* precision of the output x. Values with a precision below than
* FixidityLib.digits() will be truncated accordingly.
*/
function fromFixed(int256 x, uint8 _destinationDigits)
public
pure
returns (int256)
{
return convertFixed(x, digits(), _destinationDigits);
}
/**
* @notice Converts two int256 representing a fraction to fixed point units,
* equivalent to multiplying dividend and divisor by 10^digits().
* @dev
* Test newFixedFraction(maxFixedDiv()+1,1) fails
* Test newFixedFraction(1,maxFixedDiv()+1) fails
* Test newFixedFraction(1,0) fails
* Test newFixedFraction(0,1) returns 0
* Test newFixedFraction(1,1) returns fixed1()
* Test newFixedFraction(maxFixedDiv(),1) returns maxFixedDiv()*fixed1()
* Test newFixedFraction(1,fixed1()) returns 1
* Test newFixedFraction(1,fixed1()-1) returns 0
*/
function newFixedFraction(
int256 numerator,
int256 denominator
)
public
pure
returns (int256)
{
assert(numerator <= maxNewFixed());
assert(denominator <= maxNewFixed());
assert(denominator != 0);
int256 convertedNumerator = newFixed(numerator);
int256 convertedDenominator = newFixed(denominator);
return divide(convertedNumerator, convertedDenominator);
}
/**
* @notice Returns the integer part of a fixed point number.
* @dev
* Test integer(0) returns 0
* Test integer(fixed1()) returns fixed1()
* Test integer(newFixed(maxNewFixed())) returns maxNewFixed()*fixed1()
* Test integer(-fixed1()) returns -fixed1()
* Test integer(newFixed(-maxNewFixed())) returns -maxNewFixed()*fixed1()
*/
function integer(int256 x) public pure returns (int256) {
return (x / fixed1()) * fixed1(); // Can't overflow
}
/**
* @notice Returns the fractional part of a fixed point number.
* In the case of a negative number the fractional is also negative.
* @dev
* Test fractional(0) returns 0
* Test fractional(fixed1()) returns 0
* Test fractional(fixed1()-1) returns 10^24-1
* Test fractional(-fixed1()) returns 0
* Test fractional(-fixed1()+1) returns -10^24-1
*/
function fractional(int256 x) public pure returns (int256) {
return x - (x / fixed1()) * fixed1(); // Can't overflow
}
/**
* @notice Converts to positive if negative.
* Due to int256 having one more negative number than positive numbers
* abs(minInt256) reverts.
* @dev
* Test abs(0) returns 0
* Test abs(fixed1()) returns -fixed1()
* Test abs(-fixed1()) returns fixed1()
* Test abs(newFixed(maxNewFixed())) returns maxNewFixed()*fixed1()
* Test abs(newFixed(minNewFixed())) returns -minNewFixed()*fixed1()
*/
function abs(int256 x) public pure returns (int256) {
if (x >= 0) {
return x;
} else {
int256 result = -x;
assert (result > 0);
return result;
}
}
/**
* @notice x+y. If any operator is higher than maxFixedAdd() it
* might overflow.
* In solidity maxInt256 + 1 = minInt256 and viceversa.
* @dev
* Test add(maxFixedAdd(),maxFixedAdd()) returns maxInt256()-1
* Test add(maxFixedAdd()+1,maxFixedAdd()+1) fails
* Test add(-maxFixedSub(),-maxFixedSub()) returns minInt256()
* Test add(-maxFixedSub()-1,-maxFixedSub()-1) fails
* Test add(maxInt256(),maxInt256()) fails
* Test add(minInt256(),minInt256()) fails
*/
function add(int256 x, int256 y) public pure returns (int256) {
int256 z = x + y;
if (x > 0 && y > 0) assert(z > x && z > y);
if (x < 0 && y < 0) assert(z < x && z < y);
return z;
}
/**
* @notice x-y. You can use add(x,-y) instead.
* @dev Tests covered by add(x,y)
*/
function subtract(int256 x, int256 y) public pure returns (int256) {
return add(x,-y);
}
/**
* @notice x*y. If any of the operators is higher than maxFixedMul() it
* might overflow.
* @dev
* Test multiply(0,0) returns 0
* Test multiply(maxFixedMul(),0) returns 0
* Test multiply(0,maxFixedMul()) returns 0
* Test multiply(maxFixedMul(),fixed1()) returns maxFixedMul()
* Test multiply(fixed1(),maxFixedMul()) returns maxFixedMul()
* Test all combinations of (2,-2), (2, 2.5), (2, -2.5) and (0.5, -0.5)
* Test multiply(fixed1()/mulPrecision(),fixed1()*mulPrecision())
* Test multiply(maxFixedMul()-1,maxFixedMul()) equals multiply(maxFixedMul(),maxFixedMul()-1)
* Test multiply(maxFixedMul(),maxFixedMul()) returns maxInt256() // Probably not to the last digits
* Test multiply(maxFixedMul()+1,maxFixedMul()) fails
* Test multiply(maxFixedMul(),maxFixedMul()+1) fails
*/
function multiply(int256 x, int256 y) public pure returns (int256) {
if (x == 0 || y == 0) return 0;
if (y == fixed1()) return x;
if (x == fixed1()) return y;
// Separate into integer and fractional parts
// x = x1 + x2, y = y1 + y2
int256 x1 = integer(x) / fixed1();
int256 x2 = fractional(x);
int256 y1 = integer(y) / fixed1();
int256 y2 = fractional(y);
// (x1 + x2) * (y1 + y2) = (x1 * y1) + (x1 * y2) + (x2 * y1) + (x2 * y2)
int256 x1y1 = x1 * y1;
if (x1 != 0) assert(x1y1 / x1 == y1); // Overflow x1y1
// x1y1 needs to be multiplied back by fixed1
// solium-disable-next-line mixedcase
int256 fixed_x1y1 = x1y1 * fixed1();
if (x1y1 != 0) assert(fixed_x1y1 / x1y1 == fixed1()); // Overflow x1y1 * fixed1
x1y1 = fixed_x1y1;
int256 x2y1 = x2 * y1;
if (x2 != 0) assert(x2y1 / x2 == y1); // Overflow x2y1
int256 x1y2 = x1 * y2;
if (x1 != 0) assert(x1y2 / x1 == y2); // Overflow x1y2
x2 = x2 / mulPrecision();
y2 = y2 / mulPrecision();
int256 x2y2 = x2 * y2;
if (x2 != 0) assert(x2y2 / x2 == y2); // Overflow x2y2
// result = fixed1() * x1 * y1 + x1 * y2 + x2 * y1 + x2 * y2 / fixed1();
int256 result = x1y1;
result = add(result, x2y1); // Add checks for overflow
result = add(result, x1y2); // Add checks for overflow
result = add(result, x2y2); // Add checks for overflow
return result;
}
/**
* @notice 1/x
* @dev
* Test reciprocal(0) fails
* Test reciprocal(fixed1()) returns fixed1()
* Test reciprocal(fixed1()*fixed1()) returns 1 // Testing how the fractional is truncated
* Test reciprocal(2*fixed1()*fixed1()) returns 0 // Testing how the fractional is truncated
*/
function reciprocal(int256 x) public pure returns (int256) {
assert(x != 0);
return (fixed1()*fixed1()) / x; // Can't overflow
}
/**
* @notice x/y. If the dividend is higher than maxFixedDiv() it
* might overflow. You can use multiply(x,reciprocal(y)) instead.
* There is a loss of precision on division for the lower mulPrecision() decimals.
* @dev
* Test divide(fixed1(),0) fails
* Test divide(maxFixedDiv(),1) = maxFixedDiv()*(10^digits())
* Test divide(maxFixedDiv()+1,1) throws
* Test divide(maxFixedDiv(),maxFixedDiv()) returns fixed1()
*/
function divide(int256 x, int256 y) public pure returns (int256) {
if (y == fixed1()) return x;
assert(y != 0);
assert(y <= maxFixedDivisor());
return multiply(x, reciprocal(y));
}
}
//SPDX-License-Identifier: Unlicensed
pragma solidity ^0.6.8;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.1.0/contracts/utils/Strings.sol";
import "../structs/DecimalStruct.sol";
import "./Decimal.sol";
library SVGBuffer {
using DecimalUtils for Decimal;
using Strings for *;
function hasCapacityFor(bytes memory buffer, uint256 needed)
internal
pure
returns (bool)
{
uint256 size;
uint256 used;
assembly {
size := mload(buffer)
used := mload(add(buffer, 32))
}
return size >= 32 && used <= size - 32 && used + needed <= size - 32;
}
function toString(bytes memory buffer)
internal
pure
returns (string memory)
{
require(hasCapacityFor(buffer, 0), "Buffer.toString: invalid buffer");
string memory ret;
assembly {
ret := add(buffer, 32)
}
return ret;
}
function append(bytes memory buffer, string memory str) internal view {
require(
hasCapacityFor(buffer, bytes(str).length),
"Buffer.append: no capacity"
);
assembly {
let len := mload(add(buffer, 32))
pop(
staticcall(
gas(),
0x4,
add(str, 32),
mload(str),
add(len, add(buffer, 64)),
mload(str)
)
)
mstore(add(buffer, 32), add(len, mload(str)))
}
}
function rect(
bytes memory buffer,
Decimal[2] memory positions,
Decimal[2] memory size,
Decimal memory opacity,
uint256 _radius,
uint256 rgb
) internal view {
require(hasCapacityFor(buffer, 102), "Buffer.rect: no capacity");
string memory xpos = positions[0].toString();
string memory ypos = positions[1].toString();
string memory width = size[0].toString();
string memory height = size[1].toString();
string memory radius = _radius.toString();
string memory opacityString = opacity.toString();
assembly {
function numbx1(x, v) -> y {
// v must be in the closed interval [0, 9]
// otherwise it outputs junk
mstore8(x, add(v, 48))
y := add(x, 1)
}
function numbx2(x, v) -> y {
// v must be in the closed interval [0, 99]
// otherwise it outputs junk
y := numbx1(numbx1(x, div(v, 10)), mod(v, 10))
}
function numbu3(x, v) -> y {
// v must be in the closed interval [0, 999]
// otherwise only the last 3 digits will be converted
switch lt(v, 100)
case 0 {
// without input value sanitation: y := numbx2(numbx1(x, div(v, 100)), mod(v, 100))
y := numbx2(
numbx1(x, mod(div(v, 100), 10)),
mod(v, 100)
)
}
default {
switch lt(v, 10)
case 0 {
y := numbx2(x, v)
}
default {
y := numbx1(x, v)
}
}
}
function numbi3(x, v) -> y {
// v must be in the closed interval [-999, 999]
// otherwise only the last 3 digits will be converted
if slt(v, 0) {
v := add(not(v), 1)
mstore8(x, 45) // minus sign
x := add(x, 1)
}
y := numbu3(x, v)
}
function hexrgb(x, v) -> y {
let blo := and(v, 0xf)
let bhi := and(shr(4, v), 0xf)
let glo := and(shr(8, v), 0xf)
let ghi := and(shr(12, v), 0xf)
let rlo := and(shr(16, v), 0xf)
let rhi := and(shr(20, v), 0xf)
mstore8(x, add(add(rhi, mul(div(rhi, 10), 39)), 48))
mstore8(add(x, 1), add(add(rlo, mul(div(rlo, 10), 39)), 48))
mstore8(add(x, 2), add(add(ghi, mul(div(ghi, 10), 39)), 48))
mstore8(add(x, 3), add(add(glo, mul(div(glo, 10), 39)), 48))
mstore8(add(x, 4), add(add(bhi, mul(div(bhi, 10), 39)), 48))
mstore8(add(x, 5), add(add(blo, mul(div(blo, 10), 39)), 48))
y := add(x, 6)
}
function append(x, str, len) -> y {
mstore(x, str)
y := add(x, len)
}
let strIdx := add(mload(add(buffer, 32)), add(buffer, 64))
strIdx := append(strIdx, '<rect x="', 9)
strIdx := append(strIdx, xpos, 3)
strIdx := append(strIdx, '" y="', 5)
strIdx := append(strIdx, ypos, 3)
strIdx := append(strIdx, '" width="', 9)
strIdx := append(strIdx, width, 3)
strIdx := append(strIdx, '" height="', 10)
strIdx := append(strIdx, height, 3)
strIdx := append(strIdx, '" rx="', 6)
strIdx := append(strIdx, radius, 3)
strIdx := append(strIdx, '" style="fill:#', 15)
strIdx := hexrgb(strIdx, rgb)
strIdx := append(strIdx, "; fill-opacity:", 14)
strIdx := append(strIdx, opacityString, 7)
strIdx := append(strIdx, '"/>', 3)
mstore(add(buffer, 32), sub(sub(strIdx, buffer), 64))
}
}
}
//SPDX-License-Identifier: Unlicensed
pragma solidity ^0.6.4;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.1.0/contracts/math/SignedSafeMath.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.1.0/contracts/utils/Strings.sol";
import "./SVGBuffer.sol";
library Utils {
using SVGBuffer for bytes;
using SignedSafeMath for int256;
using Strings for uint256;
function stringToUint(string memory s)
internal
pure
returns (uint256 result)
{
bytes memory b = bytes(s);
uint256 i;
result = 0;
for (i = 0; i < b.length; i++) {
uint256 c = uint256(uint8(b[i]));
if (c >= 48 && c <= 57) {
result = result * 10 + (c - 48);
}
}
}
// special toString for signed ints
function toString(int256 val) public view returns (string memory) {
bytes memory buffer = new bytes(8192);
if (val >= 0) buffer.append(uint256(val).toString());
else {
buffer.append("-");
buffer.append(uint256(int256(val).mul(-1)).toString());
}
return buffer.toString();
}
// special toString for signed 16 bit ints
function toString(int16 val) public view returns (string memory) {
bytes memory buffer = new bytes(8192);
if (val >= 0) buffer.append(uint256(val).toString());
else {
buffer.append("-");
buffer.append(uint256(int256(val).mul(-1)).toString());
}
return buffer.toString();
}
// TODO: fix overflow error
function toHexColor(
bytes memory buffer,
uint256 rgb
) internal pure {
require(SVGBuffer.hasCapacityFor(buffer, 6), "Buffer.rect: no capacity for color");
assembly {
function hexrgb(x, v) -> y {
let blo := and(v, 0xf)
let bhi := and(shr(4, v), 0xf)
let glo := and(shr(8, v), 0xf)
let ghi := and(shr(12, v), 0xf)
let rlo := and(shr(16, v), 0xf)
let rhi := and(shr(20, v), 0xf)
mstore8(x, add(add(rhi, mul(div(rhi, 10), 39)), 48))
mstore8(add(x, 1), add(add(rlo, mul(div(rlo, 10), 39)), 48))
mstore8(add(x, 2), add(add(ghi, mul(div(ghi, 10), 39)), 48))
mstore8(add(x, 3), add(add(glo, mul(div(glo, 10), 39)), 48))
mstore8(add(x, 4), add(add(bhi, mul(div(bhi, 10), 39)), 48))
mstore8(add(x, 5), add(add(blo, mul(div(blo, 10), 39)), 48))
y := add(x, 6)
}
let strIdx := add(mload(add(buffer, 32)), add(buffer, 64))
strIdx := hexrgb(strIdx, rgb)
mstore(add(buffer, 32), sub(sub(strIdx, buffer), 64))
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment