Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 102 additions & 50 deletions src/ToExcel/ExcelImage.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,71 @@
//获取图片在单元格的位置
var getImagePosition = function (num: number, arr: number[]) {
let index = 0;
let minIndex;
let maxIndex;
for (let i = 0; i < arr.length; i++) {
if (num < arr[i]) {
index = i;
break;
type ImageExtension = "png" | "jpeg" | "gif";
type AnchorAxis = { index: number; offset: number };

const EMU_PER_PIXEL_AT_96_DPI = 9525;

// Use native OOXML offsets. ExcelJS's fractional col/row API derives offsets
// from character/point units and loses pixel accuracy for partial cells.
const getAnchorAxis = function (num: number, positions: number[]): AnchorAxis {
const pixel = Math.max(0, num || 0);
if (positions.length === 0) {
return { index: 0, offset: pixel };
}

let previous = 0;
for (let index = 0; index < positions.length; index++) {
const current = positions[index];
if (pixel < current) {
return { index, offset: pixel - previous };
}
if (pixel === current) {
return { index: index + 1, offset: 0 };
}
previous = current;
}

if (index == 0) {
minIndex = 0;
maxIndex = 1;
return Math.abs((num - 0) / (arr[maxIndex] - arr[minIndex])) + index;
} else if (index == arr.length - 1) {
minIndex = arr.length - 2;
maxIndex = arr.length - 1;
} else {
minIndex = index - 1;
maxIndex = index;
const lastIndex = positions.length - 1;
const lastSize =
lastIndex > 0
? positions[lastIndex] - positions[lastIndex - 1]
: positions[0];
if (lastSize <= 0) {
return { index: positions.length, offset: pixel - previous };
}

const remaining = pixel - previous;
const additionalCells = Math.floor(remaining / lastSize);
return {
index: positions.length + additionalCells,
offset: remaining - additionalCells * lastSize,
};
};

const getImageAnchor = function (
left: number,
top: number,
columnPositions: number[],
rowPositions: number[]
) {
const column = getAnchorAxis(left, columnPositions);
const row = getAnchorAxis(top, rowPositions);
return {
nativeCol: column.index,
nativeColOff: Math.round(column.offset * EMU_PER_PIXEL_AT_96_DPI),
nativeRow: row.index,
nativeRowOff: Math.round(row.offset * EMU_PER_PIXEL_AT_96_DPI),
};
};

const getImageExtension = function (src: string): ImageExtension {
const match = /^data:image\/([^;,]+)[;,]/i.exec(src || "");
const imageType = match?.[1]?.toLowerCase();
if (imageType === "jpg" || imageType === "jpeg") {
return "jpeg";
}
if (imageType === "gif") {
return "gif";
}
let min = arr[minIndex];
let max = arr[maxIndex];
let radio = Math.abs((num - min) / (max - min)) + index;
return radio;
return "png";
};

var setImages = function (table: any, worksheet: any, workbook: any) {
Expand All @@ -42,55 +83,66 @@ var setImages = function (table: any, worksheet: any, workbook: any) {
const item = images[key];
const imageId = workbook.addImage({
base64: myBase64Image,
extension: "png",
extension: getImageExtension(myBase64Image),
});

if (!visibledatacolumn || !visibledatarow) {
const defaultColWidth = localTable.defaultColWidth || 73;
const defaultRowHeight = localTable.defaultRowHeight || 19;

const rowCount = localTable.data.length;
const colCount = localTable.data[0].length;

visibledatacolumn = [];
visibledatarow = [];

let lastVal = 0;
for (let i=0; i<rowCount; i++) {
const rowHeight = (localTable.config?.rowlen?.[i] || defaultRowHeight);
const rowPosition = lastVal + rowHeight;

for (let i = 0; i < rowCount; i++) {
const rowHeight = localTable.config?.rowlen?.[i] || defaultRowHeight;
const isHidden = localTable.config?.rowhidden?.[i] != null;
const rowPosition = lastVal + (isHidden ? 0 : rowHeight + 1);

visibledatarow.push(rowPosition);
lastVal = rowPosition;
}

lastVal = 0;
for (let i=0; i<colCount; i++) {
const colWidth = (localTable.config?.columnlen?.[i] || defaultColWidth);
const colPosition = lastVal + colWidth;

for (let i = 0; i < colCount; i++) {
const colWidth = localTable.config?.columnlen?.[i] || defaultColWidth;
const isHidden = localTable.config?.colhidden?.[i] != null;
const colPosition = lastVal + (isHidden ? 0 : colWidth + 1);

visibledatacolumn.push(colPosition);
lastVal = colPosition;
}
}

const col_st = getImagePosition(item.left, visibledatacolumn);
const row_st = getImagePosition(item.top, visibledatarow);
const topLeft = getImageAnchor(
item.left,
item.top,
visibledatacolumn,
visibledatarow
);

//模式1,图片左侧与luckysheet位置一样,像素比例保持不变,但是,右侧位置可能与原图所在单元格不一致
worksheet.addImage(imageId, {
tl: { col: col_st, row: row_st },
ext: { width: item.width, height: item.height },
});
//模式2,图片四个角位置没有变动,但是图片像素比例可能和原图不一样
// const w_ed = item.default.left+item.default.width;
// const h_ed = item.default.top+item.default.height;
// const col_ed = getImagePosition(w_ed,visibledatacolumn);
// const row_ed = getImagePosition(h_ed,visibledatarow);
// worksheet.addImage(imageId, {
// tl: { col: col_st, row: row_st},
// br: { col: col_ed, row: row_ed},
// });
// Preserve FortuneSheet's image movement/resize mode in the OOXML anchor.
if (item.type === "1") {
worksheet.addImage(imageId, {
tl: topLeft,
br: getImageAnchor(
item.left + item.width,
item.top + item.height,
visibledatacolumn,
visibledatarow
),
editAs: "twoCell",
});
} else {
worksheet.addImage(imageId, {
tl: topLeft,
ext: { width: item.width, height: item.height },
editAs: item.type === "3" ? "absolute" : "oneCell",
});
}
}
};

Expand Down
19 changes: 17 additions & 2 deletions src/ToExcel/ExcelStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,32 @@ const formatHyperlink = (address: string) => {
return `#\'${sheetCell[0]}\'!${sheetCell[1] || "A1"}`;
};

// Inverse of the pixel conversions used by the XLSX importer.
const columnPixelsToExcelWidth = (pixels: number) => (pixels - 5) / 8 + 0.83;
const rowPixelsToPoints = (pixels: number) => pixels * (72 / 96);

var setStyleAndValue = function (table: any, worksheet: ExcelJS.Worksheet) {
const cellArr = table?.data;
if (!Array.isArray(cellArr)) return;

worksheet.properties.defaultColWidth = columnPixelsToExcelWidth(
table.defaultColWidth ?? 73
);
worksheet.properties.defaultRowHeight = rowPixelsToPoints(
table.defaultRowHeight ?? 19
);

cellArr.forEach(function (row, rowid) {
const dbrow = worksheet.getRow(rowid + 1);
dbrow.height = (table.config?.rowlen?.[rowid] || 19) / 1.2;
const rowHeight =
table.config?.rowlen?.[rowid] ?? table.defaultRowHeight ?? 19;
dbrow.height = rowPixelsToPoints(rowHeight);
row.every(function (cell: any, columnid: any) {
if (rowid == 0) {
const dobCol = worksheet.getColumn(columnid + 1);
dobCol.width = (table.config?.columnlen?.[columnid] || 73) / 8;
const columnWidth =
table.config?.columnlen?.[columnid] ?? table.defaultColWidth ?? 73;
dobCol.width = columnPixelsToExcelWidth(columnWidth);
}
if (!cell) return true;
let fill = fillConvert(cell.bg);
Expand Down
84 changes: 45 additions & 39 deletions src/ToFortuneSheet/FortuneFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,8 @@ export class FortuneFile {
let gap = def,
istring = i.toString();
if (istring in hidden) {
gap = 0;
sets.push(allGap);
continue;
} else if (istring in lens) {
gap = lens[istring];
}
Expand All @@ -293,6 +294,9 @@ export class FortuneFile {
let images = sheet.images,
defaultColWidth = sheet.defaultColWidth,
defaultRowHeight = sheet.defaultRowHeight;
if (images == null) {
return;
}
let colhidden = {};
if (sheet.config.colhidden) {
colhidden = sheet.config.colhidden;
Expand Down Expand Up @@ -330,6 +334,11 @@ export class FortuneFile {
let cx_n = 0,
cy_n = 0;

// Absolute anchors already contain their pixel position and size.
if (fromCol == null || fromRow == null) {
continue;
}

if (fromCol >= this.columnWidthSet.length) {
this.extendArray(
fromCol,
Expand Down Expand Up @@ -362,47 +371,44 @@ export class FortuneFile {
}
y_n = y_n + fromRowOff;

if (toCol >= this.columnWidthSet.length) {
this.extendArray(
toCol,
this.columnWidthSet,
defaultColWidth,
colhidden,
columnlen
);
}
if (toCol == 0) {
cx_n = 0;
if (toCol == null || toRow == null) {
// One-cell anchors store their size in xdr:ext rather than xdr:to.
cx_n = imageObject.originWidth || 0;
cy_n = imageObject.originHeight || 0;
} else {
cx_n = this.columnWidthSet[toCol - 1];
}
cx_n = cx_n + toColOff - x_n;
if (toCol >= this.columnWidthSet.length) {
this.extendArray(
toCol,
this.columnWidthSet,
defaultColWidth,
colhidden,
columnlen
);
}
if (toCol == 0) {
cx_n = 0;
} else {
cx_n = this.columnWidthSet[toCol - 1];
}
cx_n = cx_n + toColOff - x_n;

if (toRow >= this.rowHeightSet.length) {
this.extendArray(
toRow,
this.rowHeightSet,
defaultRowHeight,
rowhidden,
rowlen
);
}
if (toRow == 0) {
cy_n = 0;
} else {
cy_n = this.rowHeightSet[toRow - 1];
}

if (toRow >= this.rowHeightSet.length) {
this.extendArray(
toRow,
this.rowHeightSet,
defaultRowHeight,
rowhidden,
rowlen
);
cy_n = cy_n + toRowOff - y_n;
}
if (toRow == 0) {
cy_n = 0;
} else {
cy_n = this.rowHeightSet[toRow - 1];
}

cy_n = cy_n + toRowOff - y_n;

console.log(defaultColWidth, colhidden, columnlen);
console.log(fromCol, this.columnWidthSet[fromCol], fromColOff);
console.log(
toCol,
this.columnWidthSet[toCol],
toColOff,
JSON.stringify(this.columnWidthSet)
);

imageObject.originWidth = cx_n;
imageObject.originHeight = cy_n;
Expand Down
Loading