1 // Copyright 2014 PDFium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com 6 7 #include "../include/fsdk_define.h" 8 #include "../include/fpdf_transformpage.h" 9 10 DLLEXPORT void STDCALL FPDFPage_SetMediaBox(FPDF_PAGE page, float left, float bottom, float right, float top) 11 { 12 if(!page) 13 return; 14 CPDF_Page* pPage = (CPDF_Page*)page; 15 CPDF_Dictionary* pPageDict = pPage->m_pFormDict; 16 CPDF_Array* pMediaBoxArray = FX_NEW CPDF_Array; 17 pMediaBoxArray->Add(FX_NEW CPDF_Number(left)); 18 pMediaBoxArray->Add(FX_NEW CPDF_Number(bottom)); 19 pMediaBoxArray->Add(FX_NEW CPDF_Number(FX_FLOAT(right))); 20 pMediaBoxArray->Add(FX_NEW CPDF_Number(FX_FLOAT(top))); 21 22 pPageDict->SetAt("MediaBox", pMediaBoxArray); 23 } 24 25 26 DLLEXPORT void STDCALL FPDFPage_SetCropBox(FPDF_PAGE page, float left, float bottom, float right, float top) 27 { 28 if(!page) 29 return; 30 CPDF_Page* pPage = (CPDF_Page*)page; 31 CPDF_Dictionary* pPageDict = pPage->m_pFormDict; 32 CPDF_Array* pCropBoxArray = FX_NEW CPDF_Array; 33 pCropBoxArray->Add(FX_NEW CPDF_Number(left)); 34 pCropBoxArray->Add(FX_NEW CPDF_Number(bottom)); 35 pCropBoxArray->Add(FX_NEW CPDF_Number(FX_FLOAT(right))); 36 pCropBoxArray->Add(FX_NEW CPDF_Number(FX_FLOAT(top))); 37 38 39 pPageDict->SetAt("CropBox", pCropBoxArray); 40 } 41 42 43 DLLEXPORT FX_BOOL STDCALL FPDFPage_GetMediaBox(FPDF_PAGE page, float* left, float* bottom, float* right, float* top) 44 { 45 if(!page) 46 return FALSE; 47 CPDF_Page* pPage = (CPDF_Page*)page; 48 CPDF_Dictionary* pPageDict = pPage->m_pFormDict; 49 CPDF_Array* pArray = pPageDict->GetArray("MediaBox"); 50 if(pArray) 51 { 52 *left = pArray->GetFloat(0); 53 *bottom = pArray->GetFloat(1); 54 *right = pArray->GetFloat(2); 55 *top = pArray->GetFloat(3); 56 return TRUE; 57 } 58 return FALSE; 59 } 60 61 DLLEXPORT FPDF_BOOL STDCALL FPDFPage_GetCropBox(FPDF_PAGE page, float* left, float* bottom, float* right, float* top) 62 { 63 if(!page) 64 return FALSE; 65 CPDF_Page* pPage = (CPDF_Page*)page; 66 CPDF_Dictionary* pPageDict = pPage->m_pFormDict; 67 CPDF_Array* pArray = pPageDict->GetArray("CropBox"); 68 if(pArray) 69 { 70 *left = pArray->GetFloat(0); 71 *bottom = pArray->GetFloat(1); 72 *right = pArray->GetFloat(2); 73 *top = pArray->GetFloat(3); 74 return TRUE; 75 } 76 return FALSE; 77 } 78 79 DLLEXPORT FPDF_BOOL STDCALL FPDFPage_TransFormWithClip(FPDF_PAGE page, FS_MATRIX* matrix, FS_RECTF* clipRect) 80 { 81 if(!page) 82 return FALSE; 83 84 CFX_ByteTextBuf textBuf; 85 textBuf<<"q "; 86 CFX_FloatRect rect(clipRect->left, clipRect->bottom, clipRect->right, clipRect->top); 87 rect.Normalize(); 88 CFX_ByteString bsClipping; 89 bsClipping.Format("%f %f %f %f re W* n ", rect.left, rect.bottom, rect.Width(), rect.Height()); 90 textBuf<<bsClipping; 91 92 CFX_ByteString bsMatix; 93 bsMatix.Format("%f %f %f %f %f %f cm ", matrix->a, matrix->b,matrix->c,matrix->d,matrix->e,matrix->f); 94 textBuf<<bsMatix; 95 96 97 CPDF_Page* pPage = (CPDF_Page*)page; 98 CPDF_Dictionary* pPageDic = pPage->m_pFormDict; 99 CPDF_Object* pContentObj = pPageDic->GetElement("Contents"); 100 if(!pContentObj) 101 pContentObj = pPageDic->GetArray("Contents"); 102 if(!pContentObj) 103 return FALSE; 104 105 CPDF_Dictionary* pDic = FX_NEW CPDF_Dictionary; 106 CPDF_Stream* pStream = FX_NEW CPDF_Stream(NULL,0, pDic); 107 pStream->SetData(textBuf.GetBuffer(), textBuf.GetSize(), FALSE, FALSE); 108 CPDF_Document* pDoc = pPage->m_pDocument; 109 if(!pDoc) 110 return FALSE; 111 pDoc->AddIndirectObject(pStream); 112 113 pDic = FX_NEW CPDF_Dictionary; 114 CPDF_Stream* pEndStream = FX_NEW CPDF_Stream(NULL,0, pDic); 115 pEndStream->SetData((FX_LPCBYTE)" Q", 2, FALSE, FALSE); 116 pDoc->AddIndirectObject(pEndStream); 117 118 CPDF_Array* pContentArray = NULL; 119 if (pContentObj && pContentObj->GetType() == PDFOBJ_ARRAY) 120 { 121 pContentArray = (CPDF_Array*)pContentObj; 122 CPDF_Reference* pRef = FX_NEW CPDF_Reference(pDoc, pStream->GetObjNum()); 123 pContentArray->InsertAt(0, pRef); 124 pContentArray->AddReference(pDoc,pEndStream); 125 126 } 127 else if(pContentObj && pContentObj->GetType() == PDFOBJ_REFERENCE) 128 { 129 CPDF_Reference* pReference = (CPDF_Reference*)pContentObj; 130 CPDF_Object* pDirectObj = pReference->GetDirect(); 131 if(pDirectObj != NULL) 132 { 133 if(pDirectObj->GetType() == PDFOBJ_ARRAY) 134 { 135 pContentArray = (CPDF_Array*)pDirectObj; 136 CPDF_Reference* pRef = FX_NEW CPDF_Reference(pDoc, pStream->GetObjNum()); 137 pContentArray->InsertAt(0, pRef); 138 pContentArray->AddReference(pDoc,pEndStream); 139 140 } 141 else if(pDirectObj->GetType() == PDFOBJ_STREAM) 142 { 143 pContentArray = FX_NEW CPDF_Array(); 144 pContentArray->AddReference(pDoc,pStream->GetObjNum()); 145 pContentArray->AddReference(pDoc,pDirectObj->GetObjNum()); 146 pContentArray->AddReference(pDoc, pEndStream); 147 pPageDic->SetAtReference("Contents", pDoc, pDoc->AddIndirectObject(pContentArray)); 148 } 149 } 150 } 151 152 //Need to transform the patterns as well. 153 CPDF_Dictionary* pRes = pPageDic->GetDict(FX_BSTRC("Resources")); 154 if(pRes) 155 { 156 CPDF_Dictionary* pPattenDict = pRes->GetDict(FX_BSTRC("Pattern")); 157 if(pPattenDict) 158 { 159 FX_POSITION pos = pPattenDict->GetStartPos(); 160 while(pos) 161 { 162 CPDF_Dictionary* pDict = NULL; 163 CFX_ByteString key; 164 CPDF_Object* pObj = pPattenDict->GetNextElement(pos, key); 165 if(pObj->GetType() == PDFOBJ_REFERENCE) 166 pObj = pObj->GetDirect(); 167 if(pObj->GetType() == PDFOBJ_DICTIONARY) 168 { 169 pDict = (CPDF_Dictionary*)pObj; 170 } 171 else if(pObj->GetType() == PDFOBJ_STREAM) 172 { 173 pDict = ((CPDF_Stream*)pObj)->GetDict(); 174 } 175 else 176 continue; 177 178 CFX_AffineMatrix m = pDict->GetMatrix(FX_BSTRC("Matrix")); 179 CFX_AffineMatrix t = *(CFX_AffineMatrix*)matrix; 180 m.Concat(t); 181 pDict->SetAtMatrix(FX_BSTRC("Matrix"), m); 182 } 183 } 184 } 185 186 return TRUE; 187 } 188 189 DLLEXPORT void STDCALL FPDFPageObj_TransformClipPath(FPDF_PAGEOBJECT page_object,double a, double b, double c, double d, double e, double f) 190 { 191 CPDF_PageObject* pPageObj = (CPDF_PageObject*)page_object; 192 if(pPageObj == NULL) 193 return; 194 CFX_AffineMatrix matrix((FX_FLOAT)a,(FX_FLOAT)b,(FX_FLOAT)c,(FX_FLOAT)d,(FX_FLOAT)e,(FX_FLOAT)f); 195 196 //Special treatment to shading object, because the ClipPath for shading object is already transformed. 197 if(pPageObj->m_Type != PDFPAGE_SHADING) 198 pPageObj->TransformClipPath(matrix); 199 pPageObj->TransformGeneralState(matrix); 200 } 201 202 203 DLLEXPORT FPDF_CLIPPATH STDCALL FPDF_CreateClipPath(float left, float bottom, float right, float top) 204 { 205 CPDF_ClipPath* pNewClipPath = FX_NEW CPDF_ClipPath(); 206 pNewClipPath->GetModify(); 207 CPDF_Path Path; 208 Path.GetModify(); 209 Path.AppendRect(left, bottom, right, top); 210 pNewClipPath->AppendPath(Path, FXFILL_ALTERNATE, FALSE); 211 return pNewClipPath; 212 } 213 214 DLLEXPORT void STDCALL FPDF_DestroyClipPath(FPDF_CLIPPATH clipPath) 215 { 216 if(clipPath) 217 delete (CPDF_ClipPath*)clipPath; 218 } 219 220 void OutputPath(CFX_ByteTextBuf& buf, CPDF_Path path) 221 { 222 const CFX_PathData* pPathData = path; 223 if (pPathData == NULL) return; 224 225 FX_PATHPOINT* pPoints = pPathData->GetPoints(); 226 227 if (path.IsRect()) { 228 buf << (pPoints[0].m_PointX) << " " << (pPoints[0].m_PointY) << " " 229 << (pPoints[2].m_PointX - pPoints[0].m_PointX) << " " 230 << (pPoints[2].m_PointY - pPoints[0].m_PointY) << " re\n"; 231 return; 232 } 233 234 CFX_ByteString temp; 235 for (int i = 0; i < pPathData->GetPointCount(); i ++) { 236 buf << (pPoints[i].m_PointX) << " " << (pPoints[i].m_PointY); 237 int point_type = pPoints[i].m_Flag & FXPT_TYPE; 238 if (point_type == FXPT_MOVETO) 239 buf << " m\n"; 240 else if (point_type == FXPT_BEZIERTO) { 241 buf << " " << (pPoints[i+1].m_PointX) << " " << (pPoints[i+1].m_PointY) << " " << 242 (pPoints[i+2].m_PointX) << " " << (pPoints[i+2].m_PointY); 243 if (pPoints[i+2].m_Flag & FXPT_CLOSEFIGURE) 244 buf << " c h\n"; 245 else 246 buf << " c\n"; 247 i += 2; 248 } else if (point_type == FXPT_LINETO) { 249 if (pPoints[i].m_Flag & FXPT_CLOSEFIGURE) 250 buf << " l h\n"; 251 else 252 buf << " l\n"; 253 } 254 } 255 } 256 257 DLLEXPORT void STDCALL FPDFPage_InsertClipPath(FPDF_PAGE page,FPDF_CLIPPATH clipPath) 258 { 259 if(!page) 260 return; 261 CPDF_Page* pPage = (CPDF_Page*)page; 262 CPDF_Dictionary* pPageDic = pPage->m_pFormDict; 263 CPDF_Object* pContentObj = pPageDic->GetElement("Contents"); 264 if(!pContentObj) 265 pContentObj = pPageDic->GetArray("Contents"); 266 if(!pContentObj) 267 return; 268 269 CFX_ByteTextBuf strClip; 270 CPDF_ClipPath* pClipPath = (CPDF_ClipPath*)clipPath; 271 FX_DWORD i; 272 for (i = 0; i < pClipPath->GetPathCount(); i ++) { 273 CPDF_Path path = pClipPath->GetPath(i); 274 int iClipType = pClipPath->GetClipType(i); 275 if (path.GetPointCount() == 0) { 276 // Empty clipping (totally clipped out) 277 strClip << "0 0 m W n "; 278 } else { 279 OutputPath(strClip, path); 280 if (iClipType == FXFILL_WINDING) 281 strClip << "W n\n"; 282 else 283 strClip << "W* n\n"; 284 } 285 } 286 CPDF_Dictionary* pDic = FX_NEW CPDF_Dictionary; 287 CPDF_Stream* pStream = FX_NEW CPDF_Stream(NULL,0, pDic); 288 pStream->SetData(strClip.GetBuffer(), strClip.GetSize(), FALSE, FALSE); 289 CPDF_Document* pDoc = pPage->m_pDocument; 290 if(!pDoc) 291 return; 292 pDoc->AddIndirectObject(pStream); 293 294 CPDF_Array* pContentArray = NULL; 295 if (pContentObj && pContentObj->GetType() == PDFOBJ_ARRAY) 296 { 297 pContentArray = (CPDF_Array*)pContentObj; 298 CPDF_Reference* pRef = FX_NEW CPDF_Reference(pDoc, pStream->GetObjNum()); 299 pContentArray->InsertAt(0, pRef); 300 301 } 302 else if(pContentObj && pContentObj->GetType() == PDFOBJ_REFERENCE) 303 { 304 CPDF_Reference* pReference = (CPDF_Reference*)pContentObj; 305 CPDF_Object* pDirectObj = pReference->GetDirect(); 306 if(pDirectObj != NULL) 307 { 308 if(pDirectObj->GetType() == PDFOBJ_ARRAY) 309 { 310 pContentArray = (CPDF_Array*)pDirectObj; 311 CPDF_Reference* pRef = FX_NEW CPDF_Reference(pDoc, pStream->GetObjNum()); 312 pContentArray->InsertAt(0, pRef); 313 314 } 315 else if(pDirectObj->GetType() == PDFOBJ_STREAM) 316 { 317 pContentArray = FX_NEW CPDF_Array(); 318 pContentArray->AddReference(pDoc,pStream->GetObjNum()); 319 pContentArray->AddReference(pDoc,pDirectObj->GetObjNum()); 320 pPageDic->SetAtReference("Contents", pDoc, pDoc->AddIndirectObject(pContentArray)); 321 } 322 } 323 } 324 } 325 326