No vídeo de hoje, vamos demonstrar em como exibir uma imagem como marca d’água em um relatório com FWMSPrinter.
A dúvida de hoje, nos perguntaram, se seria possível exibir uma imagem como se fosse uma marca d’água num relatório usando a classe FWMSPrinter.
Pensando nisso, montamos um exemplo, onde vamos mostrar em como gerar um png já com transparência e depois exibir no relatório com SayBitmap.
Segue abaixo o vídeo exemplificando:
E abaixo o código fonte desenvolvido:
//Bibliotecas
#Include "tlpp-core.th"
#Include "Totvs.ch"
#Include "TopConn.ch"
#Include "RPTDef.ch"
#Include "FWPrintSetup.ch"
//Declaração da namespace
Namespace custom.terminal.youtube
//Contantes
#Define CRLF Chr(13) + Chr(10) //Carriage Return Line Feed
//Alinhamentos
#Define PAD_LEFT 0
#Define PAD_RIGHT 1
#Define PAD_CENTER 2
#Define PAD_JUSTIFY 3 //Opção disponível somente a partir da versão 1.6.2 da TOTVS Printer
//Cor(es)
Static nCorCinza := RGB(110, 110, 110)
Static nCorLinha := RGB(207, 255, 204)
/*/{Protheus.doc} User Function video0211
Exemplo de quebra com totalizador
@author Atilio
@since 15/01/2024
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
@example custom.terminal.youtube.u_video0211()
/*/
User Function video0211()
Local aArea := FWGetArea() As Array
Local aParameters := {} As Array
Local cInitState := Space(2) As Character
Local cLastState := StrTran(cInitState, ' ', 'Z') As Character
//Adicionando os parametros do ParamBox
aAdd(aParameters, {1, "Estado De", cInitState, "", ".T.", "12", ".T.", 80, .F.})
aAdd(aParameters, {1, "Estado Até", cLastState, "", ".T.", "12", ".T.", 80, .T.})
//Se a pergunta for confirma, cria o relatorio
If ParamBox(aParameters, 'Informe os parâmetros', /*aRet*/, /*bOk*/, /*aButtons*/, /*lCentered*/, /*nPosx*/, /*nPosy*/, /*oDlgWizard*/, /*cLoad*/, .F., .F.)
Processa({|| processingReport()})
EndIf
FWRestArea(aArea)
Return
/*/{Protheus.doc} processingReport
Faz a impressão do relatório video0211
@author Atilio
@since 15/01/2024
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/
Static Function processingReport()
Local aArea := FWGetArea() As Array
Local nTotal := 0 As Numeric
Local nCurrent := 0 As Numeric
Local cQuery := '' As Character
Local cFile := 'video0211'+RetCodUsr()+'_' + dToS(Date()) + '_' + StrTran(Time(), ':', '-') + '.pdf' As Character
Private oPrint As Object
Private oBrush := TBrush():New(, nCorLinha) As Object
Private cTime := Time() As Character
Private nPage := 1 As Numeric
Private cCompanyLogo := companyLogo() As Character
//Linhas e colunas
Private nCurrentLine := 0 As Numeric
Private nBottomLimit := 800 As Numeric
Private nLeftColumn := 010 As Numeric
Private nRightLimit := 580 As Numeric
Private nMiddleColumn := (nRightLimit-nLeftColumn)/2 As Numeric
//Colunas dos relatorio
Private nCityColumn := nLeftColumn As Numeric
Private nNameColumn := nLeftColumn + 80 As Numeric
//Declarando as fontes
Private cFont := 'Arial' As Character
Private oFontDetail := TFont():New(cFont, /*uPar2*/, -11, /*uPar4*/, .F., /*uPar6*/, /*uPar7*/, /*uPar8*/, /*uPar9*/, .F.) As Object
Private oFontDetailBold := TFont():New(cFont, /*uPar2*/, -13, /*uPar4*/, .T., /*uPar6*/, /*uPar7*/, /*uPar8*/, /*uPar9*/, .F.) As Object
Private oFontFooter := TFont():New(cFont, /*uPar2*/, -8, /*uPar4*/, .F., /*uPar6*/, /*uPar7*/, /*uPar8*/, /*uPar9*/, .F.) As Object
Private oFontHeaderColumns := TFont():New(cFont, /*uPar2*/, -7, /*uPar4*/, .F., /*uPar6*/, /*uPar7*/, /*uPar8*/, /*uPar9*/, .F.) As Object
Private oFontTitle := TFont():New(cFont, /*uPar2*/, -15, /*uPar4*/, .T., /*uPar6*/, /*uPar7*/, /*uPar8*/, /*uPar9*/, .F.) As Object
//Variáveis responsáveis pela quebra e total
Private cBreakKey := "" As Character
Private nTotalValue := 0 As Numeric
//Monta a consulta de dados
cQuery += "SELECT " + CRLF
cQuery += " CC2_EST, " + CRLF
cQuery += " X5_DESCRI, " + CRLF
cQuery += " CC2_CODMUN, " + CRLF
cQuery += " CC2_MUN " + CRLF
cQuery += "FROM " + CRLF
cQuery += " " + RetSQLName("CC2") + " CC2 " + CRLF
cQuery += " INNER JOIN " + RetSQLName("SX5") + " SX5 ON ( " + CRLF
cQuery += " X5_FILIAL = '" + FWxFilial("SX5") + "' " + CRLF
cQuery += " AND X5_TABELA = '12' " + CRLF
cQuery += " AND X5_CHAVE = CC2_EST " + CRLF
cQuery += " AND SX5.D_E_L_E_T_ = ' ' " + CRLF
cQuery += " ) " + CRLF
cQuery += "WHERE " + CRLF
cQuery += " CC2_FILIAL = '" + FWxFilial("CC2") + "' " + CRLF
cQuery += " AND CC2_EST >= '" + MV_PAR01 + "' " + CRLF
cQuery += " AND CC2_EST <= '" + MV_PAR02 + "' " + CRLF
cQuery += " AND CC2.D_E_L_E_T_ = ' ' " + CRLF
cQuery += "ORDER BY " + CRLF
cQuery += " CC2_EST, " + CRLF
cQuery += " CC2_CODMUN" + CRLF
PLSQuery(cQuery, 'QRY_AUX')
//Define o tamanho da régua
DbSelectArea('QRY_AUX')
QRY_AUX->(DbGoTop())
Count to nTotal
ProcRegua(nTotal)
QRY_AUX->(DbGoTop())
//Somente se tiver dados
If ! QRY_AUX->(EoF())
//Criando o objeto de impressao
oPrint := FWMSPrinter():New(;
cFile,; // cFilePrinter
IMP_PDF,; // nDevice
.F.,; // lAdjustToLegacy
,; // cPathInServer
.T.,; // lDisabeSetup
,; // lTReport
@oPrint,; // oPrintSetup
,; // cPrinter
,; // lServer
,; // lParam10
,; // lRaw
.T.; // lViewPDF
)
oPrint:cPathPDF := GetTempPath()
oPrint:SetResolution(72)
oPrint:SetPortrait()
oPrint:SetPaperSize(DMPAPER_A4)
oPrint:SetMargin(0, 0, 0, 0)
//Imprime os dados
printHeader()
While ! QRY_AUX->(EoF())
nCurrent++
IncProc('Imprimindo registro ' + cValToChar(nCurrent) + ' de ' + cValToChar(nTotal) + '...')
//Se atingiu o limite, quebra de pagina
validBreak()
//Aciona a função que valida o totalizador e imprime
printTotal()
//Faz o zebrado ao fundo
If nCurrent % 2 == 0
oPrint:FillRect({nCurrentLine - 2, nLeftColumn, nCurrentLine + 12, nRightLimit}, oBrush)
EndIf
//Imprime a linha atual
oPrint:SayAlign(nCurrentLine, nCityColumn, Alltrim(QRY_AUX->CC2_CODMUN), oFontDetail, 80, 10, /*nClrText*/, PAD_LEFT, /*nAlignVert*/)
oPrint:SayAlign(nCurrentLine, nNameColumn, Alltrim(QRY_AUX->CC2_MUN), oFontDetail, 200, 10, /*nClrText*/, PAD_LEFT, /*nAlignVert*/)
nCurrentLine += 15
oPrint:Line(nCurrentLine-3, nLeftColumn, nCurrentLine-3, nRightLimit, nCorCinza)
//Se atingiu o limite, quebra de pagina
validBreak()
//Incrementa o totalizador, contando uma cidade a mais
nTotalValue++
QRY_AUX->(DbSkip())
EndDo
//Aciona a função que valida o totalizador e imprime uma última vez antes de imprimir o último rodapé
printTotal()
printFooter()
oPrint:Preview()
Else
FWAlertError('Não foi encontrado informações com os parâmetros informados!', 'Atenção')
EndIf
QRY_AUX->(DbCloseArea())
FWRestArea(aArea)
Return
/*/{Protheus.doc} companyLogo
Função que retorna o logo da empresa conforme configuração da DANFE
@author Atilio
@since 15/01/2024
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/
Static Function companyLogo()
Local cLogo := '\x_imagens\logo.png' As Character
Return cLogo
/*/{Protheus.doc} printHeader
Função que imprime o cabeçalho do relatório
@author Atilio
@since 15/01/2024
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/
Static Function printHeader()
Local cText := '' As Character
Local nHeaderLine := 015 As Numeric
//Iniciando Pagina
oPrint:StartPage()
//Imprime o logo
If File(cCompanyLogo)
oPrint:SayBitmap(005, nLeftColumn, cCompanyLogo, 030, 030)
EndIf
//Cabecalho
cText := 'Listagem de Cidades'
oPrint:SayAlign(nHeaderLine, nMiddleColumn-200, cText, oFontTitle, 400, 20, /*nClrText*/, PAD_CENTER, /*nAlignVert*/)
//Linha Separatoria
nHeaderLine += 020
oPrint:Line(nHeaderLine, nLeftColumn, nHeaderLine, nRightLimit)
//Atualizando a linha inicial do relatorio
nCurrentLine := nHeaderLine + 5
If nPage == 1
//Imprimindo os parâmetros
cText := MV_PAR01
oPrint:SayAlign(nCurrentLine, nLeftColumn, 'Estado De', oFontDetailBold, 200, 10, /*nClrText*/, PAD_LEFT, /*nAlignVert*/)
oPrint:SayAlign(nCurrentLine, nLeftColumn+200, cText, oFontDetail, 200, 10, /*nClrText*/, PAD_LEFT, /*nAlignVert*/)
nCurrentLine += 15
cText := MV_PAR02
oPrint:SayAlign(nCurrentLine, nLeftColumn, 'Estado Até', oFontDetailBold, 200, 10, /*nClrText*/, PAD_LEFT, /*nAlignVert*/)
oPrint:SayAlign(nCurrentLine, nLeftColumn+200, cText, oFontDetail, 200, 10, /*nClrText*/, PAD_LEFT, /*nAlignVert*/)
nCurrentLine += 15
oPrint:Line(nCurrentLine-3, nLeftColumn, nCurrentLine-3, nRightLimit, nCorCinza)
nCurrentLine += 5
EndIf
oPrint:SayAlign(nCurrentLine, nCityColumn, 'Código', oFontHeaderColumns, 80, 10, /*nClrText*/, PAD_LEFT, /*nAlignVert*/)
oPrint:SayAlign(nCurrentLine, nNameColumn, 'Nome', oFontHeaderColumns, 200, 10, /*nClrText*/, PAD_LEFT, /*nAlignVert*/)
nCurrentLine += 15
Return
/*/{Protheus.doc} printFooter
Função que imprime o rodapé e encerra a página
@author Atilio
@since 15/01/2024
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/
Static Function printFooter()
Local nFooterLine := nBottomLimit As Numeric
Local cText := '' As Character
Local cWaterMark := "\x_imagens\marca.png" As Character
//Imprime a imagem da marca d'agua
oPrint:SayBitmap(005, 005, cWaterMark, nRightLimit, nBottomLimit)
//Linha Separatoria
oPrint:Line(nFooterLine, nLeftColumn, nFooterLine, nRightLimit)
nFooterLine += 3
//Dados da Esquerda
cText := dToC(dDataBase) + ' ' + cTime + ' ' + FunName() + ' (video0211) ' + UsrRetName(RetCodUsr())
oPrint:SayAlign(nFooterLine, nLeftColumn, cText, oFontFooter, 500, 10, /*nClrText*/, PAD_LEFT, /*nAlignVert*/)
//Direita
cText := 'Pagina '+cValToChar(nPage)
oPrint:SayAlign(nFooterLine, nRightLimit-40, cText, oFontFooter, 040, 10, /*nClrText*/, PAD_RIGHT, /*nAlignVert*/)
//Finalizando a pagina e somando mais um
oPrint:EndPage()
nPage++
Return
/*/{Protheus.doc} validBreak
Função que valida se a linha esta próxima do final, se sim quebra a página
@author Atilio
@since 15/01/2024
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/
Static Function validBreak()
If nCurrentLine >= nBottomLimit-10
printFooter()
printHeader()
EndIf
Return
/*/{Protheus.doc} printTotal
Função que valida a quebra e imprime as informações do total
@author Atilio
@since 15/01/2024
@version 1.0
@type function
/*/
Static Function printTotal()
Local nColor := RGB(255, 000, 000) As Numeric
Local cText := "" As Character
//Se estiver no fim do alias (já tiver acabado o while) ou a chave for diferente
If QRY_AUX->(EoF()) .Or. cBreakKey != QRY_AUX->CC2_EST
//Se tiver chave, irá imprimir o valor total (quantidade de cidades)
If ! Empty(cBreakKey)
cText := "Quantidade total de cidades: " + Alltrim(Transform(nTotalValue, "@E 999,999"))
oPrint:SayAlign(nCurrentLine, nLeftColumn, cText, oFontDetail, 200, 10, nColor, PAD_LEFT, /*nAlignVert*/)
nCurrentLine += 15
EndIf
//Se houver dados ainda na query, atualiza a chave, zera o total, e imprime a sigla e nome do estado
If ! QRY_AUX->(EoF())
cBreakKey := QRY_AUX->CC2_EST
nTotalValue := 0
cText := cBreakKey + " - " + Alltrim(QRY_AUX->X5_DESCRI)
oPrint:SayAlign(nCurrentLine, nLeftColumn, cText, oFontDetail, 200, 10, nColor, PAD_LEFT, /*nAlignVert*/)
nCurrentLine += 15
EndIf
EndIf
Return
Bom pessoal, por hoje é só.
Abraços e até a próxima.